Record
persista.record ¶
Define the Record container and helpers to filter and sort
collections of records by their metadata.
persista.record.Record
dataclass
¶
A generic immutable record with a stable UUID identifier and arbitrary metadata.
Use :meth:from_metadata as the preferred constructor to
automatically derive a stable UUID from the metadata dict.
Note
metadata is copied into a read-only
:class:~types.MappingProxyType view during construction, so
record.metadata["x"] = 1 raises TypeError instead of
silently mutating the record - the dict passed in to
metadata is not itself frozen, so mutating it directly
after construction still does not affect the record.
Instances remain unhashable, since a MappingProxyType is
itself unhashable and eq=True (the dataclass default)
disables the auto-generated __hash__. Use record.id
as the hashable identifier instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
id
|
str
|
Unique identifier for the record, typically a UUID derived
from the metadata via
:func: |
required |
metadata
|
dict[str, Any]
|
Arbitrary key-value metadata associated with the record. Defaults to an empty dict. Copied into a read-only view; the original dict is left untouched. |
dict()
|
persista.record.Record.from_metadata
classmethod
¶
from_metadata(metadata: dict[str, Any]) -> Record
Construct a :class:Record from a metadata dict.
Computes a stable UUID from metadata via
:func:~coola.identifier.generate_stable_uuid5 and uses it as
the record's id. Two calls with the same metadata
contents (regardless of key insertion order) will produce the
same id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
metadata
|
dict[str, Any]
|
Arbitrary key-value metadata to associate with
the record. Used to derive the |
required |
Returns:
| Type | Description |
|---|---|
Record
|
A new :class: |
Record
|
|
Example
>>> from persista.record import Record
>>> record = Record.from_metadata({"source": "cats.txt", "page": 1})
>>> record.id # doctest: +ELLIPSIS
'...'
>>> dict(record.metadata)
{'source': 'cats.txt', 'page': 1}
persista.record.filter_by_metadata ¶
Filter a list of records by the value of a metadata key.
Returns a new list containing only records whose metadata contains
metadata_key with a value equal to value. Records missing
metadata_key are excluded, even when value=None: a record
missing metadata_key never matches, regardless of value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
list[Record]
|
The list of :class: |
required |
metadata_key
|
str
|
The metadata key to filter by. |
required |
value
|
Any
|
The value to match against. Records whose
|
required |
Returns:
| Type | Description |
|---|---|
list[Record]
|
A new list of :class: |
list[Record]
|
matches the filter. The original list is not modified. |
Example
>>> from persista.record import Record, filter_by_metadata
>>> records = [
... Record(id="a", metadata={"category": "Science"}),
... Record(id="b", metadata={"category": "Cooking"}),
... Record(id="c", metadata={"category": "Science"}),
... ]
>>> result = filter_by_metadata(records, "category", "Science")
>>> [r.id for r in result]
['a', 'c']
persista.record.filter_by_metadata_range ¶
filter_by_metadata_range(
records: list[Record],
metadata_key: str,
lower: Any = None,
upper: Any = None,
) -> list[Record]
Filter a list of records by a range of values for a metadata key.
Returns a new list containing only records whose metadata contains
metadata_key with a value within the specified range
[lower, upper] (inclusive on both ends). Either bound can be
set to None to indicate no constraint on that side. If both
bounds are None, all records that contain metadata_key are
returned. Records missing metadata_key are always excluded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
list[Record]
|
The list of :class: |
required |
metadata_key
|
str
|
The metadata key to filter by. |
required |
lower
|
Any
|
The inclusive lower bound. Pass |
None
|
upper
|
Any
|
The inclusive upper bound. Pass |
None
|
Returns:
| Type | Description |
|---|---|
list[Record]
|
A new list of :class: |
list[Record]
|
|
list[Record]
|
original list is not modified. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the metadata values are not comparable with the
provided bounds (e.g. comparing |
Example
>>> from persista.record import Record, filter_by_metadata_range
>>> records = [
... Record(id="a", metadata={"page": 1}),
... Record(id="b", metadata={"page": 5}),
... Record(id="c", metadata={"page": 10}),
... ]
>>> result = filter_by_metadata_range(records, "page", lower=2, upper=8)
>>> [r.id for r in result]
['b']
>>> result = filter_by_metadata_range(records, "page", lower=5)
>>> [r.id for r in result]
['b', 'c']
>>> result = filter_by_metadata_range(records, "page", upper=5)
>>> [r.id for r in result]
['a', 'b']
persista.record.filter_by_metadata_values ¶
filter_by_metadata_values(
records: list[Record],
metadata_key: str,
values: set[Any],
) -> list[Record]
Filter a list of records by checking if a metadata value is in a set.
Returns a new list containing only records whose metadata contains
metadata_key with a value that is a member of values.
Records missing metadata_key are excluded, even when None
is included in values: a record missing metadata_key never
matches.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
list[Record]
|
The list of :class: |
required |
metadata_key
|
str
|
The metadata key to filter by. |
required |
values
|
set[Any]
|
The set of accepted values. Records whose
|
required |
Returns:
| Type | Description |
|---|---|
list[Record]
|
A new list of :class: |
list[Record]
|
|
list[Record]
|
not modified. |
Example
>>> from persista.record import Record, filter_by_metadata_values
>>> records = [
... Record(id="a", metadata={"category": "Science"}),
... Record(id="b", metadata={"category": "Cooking"}),
... Record(id="c", metadata={"category": "Technology"}),
... Record(id="d", metadata={"category": "Science"}),
... ]
>>> result = filter_by_metadata_values(records, "category", {"Science", "Technology"})
>>> sorted(r.id for r in result)
['a', 'c', 'd']
persista.record.sort_by_metadata ¶
sort_by_metadata(
records: list[Record],
metadata_key: str,
*,
keep_missing: bool = True,
reverse: bool = False,
) -> list[Record]
Sort a list of records by the value of a metadata key.
Records are sorted in ascending order by the value of
metadata_key by default, or descending order if
reverse=True. Records that do not contain metadata_key
in their metadata are placed at the end of the result by default,
or removed entirely if keep_missing=False.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
list[Record]
|
The list of :class: |
required |
metadata_key
|
str
|
The metadata key to sort by. |
required |
keep_missing
|
bool
|
If |
True
|
reverse
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
list[Record]
|
A new sorted list of :class: |
list[Record]
|
original list is not modified. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the metadata values for |
Example
>>> from persista.record import Record, sort_by_metadata
>>> records = [
... Record(id="b", metadata={"source": "b.txt"}),
... Record(id="a", metadata={"source": "a.txt"}),
... Record(id="c"),
... ]
>>> sorted_records = sort_by_metadata(records, "source")
>>> [r.metadata.get("source") for r in sorted_records]
['a.txt', 'b.txt', None]
>>> sorted_records = sort_by_metadata(records, "source", reverse=True)
>>> [r.metadata.get("source") for r in sorted_records]
['b.txt', 'a.txt', None]
>>> sorted_records = sort_by_metadata(records, "source", keep_missing=False)
>>> [r.metadata.get("source") for r in sorted_records]
['a.txt', 'b.txt']
persista.record.analysis ¶
Contain code to analyze records.
persista.record.analysis.MetadataStats
dataclass
¶
Streaming record metadata health/stats.
Accumulates statistics one record at a time via update, so it
can be fed from a list, a generator, or any other iterable without
requiring the full corpus to be held in memory at once. Call
to_dict at the end to compute the final report.
Note
Once a key's sample of unique values has reached
n_sample_values, no further values for that key are added
to the sample - the sample simply reflects the first
n_sample_values distinct values encountered for that key,
in record order. This makes the sample deterministic
(independent of set iteration order) at the cost of not
necessarily being a uniform sample over the whole corpus.
Memory
- O(number of distinct metadata keys) for the per-key counters.
- O(number of distinct keys x n_sample_values) for the sampled
unique values, bounded by
n_sample_valuesper key regardless of corpus size. Ifn_sample_valuesisNone, this becomes O(number of distinct keys x number of distinct values per key) instead, which can grow unbounded for high-cardinality keys (e.g. UUIDs).
With a numeric n_sample_values, this is effectively O(1) with
respect to the number of records, so it scales to corpora too
large to fit in memory.
Attributes:
| Name | Type | Description |
|---|---|---|
n_sample_values |
int | None
|
Max number of unique sample values retained
per metadata key, or |
count |
int
|
Total number of records processed. |
missing_metadata_count |
int
|
Number of records whose |
total_keys |
int
|
Sum of the number of metadata keys across all records processed. |
min_keys |
int | None
|
Number of metadata keys on the record with the
fewest keys seen so far, or |
max_keys |
int | None
|
Number of metadata keys on the record with the
most keys seen so far, or |
persista.record.analysis.MetadataStats.to_dict ¶
to_dict() -> dict[str, Any]
Compute the final statistics report from the accumulated state.
Safe to call multiple times and at any point during
accumulation; it does not mutate any state and always reflects
everything processed via update so far.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
A dict with the following keys: |
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
Percentages are intentionally omitted - compute them later |
dict[str, Any]
|
from the raw counts (e.g. |
dict[str, Any]
|
since they are trivially derived from this report. |
persista.record.analysis.MetadataStats.update ¶
update(record: Record) -> None
Fold a single record's metadata into the running statistics.
Updates the record-level counters (count, missing metadata, keys-per-record min/max/total) as well as the per-key counters, value-type sets, none/empty counts, and unique-value samples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
Record
|
The record to process. Its |
required |
persista.record.analysis.compute_metadata_stats ¶
compute_metadata_stats(
records: Iterable[Record],
n_sample_values: int | None = 3,
) -> dict[str, Any]
Compute metadata health/statistics over a stream of records.
Streaming health/stat check over a list, generator, or any iterable
of Records. Records are consumed one at a time, so this works
with iterators or generators whose full contents cannot fit in
memory — only per-key aggregates are retained (see
RecordMetadataStats for the memory profile).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
n_sample_values
|
int | None
|
Max number of unique sample values to retain
per metadata key. Defaults to 3. Pass |
3
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
A dict of statistics as described in |
dict[str, Any]
|
|
dict[str, Any]
|
report with |
dict[str, Any]
|
for the remaining fields. |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import compute_metadata_stats
>>> records = [
... Record(id="a", metadata={"source": "a.pdf"}),
... Record(id="b", metadata={"source": "b.pdf", "page": 1}),
... ]
>>> stats = compute_metadata_stats(records)
>>> stats["count"]
2
persista.record.analysis.compute_schema_shapes ¶
compute_schema_shapes(
records: Iterable[Record],
) -> dict[tuple[str, ...], list[Any]]
Group record ids by the shape of their metadata, i.e. the set of keys present, ignoring the keys' values.
This complements compute_metadata_stats, which reports
per-key statistics across the whole corpus but does not show which
combinations of keys co-occur. A corpus with schema drift (e.g.
some records carrying an extra field added later, or missing one
dropped later) shows up here as multiple distinct shapes.
Records are consumed one at a time, so this works with generators or other iterables whose full contents cannot fit in memory. Memory usage is O(number of distinct shapes), which is typically small even for large corpora since most pipelines only produce a handful of distinct metadata schemas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
Returns:
| Type | Description |
|---|---|
dict[tuple[str, ...], list[Any]]
|
A dict mapping each distinct shape (a tuple of metadata keys, |
dict[tuple[str, ...], list[Any]]
|
sorted alphabetically) to the list of record |
dict[tuple[str, ...], list[Any]]
|
that shape, in the order their records were encountered. Keys |
dict[tuple[str, ...], list[Any]]
|
are in the order their shape was first encountered. A record |
dict[tuple[str, ...], list[Any]]
|
with no metadata has the shape |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import compute_schema_shapes
>>> records = [
... Record(id="a", metadata={"source": "a.pdf", "page": 1}),
... Record(id="b", metadata={"source": "b.pdf", "page": 2}),
... Record(id="c", metadata={"source": "c.pdf"}),
... ]
>>> compute_schema_shapes(records)
{('page', 'source'): ['a', 'b'], ('source',): ['c']}
persista.record.analysis.compute_value_frequency ¶
compute_value_frequency(
records: Iterable[Record],
*,
top_k: int = 5,
hll_precision: int = 12,
) -> dict[str, dict[str, Any]]
Compute, for each metadata key, its most common values and an approximate cardinality (number of distinct values).
This complements compute_metadata_stats, whose
unique_values_sample is a small, arbitrary (first-seen) sample
rather than a ranked top-K, and does not report cardinality.
Frequency counts help spot near-constant keys (a single value
dominates) or skewed distributions; cardinality helps spot keys
unsuitable for grouping/joins because of excessive uniqueness
(e.g. UUIDs, timestamps).
Records are consumed one at a time, so this works with generators or other iterables whose full contents cannot fit in memory. Memory usage is O(number of distinct keys x number of distinct values per key) for the frequency counters (unbounded for high-cardinality keys), plus a fixed O(2 ** hll_precision) per key for the cardinality estimator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
top_k
|
int
|
Number of most common values to report per key. |
5
|
hll_precision
|
int
|
Precision passed to the internal HyperLogLog cardinality estimator for each key. Higher values give a more accurate estimate at the cost of more memory per key. |
12
|
Returns:
| Type | Description |
|---|---|
dict[str, dict[str, Any]]
|
A dict mapping each metadata key to a dict with: |
dict[str, dict[str, Any]]
|
|
dict[str, dict[str, Any]]
|
|
Example
>>> from persista.record import Record
>>> from persista.record.analysis import compute_value_frequency
>>> records = [
... Record(id="a", metadata={"lang": "en"}),
... Record(id="b", metadata={"lang": "en"}),
... Record(id="c", metadata={"lang": "fr"}),
... ]
>>> result = compute_value_frequency(records)
>>> result["lang"]["top_values"]
[('en', 2), ('fr', 1)]
persista.record.analysis.count_approx_duplicate_records ¶
count_approx_duplicate_records(
records: Iterable[Record],
*,
expected_record_count: int = 1000000,
fp_rate: float = 0.01,
) -> int
Count records whose metadata has probably already been seen
earlier in the stream, using a Bloom filter.
Records are consumed one at a time, so this works with iterators
or generators whose full contents cannot fit in memory. Unlike
find_duplicate_record_ids, memory usage here is fixed up front
from expected_record_count and does not grow with the number of
records processed, at the cost of a tunable false-positive rate: a
record may occasionally be counted as a duplicate when it is not,
but a true duplicate is never missed. The hash fed to the Bloom
filter is computed via :func:coola.hashing.hash_object with
ignore_unhashable=True, so metadata containing values with no
registered hasher is tolerated rather than raising.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
expected_record_count
|
int
|
Rough estimate of the total number of
records (or, more precisely, unique metadata values) that
will be processed. Used to size the Bloom filter for the
requested |
1000000
|
fp_rate
|
float
|
Target false-positive probability, once approximately
|
0.01
|
Returns:
| Type | Description |
|---|---|
int
|
The approximate number of records whose |
int
|
an earlier record's, as reported by the Bloom filter. Never |
int
|
undercounts by much; may slightly overcount due to the |
int
|
filter's false-positive rate. |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import count_approx_duplicate_records
>>> records = [
... Record(id="a", metadata={"source": "a.pdf"}),
... Record(id="b", metadata={"source": "a.pdf"}),
... Record(id="c", metadata={"source": "b.pdf"}),
... ]
>>> count_approx_duplicate_records(records, expected_record_count=1000)
1
See Also
find_duplicate_record_ids: an exact variant using a hash
map to group duplicate ids, with memory usage that grows with
corpus size but produces exact (non-approximate) results.
persista.record.analysis.diff_records ¶
Diff two record snapshots (e.g. before/after a pipeline run) by
id.
Useful for auditing what an ingestion or transformation step changed: which records were newly added, which disappeared, and which kept the same id but had their metadata altered.
Both before and after are consumed one at a time and fully
materialized internally (as id -> metadata maps), so this
works with generators or other iterables, but memory usage is
O(number of records in each snapshot) - unlike the single-pass
analyses elsewhere in this package, a diff inherently needs both
full snapshots available for comparison.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
before
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
after
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
Returns:
| Type | Description |
|---|---|
dict[str, list[Any]]
|
A dict with three keys: |
dict[str, list[Any]]
|
|
dict[str, list[Any]]
|
|
dict[str, list[Any]]
|
|
dict[str, list[Any]]
|
Ids present in both snapshots with identical metadata are |
dict[str, list[Any]]
|
omitted entirely. |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import diff_records
>>> before = [
... Record(id="a", metadata={"source": "a.pdf"}),
... Record(id="b", metadata={"source": "b.pdf"}),
... ]
>>> after = [
... Record(id="a", metadata={"source": "a.pdf", "page": 1}),
... Record(id="c", metadata={"source": "c.pdf"}),
... ]
>>> diff_records(before, after)
{'added': ['c'], 'removed': ['b'], 'changed': ['a']}
persista.record.analysis.find_duplicate_record_ids ¶
find_duplicate_record_ids(
records: Iterable[Record],
) -> list[list[Any]]
Group record ids that share exactly the same metadata.
Records are consumed one at a time, so this works with generators
or other iterables whose full contents cannot fit in memory. Only a
hash of each record's metadata is retained (rather than the full
metadata itself), making this more memory-efficient for large
corpora. The hash is computed via
:func:coola.hashing.hash_object with ignore_unhashable=True,
so metadata containing values with no registered hasher is
tolerated (grouped by a deterministic placeholder) rather than
raising.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
Returns:
| Type | Description |
|---|---|
list[list[Any]]
|
A list of groups of record |
list[list[Any]]
|
identical. Each group contains two or more ids, in the order |
list[list[Any]]
|
their records were encountered; groups are in the order their |
list[list[Any]]
|
first member was encountered. Records with unique metadata are |
list[list[Any]]
|
not included in the result. |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import find_duplicate_record_ids
>>> records = [
... Record(id="a", metadata={"source": "a.pdf"}),
... Record(id="b", metadata={"source": "a.pdf"}),
... Record(id="c", metadata={"source": "b.pdf"}),
... ]
>>> find_duplicate_record_ids(records)
[['a', 'b']]
See Also
count_approx_duplicate_records: an approximate variant
using a Bloom filter, with fixed (O(1)) memory usage, better
suited to corpora too large for the exact hash groups above to
fit in memory.
persista.record.analysis.find_id_collisions ¶
find_id_collisions(
records: Iterable[Record],
) -> dict[Any, list[dict[str, Any]]]
Find record ids that are reused across records with different metadata.
find_duplicate_record_ids groups different ids that share
identical metadata. This is the complementary check: it flags the
same id appearing more than once with different metadata,
which usually indicates an id-generation bug (e.g. a non-unique or
colliding hash) rather than a legitimate duplicate.
An id that appears multiple times with exactly the same metadata each time is not considered a collision - it is treated as the same record encountered more than once.
Records are consumed one at a time, so this works with generators or other iterables whose full contents cannot fit in memory. Memory usage is O(number of distinct ids x number of distinct metadata variants per id).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
Returns:
| Type | Description |
|---|---|
dict[Any, list[dict[str, Any]]]
|
A dict mapping each colliding record |
dict[Any, list[dict[str, Any]]]
|
distinct |
dict[Any, list[dict[str, Any]]]
|
they were first encountered. Ids observed with only one |
dict[Any, list[dict[str, Any]]]
|
distinct metadata value (whether seen once or many times) are |
dict[Any, list[dict[str, Any]]]
|
not included. |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import find_id_collisions
>>> records = [
... Record(id="a", metadata={"source": "x.pdf"}),
... Record(id="a", metadata={"source": "y.pdf"}),
... Record(id="b", metadata={"source": "z.pdf"}),
... Record(id="b", metadata={"source": "z.pdf"}),
... ]
>>> find_id_collisions(records)
{'a': [{'source': 'x.pdf'}, {'source': 'y.pdf'}]}
persista.record.analysis.find_near_duplicate_record_ids ¶
find_near_duplicate_record_ids(
records: Iterable[Record],
*,
num_hashes: int = 32,
num_bands: int = 8,
) -> list[list[Any]]
Group record ids whose metadata is approximately similar, using MinHash signatures and locality-sensitive hashing (LSH) banding.
Unlike find_duplicate_record_ids (which only groups records
with byte-for-byte identical metadata), this catches records whose
metadata overlaps substantially but not completely - e.g. the same
document re-ingested with one extra or corrected field, or
metadata differing only in a timestamp key.
Each record's metadata is treated as a set of "key=value"
tokens. A num_hashes-sized MinHash signature approximates the
Jaccard similarity between two records' token sets; signatures are
then split into num_bands bands, and any two records sharing
an identical band are considered candidate near-duplicates and
merged into the same group (via union-find). More bands (with
fewer rows each) increases recall (catches less similar pairs) at
the cost of more false positives; fewer bands does the opposite.
Records are consumed one at a time, so this works with generators
or other iterables whose full contents cannot fit in memory for
the signature computation itself, though - like
find_duplicate_record_ids - the signatures and grouping
structure are retained for the whole corpus, so memory usage
grows with the number of records (O(number of records x
num_hashes)).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, generator, or other iterable of
|
required |
num_hashes
|
int
|
Number of hash functions in each MinHash
signature. Must be evenly divisible by |
32
|
num_bands
|
int
|
Number of LSH bands the signature is split into.
Must evenly divide |
8
|
Returns:
| Type | Description |
|---|---|
list[list[Any]]
|
A list of groups of record |
list[list[Any]]
|
of each other, in the order their records were encountered. |
list[list[Any]]
|
Each group contains two or more ids. Records with no |
list[list[Any]]
|
near-duplicate are not included. Records with empty metadata |
list[list[Any]]
|
are never grouped with each other or with anything else. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import find_near_duplicate_record_ids
>>> records = [
... Record(id="a", metadata={"source": "a.pdf", "page": 1, "lang": "en"}),
... Record(id="b", metadata={"source": "a.pdf", "page": 1, "lang": "fr"}),
... Record(id="c", metadata={"source": "z.pdf", "page": 9}),
... ]
>>> find_near_duplicate_record_ids(records, num_hashes=4, num_bands=4)
[['a', 'b']]
See Also
find_duplicate_record_ids: an exact variant that only
groups records with identical metadata.
persista.record.analysis.find_orphan_references ¶
find_orphan_references(
records: Iterable[Record], reference_key: str
) -> list[Any]
Find records whose metadata references another record id that does not exist in the corpus.
Some corpora encode relationships between records via a metadata
field holding another record's id (e.g. a "parent_id" for
a chunk pointing back at the document it was split from). This
detects dangling references: values of reference_key that do
not match any id present in records.
This requires two passes over records (once to collect all
ids, once to check references). records is materialized into a
list up front if it is not already one, so a single-use generator
or iterator works too, at the cost of holding all records in
memory at once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
Iterable[Record]
|
A list, tuple, generator, or other iterable of
|
required |
reference_key
|
str
|
The metadata key holding the referenced record
id. Records missing this key, or whose value is |
required |
Returns:
| Type | Description |
|---|---|
list[Any]
|
A list of record |
list[Any]
|
value does not match any record id in the corpus, in the |
list[Any]
|
order their records were encountered. |
Example
>>> from persista.record import Record
>>> from persista.record.analysis import find_orphan_references
>>> records = [
... Record(id="doc1", metadata={}),
... Record(id="chunk1", metadata={"parent_id": "doc1"}),
... Record(id="chunk2", metadata={"parent_id": "missing_doc"}),
... Record(id="chunk3", metadata={}),
... ]
>>> find_orphan_references(records, reference_key="parent_id")
['chunk2']
persista.record.analysis.print_metadata_stats_report ¶
print_metadata_stats_report(
stats: dict[str, Any],
*,
title: str = "Metadata Report",
console: Console | None = None,
) -> None
Render a record-metadata-stats report (from
compute_metadata_stats) as an overview line, a summary table,
and a per-key breakdown table, inside a cyan panel that shrinks to
fit its content rather than stretching to the full terminal width.
This function orchestrates the report layout by delegating each
section to a dedicated builder: _build_overview_line (record/key
count summary), _build_summary_table (keys-per-record / data
quality), and _build_per_key_table (one row per metadata key,
with sampled values and data-quality flags).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stats
|
dict[str, Any]
|
The dict returned by |
required |
title
|
str
|
Panel title shown above the report, at the top-left of the panel border. |
'Metadata Report'
|
console
|
Console | None
|
An existing |
None
|
Returns:
| Type | Description |
|---|---|
None
|
None. Output is printed directly to |
Examples:
>>> stats = {
... "count": 2, "missing_metadata_count": 0,
... "avg_keys": 1.5, "min_keys": 1, "max_keys": 2,
... "distinct_keys_seen": 2,
... "per_key": {
... "source": {
... "present_in_records": 2, "missing_in_records": 0,
... "value_types": ["str"], "none_or_empty_count": 0,
... "unique_values_sample": ["a.pdf", "b.pdf"],
... "unique_values_sample_truncated": False,
... },
... },
... }
>>> print_metadata_stats_report(stats)
persista.record.store ¶
Contain record store utilities.
persista.record.store.BaseRecordStore ¶
Bases: ABC
Abstract base class for record stores.
Defines the common interface that all record store implementations
must provide. The API mirrors :class:persista.store.BaseStore,
with :class:~persista.record.Record instances (keyed by their
id) taking the place of key-value pairs.
To implement a custom record store, subclass
:class:BaseRecordStore and implement all abstract methods.
Implementations are expected to support use as a context manager
(with SomeRecordStore(...) as store: ...), which calls
:meth:open on entry and :meth:close on exit.
Constructing a record store does not connect to the underlying
backend: implementations must defer that to :meth:open/
:meth:aopen, so every other method (including :meth:close)
raises until the store has been opened, either explicitly or via
the context manager.
persista.record.store.BaseRecordStore.closed
abstractmethod
property
¶
closed: bool
Indicate whether the store is closed.
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
open and ready to use. |
persista.record.store.BaseRecordStore.aclear
abstractmethod
async
¶
aclear() -> None
Async equivalent of :meth:clear.
persista.record.store.BaseRecordStore.aclose
abstractmethod
async
¶
aclose() -> None
Async equivalent of :meth:close.
persista.record.store.BaseRecordStore.acontains
abstractmethod
async
¶
acontains(record_id: str) -> bool
Async equivalent of :meth:contains.
persista.record.store.BaseRecordStore.acontains_many
abstractmethod
async
¶
acontains_many(record_ids: list[str]) -> list[bool]
Async equivalent of :meth:contains_many.
persista.record.store.BaseRecordStore.acount
abstractmethod
async
¶
acount() -> int
Async equivalent of :meth:count.
persista.record.store.BaseRecordStore.adelete
abstractmethod
async
¶
adelete(record_id: str) -> None
Async equivalent of :meth:delete.
persista.record.store.BaseRecordStore.adelete_many
abstractmethod
async
¶
adelete_many(record_ids: list[str]) -> None
Async equivalent of :meth:delete_many.
persista.record.store.BaseRecordStore.afilter
abstractmethod
async
¶
afilter(**metadata_filters: Any) -> list[Record]
Async equivalent of :meth:filter.
persista.record.store.BaseRecordStore.aget
abstractmethod
async
¶
aget(record_id: str) -> Record | None
Async equivalent of :meth:get.
persista.record.store.BaseRecordStore.aget_many
abstractmethod
async
¶
aget_many(record_ids: list[str]) -> list[Record | None]
Async equivalent of :meth:get_many.
persista.record.store.BaseRecordStore.aiter_batches
abstractmethod
¶
aiter_batches(
batch_size: int = 32,
) -> AsyncIterator[list[Record]]
Async equivalent of :meth:iter_batches.
persista.record.store.BaseRecordStore.akeys
abstractmethod
¶
akeys() -> AsyncIterator[str]
Async equivalent of :meth:keys.
persista.record.store.BaseRecordStore.aopen
abstractmethod
async
¶
aopen() -> None
Async equivalent of :meth:open.
persista.record.store.BaseRecordStore.aset_many
abstractmethod
async
¶
aset_many(records: list[Record]) -> None
Async equivalent of :meth:set_many.
persista.record.store.BaseRecordStore.avalues
async
¶
avalues(batch_size: int = 32) -> AsyncIterator[Record]
Async equivalent of :meth:values.
persista.record.store.BaseRecordStore.clear
abstractmethod
¶
clear() -> None
Remove every record from the store.
This is equivalent to resetting the store to empty, without closing it.
persista.record.store.BaseRecordStore.close
abstractmethod
¶
close() -> None
Close the store and release any underlying resources (e.g. database connections, file handles).
Implementations should make repeated calls to close() safe
(i.e. idempotent), since :meth:__exit__ calls it
unconditionally and callers may also close a store manually
before using it as a context manager.
persista.record.store.BaseRecordStore.contains
abstractmethod
¶
contains(record_id: str) -> bool
Check if a record ID exists in the store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_id
|
str
|
The record ID to check. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
bool
|
otherwise. |
persista.record.store.BaseRecordStore.contains_many
abstractmethod
¶
contains_many(record_ids: list[str]) -> list[bool]
Check which record IDs exist in the store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_ids
|
list[str]
|
The record IDs to check. |
required |
Returns:
| Type | Description |
|---|---|
list[bool]
|
A list of booleans, in the same order as |
list[bool]
|
where each entry is |
list[bool]
|
ID exists in the store and |
persista.record.store.BaseRecordStore.count
abstractmethod
¶
count() -> int
Return the total number of records in the store.
Returns:
| Type | Description |
|---|---|
int
|
The number of records currently stored. |
persista.record.store.BaseRecordStore.delete
abstractmethod
¶
delete(record_id: str) -> None
Delete a record by its ID.
IDs that do not exist should be silently ignored.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_id
|
str
|
The ID of the record to delete. |
required |
persista.record.store.BaseRecordStore.delete_many
abstractmethod
¶
delete_many(record_ids: list[str]) -> None
Delete multiple records by their IDs.
IDs that do not exist should be silently ignored.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_ids
|
list[str]
|
The IDs of the records to delete. |
required |
persista.record.store.BaseRecordStore.filter
abstractmethod
¶
filter(**metadata_filters: Any) -> list[Record]
Retrieve records matching all provided metadata filters.
All filters should be combined with AND. Each keyword
argument matches the corresponding metadata key exactly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**metadata_filters
|
Any
|
Key-value pairs where each key is a metadata field name and the value is the exact value to match. Calling with no arguments should return all records. |
{}
|
Returns:
| Type | Description |
|---|---|
list[Record]
|
A list of matching :class: |
list[Record]
|
instances. |
persista.record.store.BaseRecordStore.get_many
abstractmethod
¶
get_many(record_ids: list[str]) -> list[Record | None]
Retrieve multiple records by their IDs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_ids
|
list[str]
|
The record IDs to look up. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
list[Record | None]
|
A list the same length as |
|
corresponding |
list[Record | None]
|
class: |
list[Record | None]
|
ID that exists, or |
persista.record.store.BaseRecordStore.iter_batches
abstractmethod
¶
iter_batches(
batch_size: int = 32,
) -> Generator[list[Record], None, None]
Yield records in batches, avoiding loading the whole store into memory at once.
This is the scalable equivalent of :meth:values: instead of
materializing every record as a single list, it streams them
from the database in chunks of batch_size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
batch_size
|
int
|
The maximum number of records to yield per batch. Must be a positive integer. |
32
|
Yields:
| Type | Description |
|---|---|
list[Record]
|
Lists of records, each with at most |
list[Record]
|
elements, in the same order as :meth: |
list[Record]
|
batch may contain fewer than |
persista.record.store.BaseRecordStore.keys
abstractmethod
¶
keys() -> Iterator[str]
Iterate over the IDs of all records in the store.
Yields:
| Type | Description |
|---|---|
str
|
Every record ID currently in the store. |
persista.record.store.BaseRecordStore.open
abstractmethod
¶
open() -> None
Connect to the underlying backend and prepare the store for use (e.g. open a database connection, create a directory).
The constructor must not do this itself: implementations
connect lazily, only once open() (or :meth:__enter__) is
called. Implementations should make repeated calls to
open() safe (i.e. idempotent), since a store may be
reopened after :meth:close.
persista.record.store.BaseRecordStore.set_many
abstractmethod
¶
set_many(records: list[Record]) -> None
Add or replace records in the store.
Records whose id already exists should be replaced (upsert
semantics).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
records
|
list[Record]
|
The list of :class: |
required |
persista.record.store.BaseRecordStore.values ¶
values(batch_size: int = 32) -> Iterator[Record]
Lazily iterate over all records without loading them all into memory at once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
batch_size
|
int
|
The batch size used internally when pulling records from the underlying store. Does not affect the granularity of what is yielded -- records are always yielded one at a time. |
32
|
Yields:
| Name | Type | Description |
|---|---|---|
One |
Record
|
class: |
Record
|
same order as :meth: |
persista.record.store.DuckDBRecordStore ¶
Bases: _UntypedRecordStore
Implement a :class:~persista.record.store.RecordStore backed by
a DuckDB database, with record metadata stored as JSON.
This is a convenience wrapper around
:class:persista.store.TypedDuckDBStore with no fixed schema, so
every metadata field is stored in the JSON overflow column. Use
:class:TypedDuckDBRecordStore instead when metadata fields
should be stored as their own SQL columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the DuckDB database file, or
|
':memory:'
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record import Record
>>> from persista.record.store import DuckDBRecordStore
>>> with DuckDBRecordStore() as store:
... store.set_many([Record(id="1", metadata={"author": "Alice"})])
... store.get("1")
...
Record(id='1', metadata={'author': 'Alice'})
persista.record.store.InMemoryRecordStore ¶
Bases: RecordStore
Implement a :class:~persista.record.store.RecordStore backed by
a plain in-memory dictionary store.
This is a convenience wrapper around
:class:persista.store.InMemoryStore, useful for tests, examples,
and other scenarios where records do not need to be persisted
across processes.
Example
>>> from persista.record import Record
>>> from persista.record.store import InMemoryRecordStore
>>> with InMemoryRecordStore() as store:
... store.set_many([Record(id="1", metadata={"author": "Alice"})])
... store.get("1")
...
Record(id='1', metadata={'author': 'Alice'})
persista.record.store.RecordStore ¶
Bases: BaseRecordStore, MultilineDisplayMixin
Implement a record store backed by a
:class:persista.store.BaseStore.
Records are keyed by their id in the underlying key-value
store, and a record's metadata dict is stored directly as the
value, so the id itself is not duplicated in the stored value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
BaseStore
|
The underlying key-value store. |
required |
Example
>>> from persista.record import Record
>>> from persista.record.store import RecordStore
>>> from persista.store import InMemoryStore
>>> with RecordStore(InMemoryStore()) as store:
... store.set_many([Record(id="1", metadata={"author": "Alice"})])
... store.get("1")
...
Record(id='1', metadata={'author': 'Alice'})
persista.record.store.RecordStore.afilter
async
¶
afilter(**metadata_filters: Any) -> list[Record]
Async equivalent of :meth:filter.
Note
Same fast-path/full-scan behavior as :meth:filter; see
its Note.
persista.record.store.RecordStore.filter ¶
filter(**metadata_filters: Any) -> list[Record]
See :meth:BaseRecordStore.filter.
Note
When the underlying store exposes filter_items (e.g.
Typed*Store variants whose metadata fields are stored
as their own SQL columns), metadata_filters is pushed
down to it, letting the store answer via a SQL WHERE
clause instead of a full scan. Otherwise this falls back
to a full scan of the underlying store (via
:meth:~persista.store.BaseStore.iter_batches), filtering
records in Python.
persista.record.store.SQLiteRecordStore ¶
Bases: _UntypedRecordStore
Implement a :class:~persista.record.store.RecordStore backed by
a SQLite database, with record metadata stored as JSON.
This is a convenience wrapper around
:class:persista.store.TypedSQLiteStore with no fixed schema, so
every metadata field is stored in the JSON overflow column. Use
:class:TypedSQLiteRecordStore instead when metadata fields
should be stored as their own SQL columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the SQLite database file, or
|
':memory:'
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record import Record
>>> from persista.record.store import SQLiteRecordStore
>>> with SQLiteRecordStore() as store:
... store.set_many([Record(id="1", metadata={"author": "Alice"})])
... store.get("1")
...
Record(id='1', metadata={'author': 'Alice'})
persista.record.store.TypedDuckDBRecordStore ¶
Bases: _TypedRecordStore
Implement a :class:~persista.record.store.RecordStore backed by
a DuckDB database, with each record metadata field stored as its own
typed SQL column.
This is a convenience wrapper around
:class:persista.store.TypedDuckDBStore configured with one
column per metadata field declared in metadata_schema.
Use this store when record metadata follows a known, fixed schema
and individual metadata fields should be queryable as SQL columns.
Use :class:DuckDBRecordStore instead when records may have
arbitrary or varying metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the DuckDB database file, or
|
':memory:'
|
metadata_schema
|
dict[str, str] | None
|
A mapping from metadata field name to its SQL
column type declaration (e.g. |
None
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record import Record
>>> from persista.record.store import TypedDuckDBRecordStore
>>> with TypedDuckDBRecordStore(metadata_schema={"author": "TEXT"}) as store:
... store.set_many([Record(id="1", metadata={"author": "Alice"})])
... store.get("1")
...
Record(id='1', metadata={'author': 'Alice'})
persista.record.store.TypedSQLiteRecordStore ¶
Bases: _TypedRecordStore
Implement a :class:~persista.record.store.RecordStore backed by
a SQLite database, with each record metadata field stored as its own
typed SQL column.
This is a convenience wrapper around
:class:persista.store.TypedSQLiteStore configured with one
column per metadata field declared in metadata_schema.
Use this store when record metadata follows a known, fixed schema
and individual metadata fields should be queryable as SQL columns.
Use :class:SQLiteRecordStore instead when records may have
arbitrary or varying metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the SQLite database file, or
|
':memory:'
|
metadata_schema
|
dict[str, str] | None
|
A mapping from metadata field name to its SQL
column type declaration (e.g. |
None
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record import Record
>>> from persista.record.store import TypedSQLiteRecordStore
>>> with TypedSQLiteRecordStore(metadata_schema={"author": "TEXT"}) as store:
... store.set_many([Record(id="1", metadata={"author": "Alice"})])
... store.get("1")
...
Record(id='1', metadata={'author': 'Alice'})
persista.record.store.check_is_closed ¶
check_is_closed(store: BaseRecordStore) -> None
Check that a record store is closed, raising if it is not.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
BaseRecordStore
|
The :class: |
required |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
Example
>>> from persista.record.store import InMemoryRecordStore
>>> from persista.record.store.validation import check_is_closed
>>> store = InMemoryRecordStore()
>>> check_is_closed(store)
persista.record.store.check_is_open ¶
check_is_open(store: BaseRecordStore) -> None
Check that a record store is open, raising if it is not.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
BaseRecordStore
|
The :class: |
required |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
Example
>>> from persista.record.store import InMemoryRecordStore
>>> from persista.record.store.validation import check_is_open
>>> store = InMemoryRecordStore()
>>> with store:
... check_is_open(store)
...
persista.record.store.resolve_record_store ¶
resolve_record_store(
store: BaseRecordStore | dict[str, Any],
) -> BaseRecordStore
Resolve a :class:~persista.record.store.BaseRecordStore
instance from an existing object or a configuration dictionary.
If store is already a
:class:~persista.record.store.BaseRecordStore instance it is
returned as-is. If it is a :class:dict, it is treated as an
objectory factory configuration and instantiated via
:func:objectory.factory. See
:func:~coola.factory.resolve_object for details.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
BaseRecordStore | dict[str, Any]
|
Either a fully configured
:class: |
required |
Returns:
| Type | Description |
|---|---|
BaseRecordStore
|
A configured :class: |
BaseRecordStore
|
instance. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the resolved object is not a
:class: |
Example
>>> from persista.record.store import InMemoryRecordStore, resolve_record_store
>>> # From an existing instance:
>>> store = resolve_record_store(InMemoryRecordStore())
>>> # From a configuration dictionary:
>>> store = resolve_record_store({"_target_": "persista.record.store.InMemoryRecordStore"})
persista.record.store.factory ¶
Contain factories for record stores.
persista.record.store.factory.BaseRecordStoreFactory ¶
Bases: ABC
Abstract base class for
:class:~persista.record.store.BaseRecordStore factories.
Subclasses implement :meth:make_record_store to instantiate and
return a configured :class:~persista.record.store.BaseRecordStore
object. This pattern decouples record store creation from the
rest of the codebase, making it easy to swap how a record store is
built (e.g. a shared instance vs. a fresh one per call) without
changing call sites.
Example
>>> from persista.record.store import BaseRecordStore, InMemoryRecordStore
>>> from persista.record.store.factory import BaseRecordStoreFactory
>>> class MyRecordStoreFactory(BaseRecordStoreFactory):
... def make_record_store(self) -> BaseRecordStore:
... return InMemoryRecordStore()
...
>>> factory = MyRecordStoreFactory()
>>> store = factory.make_record_store()
persista.record.store.factory.BaseRecordStoreFactory.make_record_store
abstractmethod
¶
make_record_store() -> BaseRecordStore
Create and return a configured BaseRecordStore instance.
Returns:
| Name | Type | Description |
|---|---|---|
A |
BaseRecordStore
|
class: |
BaseRecordStore
|
instance ready for use. |
persista.record.store.factory.ConfigurableRecordStoreFactory ¶
Bases: BaseRecordStoreFactory, MultilineDisplayMixin
A concrete BaseRecordStore factory that accepts either a
pre-built :class:~persista.record.store.BaseRecordStore instance
or a configuration dictionary.
When a dict is provided it is resolved at each
:meth:make_record_store call via
:func:~persista.record.store.resolve.resolve_record_store, which
uses objectory to instantiate the configured class. When an
instance is provided it is returned as-is.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_store
|
BaseRecordStore | dict[str, Any]
|
A fully configured
:class: |
required |
Example
>>> from persista.record.store import InMemoryRecordStore
>>> from persista.record.store.factory import ConfigurableRecordStoreFactory
>>> factory = ConfigurableRecordStoreFactory(InMemoryRecordStore())
>>> store = factory.make_record_store()
persista.record.store.factory.DuckDBRecordStoreFactory ¶
Bases: _UntypedRecordStoreFactory
Implement a record store factory that builds a new
:class:~persista.record.store.DuckDBRecordStore on each call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the DuckDB database file, or
|
':memory:'
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record.store.factory import DuckDBRecordStoreFactory
>>> factory = DuckDBRecordStoreFactory()
>>> store = factory.make_record_store()
persista.record.store.factory.InMemoryRecordStoreFactory ¶
Bases: BaseRecordStoreFactory, MultilineDisplayMixin
Implement a record store factory that builds a new
:class:~persista.record.store.InMemoryRecordStore on each call.
Example
>>> from persista.record.store.factory import InMemoryRecordStoreFactory
>>> factory = InMemoryRecordStoreFactory()
>>> store = factory.make_record_store()
persista.record.store.factory.RecordStoreFactory ¶
Bases: BaseRecordStoreFactory, MultilineDisplayMixin
A concrete BaseRecordStore factory that wraps a pre-built
:class:~persista.record.store.BaseRecordStore instance.
Use this when the record store is already instantiated and you
simply want to wrap it in the :class:~BaseRecordStoreFactory
interface -- for example, when injecting a fixed record store
into a component that expects a factory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record_store
|
BaseRecordStore
|
A fully configured
:class: |
required |
Example
>>> from persista.record.store import InMemoryRecordStore
>>> from persista.record.store.factory import RecordStoreFactory
>>> factory = RecordStoreFactory(InMemoryRecordStore())
>>> store = factory.make_record_store()
persista.record.store.factory.SQLiteRecordStoreFactory ¶
Bases: _UntypedRecordStoreFactory
Implement a record store factory that builds a new
:class:~persista.record.store.SQLiteRecordStore on each call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the SQLite database file, or
|
':memory:'
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record.store.factory import SQLiteRecordStoreFactory
>>> factory = SQLiteRecordStoreFactory()
>>> store = factory.make_record_store()
persista.record.store.factory.StoreRecordStoreFactory ¶
Bases: BaseRecordStoreFactory, MultilineDisplayMixin
A concrete record store factory that builds its backing store
from a :class:~persista.store.factory.BaseStoreFactory.
Use this when the underlying key-value store needs to be freshly
created (e.g. a new connection, a new in-memory dict) each time a
:class:~persista.record.store.RecordStore is requested, rather
than sharing one store instance across every record store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store_factory
|
BaseStoreFactory
|
The factory used to create the backing
key-value store passed to each
:class: |
required |
Example
>>> from persista.record.store.factory import StoreRecordStoreFactory
>>> from persista.store.factory import InMemoryStoreFactory
>>> factory = StoreRecordStoreFactory(InMemoryStoreFactory())
>>> store = factory.make_record_store()
>>> store.open()
persista.record.store.factory.TypedDuckDBRecordStoreFactory ¶
Bases: _TypedRecordStoreFactory
Implement a record store factory that builds a new
:class:~persista.record.store.TypedDuckDBRecordStore on each
call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the DuckDB database file, or
|
':memory:'
|
metadata_schema
|
dict[str, str] | None
|
A mapping from metadata field name to its SQL
column type declaration (e.g. |
None
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record.store.factory import TypedDuckDBRecordStoreFactory
>>> factory = TypedDuckDBRecordStoreFactory(metadata_schema={"author": "TEXT"})
>>> store = factory.make_record_store()
persista.record.store.factory.TypedSQLiteRecordStoreFactory ¶
Bases: _TypedRecordStoreFactory
Implement a record store factory that builds a new
:class:~persista.record.store.TypedSQLiteRecordStore on each
call.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
database
|
Path | str
|
The path to the SQLite database file, or
|
':memory:'
|
metadata_schema
|
dict[str, str] | None
|
A mapping from metadata field name to its SQL
column type declaration (e.g. |
None
|
**kwargs
|
Any
|
Additional keyword arguments passed to
:class: |
{}
|
Example
>>> from persista.record.store.factory import TypedSQLiteRecordStoreFactory
>>> factory = TypedSQLiteRecordStoreFactory(metadata_schema={"author": "TEXT"})
>>> store = factory.make_record_store()