Skip to content

Database models

database

This file was partially generated using sqlacodegen using the downloaded version of the db.sqlite file export in order to update this file, you can generate the code with:

sqlacodegen --generator sqlmodels sqlite:///db.sqlite

and patch the necessary models by merging the results. The BaseModel defines all models that can be updated from the user, and must contain a unique id. Those models can then be converted automatically into a protobuf change message using BaseModel.convert.

It is preferred to create database entries using the queries, rather than using the raw database model.

Classes:

Functions:

TableColumnsEntry

Bases: TypedDict

Parameters:

BaseModel

Bases: SQLModel

Parameters:

Methods:

  • convert

    Convert the object into distinct entries for sync method. Based on the [original implementation](

  • changed

    Returns a list of attributes changed.

  • delete

    Deletes the model, by setting the tombstone attribute to 1. It is only possible to hard delete

convert

convert(is_new: bool = True) -> list[Message]

Convert the object into distinct entries for sync method. Based on the original implementation

Source code in actual/database.py
def convert(self, is_new: bool = True) -> list[Message]:
    """Convert the object into distinct entries for sync method. Based on the [original implementation](
    https://github.com/actualbudget/actual/blob/98c17bd5e0f13e27a09a7f6ac176510530572be7/packages/loot-core/src/server/aql/schema-helpers.ts#L146)
    """
    row = getattr(self, "id", None)  # also helps lazy loading the instance
    if row is None:
        raise AttributeError(
            f"Cannot convert model {self.__name__} because it misses the 'id' attribute.\n"
            f"If you see this error, make sure your entry has a unique 'id' as primary key."
        )
    # compute changes from a sqlalchemy instance, see https://stackoverflow.com/a/28353846/12681470
    changes = []
    table_name = str(self.__tablename__)
    for column in self.changed():
        converted_attr_name = get_attribute_by_table_name(table_name, column, reverse=True)
        m = Message(dict(dataset=table_name, row=row, column=converted_attr_name))
        value = self.__getattribute__(column)
        # we cannot store boolean values, so we always convert it to integer
        if isinstance(value, bool):
            value = int(value)
        # if the entry is new, we can ignore null columns, otherwise consider it an update to None
        if value is not None or not is_new:
            m.set_value(value)
            changes.append(m)
    return changes

changed

changed() -> list[str]

Returns a list of attributes changed.

Source code in actual/database.py
def changed(self) -> list[str]:
    """Returns a list of attributes changed."""
    changed_attributes = []
    inspr = inspect(self)
    attrs = class_mapper(self.__class__).column_attrs  # exclude relationships
    for attr in attrs:
        column = attr.key
        if column == "id":
            continue
        hist = getattr(inspr.attrs, column).history  # type: ignore[union-attr]
        if hist.has_changes():
            changed_attributes.append(column)
    return changed_attributes

delete

delete()

Deletes the model, by setting the tombstone attribute to 1. It is only possible to hard delete transactions by updating and re-uploading the downloaded budget.

Source code in actual/database.py
def delete(self):
    """Deletes the model, by setting the `tombstone` attribute to 1. It is only possible to hard delete
    transactions by updating and re-uploading the downloaded budget."""
    if not hasattr(self, "tombstone"):
        raise AttributeError(f"Model {self.__class__.__name__} has no tombstone field and cannot be deleted.")
    setattr(self, "tombstone", 1)

Meta

Bases: SQLModel

Parameters:

  • key

    (str | None, default: None ) –
  • value

    (str | None, default: None ) –

Migrations

Bases: SQLModel

Parameters:

  • id

    (int | None, default: None ) –

Accounts

Bases: BaseModel

Represents an account entity with detailed attributes describing account properties, transactions, and relationships.

This class is used to model financial accounts, and it includes methods and attributes necessary for managing and interacting with account-related data.

Parameters:

  • id

    (str) –
  • account_id

    (str | None, default: None ) –
  • name

    (str | None, default: None ) –
  • balance_current

    (int | None, default: None ) –
  • balance_available

    (int | None, default: None ) –
  • balance_limit

    (int | None, default: None ) –
  • mask

    (str | None, default: None ) –
  • official_name

    (str | None, default: None ) –
  • subtype

    (str | None, default: None ) –
  • bank_id

    (str | None, default: None ) –
  • offbudget

    (int | None, default: None ) –
  • closed

    (int | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • sort_order

    (float | None, default: None ) –
  • type

    (str | None, default: None ) –
  • account_sync_source

    (str | None, default: None ) –
  • last_sync

    (str | None, default: None ) –
  • last_reconciled

    (str | None, default: None ) –

Attributes:

  • balance (Decimal) –

    Returns the current balance of the account. Deleted transactions are ignored.

  • notes (str | None) –

    Returns notes for the account. If none is present, returns None.

balance property

balance: Decimal

Returns the current balance of the account. Deleted transactions are ignored.

notes property writable

notes: str | None

Returns notes for the account. If none is present, returns None.

Banks

Bases: BaseModel

Parameters:

  • id

    (str) –
  • bank_id

    (str | None, default: None ) –
  • name

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –

Categories

Bases: BaseModel

Stores the category list, which is the classification applied on top of the transaction.

Each category will belong to its own category group.

Parameters:

  • id

    (str) –
  • hidden

    (bool) –
  • name

    (str | None, default: None ) –
  • is_income

    (int | None, default: None ) –
  • cat_group

    (str | None, default: None ) –
  • sort_order

    (float | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • goal_def

    (str | None, default: None ) –
  • template_settings

    (dict | None, default: None ) –

Attributes:

  • balance (Decimal) –

    Returns the current balance of the category. Deleted transactions are ignored.

  • notes (str | None) –

    Returns notes for the category. If none is present, returns None.

balance property

balance: Decimal

Returns the current balance of the category. Deleted transactions are ignored.

notes property writable

notes: str | None

Returns notes for the category. If none is present, returns None.

CategoryGroups

Bases: BaseModel

Stores the groups that the categories can belong to.

Parameters:

  • id

    (str) –
  • hidden

    (bool) –
  • name

    (str | None, default: None ) –
  • is_income

    (int | None, default: None ) –
  • sort_order

    (float | None, default: None ) –
  • tombstone

    (int | None, default: None ) –

CategoryMapping

Bases: BaseModel

Parameters:

  • id

    (str) –
  • transfer_id

    (str | None, default: None ) –

CreatedBudgets

Bases: SQLModel

Parameters:

  • month

    (str | None, default: None ) –

CustomReports

Bases: BaseModel

Metadata for all the custom reports available on the Actual frontend.

Parameters:

  • id

    (str) –
  • name

    (str | None, default: None ) –
  • start_date

    (str | None, default: None ) –
  • end_date

    (str | None, default: None ) –
  • date_static

    (int | None, default: None ) –
  • date_range

    (str | None, default: None ) –
  • mode

    (str | None, default: None ) –
  • group_by

    (str | None, default: None ) –
  • balance_type

    (str | None, default: None ) –
  • show_empty

    (int | None, default: None ) –
  • show_offbudget

    (int | None, default: None ) –
  • show_hidden

    (int | None, default: None ) –
  • show_uncategorized

    (int | None, default: None ) –
  • selected_categories

    (str | None, default: None ) –
  • graph_type

    (str | None, default: None ) –
  • conditions

    (str | None, default: None ) –
  • conditions_op

    (str | None, default: None ) –
  • metadata_

    (str | None, default: None ) –
  • interval

    (str | None, default: None ) –
  • color_scheme

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • include_current

    (int | None, default: None ) –
  • sort_by

    (str | None, default: None ) –
  • trim_intervals

    (int | None, default: None ) –

Dashboard

Bases: BaseModel

A dashboard holds the JSON information in the meta column.

These dashboards are grouped together in a DashboardPages object.

Parameters:

  • id

    (str) –
  • type

    (str | None, default: None ) –
  • width

    (int | None, default: None ) –
  • height

    (int | None, default: None ) –
  • x

    (int | None, default: None ) –
  • y

    (int | None, default: None ) –
  • meta

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • dashboard_page_id

    (str | None, default: None ) –

DashboardPages

Bases: SQLModel

Named collection of multiple Dashboard objects in one dashboard page.

Parameters:

  • id

    (str) –
  • name

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –

Kvcache

Bases: SQLModel

Parameters:

  • key

    (str | None, default: None ) –
  • value

    (str | None, default: None ) –

KvcacheKey

Bases: SQLModel

Parameters:

  • id

    (int | None, default: None ) –
  • key

    (float | None, default: None ) –

MessagesClock

Bases: SQLModel

Parameters:

  • id

    (int | None, default: None ) –
  • clock

    (str | None, default: None ) –

Methods:

  • get_clock

    Gets the clock from JSON text to a dictionary with fields timestamp and merkle.

  • set_clock

    Sets the clock from a dictionary and stores it in the correct format.

  • get_timestamp

    Gets the timestamp from the clock value directly as a HULC_Client.

  • set_timestamp

    Sets the timestamp on the clock value based on the HULC_Client

get_clock

get_clock() -> dict

Gets the clock from JSON text to a dictionary with fields timestamp and merkle.

Source code in actual/database.py
def get_clock(self) -> dict:
    """Gets the clock from JSON text to a dictionary with fields `timestamp` and `merkle`."""
    if self.clock is None:
        raise ValueError("Clock is not set")
    return json.loads(self.clock)

set_clock

set_clock(value: dict)

Sets the clock from a dictionary and stores it in the correct format.

Source code in actual/database.py
def set_clock(self, value: dict):
    """Sets the clock from a dictionary and stores it in the correct format."""
    self.clock = json.dumps(value, separators=(",", ":"))

get_timestamp

get_timestamp() -> HULC_Client

Gets the timestamp from the clock value directly as a HULC_Client.

Source code in actual/database.py
def get_timestamp(self) -> HULC_Client:
    """Gets the timestamp from the clock value directly as a [HULC_Client][actual.protobuf_models.HULC_Client]."""
    clock = self.get_clock()
    return HULC_Client.from_timestamp(clock["timestamp"])

set_timestamp

set_timestamp(client: HULC_Client) -> None

Sets the timestamp on the clock value based on the HULC_Client provided.

Source code in actual/database.py
def set_timestamp(self, client: HULC_Client) -> None:
    """Sets the timestamp on the clock value based on the [HULC_Client][actual.protobuf_models.HULC_Client]
    provided."""
    clock_message = self.get_clock()
    clock_message["timestamp"] = str(client)
    self.set_clock(clock_message)

MessagesCrdt

Bases: SQLModel

Parameters:

  • timestamp

    (str) –
  • dataset

    (str) –
  • row

    (str) –
  • column

    (str) –
  • value

    (bytes) –
  • id

    (int | None, default: None ) –

Notes

Bases: BaseModel

Stores the description of each account.

Parameters:

  • id

    (str) –
  • note

    (str | None, default: None ) –

PayeeMapping

Bases: BaseModel

Parameters:

  • id

    (str) –
  • target_id

    (str | None, default: None ) –

Payees

Bases: BaseModel

Stores the individual payees.

Each payee is a unique identifier that can be assigned to a transaction. Certain payees have empty names and are associated to the accounts themselves, representing the transfer between one account and another. These would have the field account not set to None.

Parameters:

  • id

    (str) –
  • name

    (str | None, default: None ) –
  • category

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • transfer_acct

    (str | None, default: None ) –
  • favorite

    (int | None, default: None ) –
  • learn_categories

    (bool | None) –

Attributes:

  • balance (Decimal) –

    Returns the current balance of the payee. Deleted transactions are ignored.

balance property

balance: Decimal

Returns the current balance of the payee. Deleted transactions are ignored.

Preferences

Bases: BaseModel

Stores the preferences for the user, using key/value pairs.

Parameters:

  • id

    (str) –
  • value

    (str | None, default: None ) –

Rules

Bases: BaseModel

Stores all rules on the budget. The conditions and actions are stored separately using the JSON format.

The conditions are stored as a text field, but can be retrieved as a model using get_ruleset.

Parameters:

  • id

    (str) –
  • stage

    (str | None, default: None ) –
  • conditions

    (str | None, default: None ) –
  • actions

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • conditions_op

    (str | None, default: None ) –

Schedules

Bases: BaseModel

Stores the schedules defined by the user. Is also linked to a rule that executes it.

Parameters:

  • id

    (str) –
  • rule_id

    (str | None, default: None ) –
  • active

    (int | None, default: None ) –
  • completed

    (int | None, default: None ) –
  • posts_transaction

    (int | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • name

    (str | None, default: None ) –

SchedulesJsonPaths

Bases: SQLModel

Parameters:

  • schedule_id

    (str | None, default: None ) –
  • payee

    (str | None, default: None ) –
  • account

    (str | None, default: None ) –
  • amount

    (str | None, default: None ) –
  • date

    (str | None, default: None ) –

SchedulesNextDate

Bases: BaseModel

Parameters:

  • id

    (str) –
  • schedule_id

    (str | None, default: None ) –
  • local_next_date

    (int | None, default: None ) –
  • local_next_date_ts

    (int | None, default: None ) –
  • base_next_date

    (int | None, default: None ) –
  • base_next_date_ts

    (int | None, default: None ) –
  • tombstone

    (int | None, default: None ) –

Tags

Bases: BaseModel

Parameters:

  • id

    (str) –
  • tag

    (str | None, default: None ) –
  • color

    (str | None, default: None ) –

    Color in hex format (i.e. '#690CB0')

  • description

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –

Attributes:

transactions property

transactions: Sequence[Transactions]

Returns all transactions with this tag associated to them.

TransactionFilters

Bases: BaseModel

Parameters:

  • id

    (str) –
  • name

    (str | None, default: None ) –
  • conditions

    (str | None, default: None ) –
  • conditions_op

    (str | None, default: None ) –
  • tombstone

    (int | None, default: None ) –

Transactions

Bases: BaseModel

Contains all transactions inserted into Actual.

Parameters:

  • id

    (str) –
  • is_parent

    (int | None, default: None ) –
  • is_child

    (int | None, default: None ) –
  • acct

    (str) –
  • category_id

    (str | None, default: None ) –
  • amount

    (int | None, default: None ) –
  • payee_id

    (str | None, default: None ) –
  • notes

    (str | None, default: None ) –
  • date

    (int | None, default: None ) –
  • financial_id

    (str | None, default: None ) –
  • type

    (str | None, default: None ) –
  • location

    (str | None, default: None ) –
  • error

    (str | None, default: None ) –
  • imported_description

    (str | None, default: None ) –
  • starting_balance_flag

    (int | None, default: None ) –
  • transferred_id

    (str | None, default: None ) –
  • sort_order

    (float | None, default: None ) –
  • tombstone

    (int | None, default: None ) –
  • cleared

    (int | None, default: None ) –
  • pending

    (int | None, default: None ) –
  • parent_id

    (str | None, default: None ) –
  • schedule_id

    (str | None, default: None ) –
  • reconciled

    (int | None, default: None ) –
  • raw_synced_data

    (str | None, default: None ) –

Methods:

  • get_date

    Returns the transaction date as a datetime.date object, instead of as a string.

  • set_date

    Sets the transaction date as a datetime.date object, instead of as a string.

  • set_amount

    Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents.

  • get_amount

    Returns the amount as a decimal.Decimal, instead of as an integer representing the number of cents.

  • validate_cleared

    Add an validator which ensures that clearing parent transactions also affects all splits

  • delete

    Overload the delete() from the BaseModel so that we can properly delete any children splits

get_date

get_date() -> date

Returns the transaction date as a datetime.date object, instead of as a string.

Source code in actual/database.py
def get_date(self) -> datetime.date:
    """Returns the transaction date as a datetime.date object, instead of as a string."""
    if self.date is None:
        raise ValueError("Transaction date is not set")
    return int_to_date(self.date)

set_date

set_date(date: date)

Sets the transaction date as a datetime.date object, instead of as a string.

Source code in actual/database.py
def set_date(self, date: datetime.date):
    """Sets the transaction date as a datetime.date object, instead of as a string."""
    self.date = date_to_int(date)

set_amount

set_amount(amount: Decimal | int | float)

Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents.

Source code in actual/database.py
def set_amount(self, amount: decimal.Decimal | int | float):
    """Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents."""
    self.amount = decimal_to_cents(amount)

get_amount

get_amount() -> Decimal

Returns the amount as a decimal.Decimal, instead of as an integer representing the number of cents.

Source code in actual/database.py
def get_amount(self) -> decimal.Decimal:
    """Returns the amount as a decimal.Decimal, instead of as an integer representing the number of cents."""
    return cents_to_decimal(self.amount)

validate_cleared

validate_cleared(key, v)

Add an validator which ensures that clearing parent transactions also affects all splits

Source code in actual/database.py
@validates("cleared")
def validate_cleared(self, key, v):
    """Add an validator which ensures that clearing parent transactions also affects all splits"""

    # Validation only performed on parent transactions where cleared is changed
    if self.is_parent and self.cleared != v:
        session = self._object_session()
        splits = session.scalars(select(Transactions).where(Transactions.parent_id == self.id)).all()
        for s in splits:
            s.cleared = v

    # Return the input value unmodified as this is a validator for the parent
    return v

delete

delete()

Overload the delete() from the BaseModel so that we can properly delete any children splits as well. Otherwise things will not add up in the Actual GUI when calling delete() on a parent.

It is technically possible to call delete() a child transaction, that would probably also cause things to go out of sync ,but since that is not possible to do in the UI this case is not handled here and is left as undefined behaviour.

Neither is it handled if the tombstone flag is set directly on an object without using the delete() metod. If you are into this direct attribute modification you will have to handle the splits yourself.

Source code in actual/database.py
def delete(self):
    """Overload the delete() from the BaseModel so that we can properly delete any children splits
    as well. Otherwise things will not add up in the Actual GUI when calling delete() on a parent.

    It is technically possible to call delete() a child transaction, that would probably also cause
    things to go out of sync ,but since that is not possible to do in the UI this case is not handled
    here and is left as undefined behaviour.

    Neither is it handled if the tombstone flag is set directly on an object without using the delete()
    metod. If you are into this direct attribute modification you will have to handle the splits yourself.
    """

    # Check if this is a parent transaction, if so iterate the children and call delete() on them as well
    if self.is_parent:
        session = self._object_session()
        splits = session.scalars(select(Transactions).where(Transactions.parent_id == self.id)).all()
        for s in splits:
            s.delete()

    # Utilise the BaseModel delete() for deleting the transaction
    super().delete()

ZeroBudgetMonths

Bases: BaseModel

Holds the amount of budget held for the next month for a specific budget id.

Only applies to envelope budgets and is attached to a ZeroBudgets object.

The month data is stored on the id field instead of the default uuid as id. Here, Actual actually ignores the previous models for the int dates and instead uses a string with "-" as separator (i.e., '2025-09'). The buffered represents the amount held for the next month in cents as usual.

Parameters:

  • id

    (str) –
  • buffered

    (int | None, default: None ) –

Methods:

  • get_month

    Returns the month as a datetime.date object, instead of as a string.

  • set_month

    Sets the month as a datetime.date object, instead of as a string.

  • set_amount

    Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents.

  • get_amount

    Returns the amount being held for next month for a budget as a decimal.Decimal.

get_month

get_month() -> date

Returns the month as a datetime.date object, instead of as a string.

Source code in actual/database.py
def get_month(self) -> datetime.date:
    """Returns the month as a datetime.date object, instead of as a string."""
    return int_to_date(self.id.replace("-", ""), month_only=True)

set_month

set_month(month: date)

Sets the month as a datetime.date object, instead of as a string.

Source code in actual/database.py
def set_month(self, month: datetime.date):
    """Sets the month as a datetime.date object, instead of as a string."""
    self.id = datetime.date.strftime(month, "%Y-%m")

set_amount

set_amount(amount: Decimal | int | float)

Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents.

Source code in actual/database.py
def set_amount(self, amount: decimal.Decimal | int | float):
    """Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents."""
    self.buffered = decimal_to_cents(amount)

get_amount

get_amount() -> Decimal

Returns the amount being held for next month for a budget as a decimal.Decimal.

Source code in actual/database.py
def get_amount(self) -> decimal.Decimal:
    """
    Returns the amount being held for next month for a budget as a `decimal.Decimal`."""
    return cents_to_decimal(self.buffered)

BaseBudgets

Bases: BaseModel

Hosts the shared code between both ZeroBudgets and ReflectBudgets.

Each budget will represent a certain month in a certain category. When a budget is missing on the frontend, frontend will assume this value is zero, but the entity will be missing from the database.

Parameters:

  • id

    (str) –
  • month

    (int | None, default: None ) –
  • category_id

    (str | None, default: None ) –
  • amount

    (int | None, default: None ) –
  • carryover

    (int | None, default: None ) –

Methods:

  • get_date

    Returns the transaction date as a datetime.date object, instead of as a string.

  • set_date

    Sets the transaction date as a datetime.date object, instead of as a string.

  • set_amount

    Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents.

  • get_amount

    Returns the amount as a decimal.Decimal, instead of as an integer representing the number of cents.

Attributes:

  • range (tuple[date, date]) –

    Range of the budget as a tuple [start, end).

  • balance (Decimal) –

    Returns the current spent balance of the budget.

  • notes (str | None) –

    Returns notes for the budget. If none is present, returns None.

range property

range: tuple[date, date]

Range of the budget as a tuple [start, end).

The end date is not inclusive, as it represents the start of the next month.

balance property

balance: Decimal

Returns the current spent balance of the budget.

The evaluation will take into account the budget month and only selected transactions for the combination month and category. Deleted transactions are ignored.

If you want to get the balance from the frontend, take a look at the query get_accumulated_budgeted_balance instead.

notes property writable

notes: str | None

Returns notes for the budget. If none is present, returns None.

get_date

get_date() -> date

Returns the transaction date as a datetime.date object, instead of as a string.

Source code in actual/database.py
def get_date(self) -> datetime.date:
    """Returns the transaction date as a datetime.date object, instead of as a string."""
    if self.month is None:
        raise ValueError("Budget month is not set")
    return int_to_date(self.month, month_only=True)

set_date

set_date(date: date)

Sets the transaction date as a datetime.date object, instead of as a string.

If the date value contains a day, it will be truncated and only the month and year will be inserted, as the budget applies to a month.

Source code in actual/database.py
def set_date(self, date: datetime.date):
    """
    Sets the transaction date as a datetime.date object, instead of as a string.

    If the date value contains a day, it will be truncated and only the month and year will be inserted, as the
    budget applies to a month.
    """
    self.month = date_to_int(date, month_only=True)

set_amount

set_amount(amount: Decimal | int | float)

Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents.

Source code in actual/database.py
def set_amount(self, amount: decimal.Decimal | int | float):
    """Sets the amount as a decimal.Decimal object, instead of as an integer representing the number of cents."""
    self.amount = decimal_to_cents(amount)

get_amount

get_amount() -> Decimal

Returns the amount as a decimal.Decimal, instead of as an integer representing the number of cents.

Source code in actual/database.py
def get_amount(self) -> decimal.Decimal:
    """Returns the amount as a decimal.Decimal, instead of as an integer representing the number of cents."""
    return cents_to_decimal(self.amount)

ReflectBudgets

Bases: BaseBudgets

Stores the budgets, when using tracking budget.

This table will only contain data for the entries which are created. If a combination of category and budget month is not existing, it is assumed that the budget is 0.

Parameters:

  • id

    (str) –
  • month

    (int | None, default: None ) –
  • category_id

    (str | None, default: None ) –
  • amount

    (int | None, default: None ) –
  • carryover

    (int | None, default: None ) –
  • goal

    (int | None, default: None ) –
  • long_goal

    (int | None, default: None ) –

ZeroBudgets

Bases: BaseBudgets

Stores the budgets, when using envelope budget (default).

This table will only contain data for the entries which are created. If a combination of category and budget month is not existing, it is assumed that the budget is 0.

Parameters:

  • id

    (str) –
  • month

    (int | None, default: None ) –
  • category_id

    (str | None, default: None ) –
  • amount

    (int | None, default: None ) –
  • carryover

    (int | None, default: None ) –
  • goal

    (int | None, default: None ) –
  • long_goal

    (int | None, default: None ) –

PendingTransactions

Bases: SQLModel

Parameters:

  • id

    (str) –
  • acct

    (int | None, default: None ) –
  • amount

    (int | None, default: None ) –
  • description

    (str | None, default: None ) –
  • date

    (str | None, default: None ) –

reflect_model

reflect_model(eng: Engine) -> MetaData

Reflects the current state of the database, containing the state of all remote tables and columns.

Source code in actual/database.py
def reflect_model(eng: engine.Engine) -> MetaData:
    """Reflects the current state of the database, containing the state of all remote tables and columns."""
    local_meta = MetaData()
    local_meta.reflect(bind=eng)
    return local_meta

get_class_from_reflected_table_name

get_class_from_reflected_table_name(
    metadata: MetaData, table_name: str
) -> Table | None

Returns, based on the defined tables on the reflected model the corresponding SQLAlchemy table.

If not found, returns None.

Source code in actual/database.py
def get_class_from_reflected_table_name(metadata: MetaData, table_name: str) -> Table | None:
    """
    Returns, based on the defined tables on the reflected model the corresponding SQLAlchemy table.

    If not found, returns `None`.
    """
    return metadata.tables.get(table_name, None)

get_attribute_from_reflected_table_name

get_attribute_from_reflected_table_name(
    metadata: MetaData, table_name: str, column_name: str
) -> Column | None

Returns, based on the defined reflected model the corresponding and the SAColumn.

If not found, returns None.

Source code in actual/database.py
def get_attribute_from_reflected_table_name(metadata: MetaData, table_name: str, column_name: str) -> Column | None:
    """
    Returns, based on the defined reflected model the corresponding and the SAColumn.

    If not found, returns `None`.
    """
    table = get_class_from_reflected_table_name(metadata, table_name)
    if table is None:
        return None
    return table.columns.get(column_name, None)

get_class_by_table_name

get_class_by_table_name(table_name: str) -> type[BaseModel]

Returns, based on the defined tables __tablename__ the corresponding SQLModel object.

If not found, raises ValueError.

Parameters:

  • table_name

    (str) –

    SQL table name.

Returns:

Raises:

  • ValueError

    Raises ValueError if the table name is not existing.

Source code in actual/database.py
def get_class_by_table_name(table_name: str) -> type["BaseModel"]:
    """
    Returns, based on the defined tables `__tablename__` the corresponding SQLModel object.

    If not found, raises `ValueError`.

    :param table_name: SQL table name.
    :return SQLModel: SQLAlchemy object.
    :raises ValueError: Raises `ValueError` if the table name is not existing.
    """
    entry = __TABLE_COLUMNS_MAP__.get(table_name)
    if entry is None:
        raise ValueError(f"Could not find table '{table_name}' on the database model.")
    return entry["entity"]

get_attribute_by_table_name

get_attribute_by_table_name(
    table_name: str, column_name: str, reverse: bool = False
) -> str | None

Returns, based on the defined tables __tablename__ and the SAColumn name, the correct pydantic attribute.

The search can be reversed by setting the reverse flag to True. If not found, returns None.

Parameters:

  • table_name

    (str) –

    SQL table name.

  • column_name

    (str) –

    SQL column name.

  • reverse

    (bool, default: False ) –

    If true, reverses the search and returns the SAColumn from the Pydantic attribute.

Returns:

  • str | None

    Pydantic attribute name or SAColumn name.

Source code in actual/database.py
def get_attribute_by_table_name(table_name: str, column_name: str, reverse: bool = False) -> str | None:
    """
    Returns, based on the defined tables `__tablename__` and the SAColumn name, the correct pydantic attribute.

    The search can be reversed by setting the `reverse` flag to `True`. If not found, returns `None`.

    :param table_name: SQL table name.
    :param column_name: SQL column name.
    :param reverse: If true, reverses the search and returns the SAColumn from the Pydantic attribute.
    :return: Pydantic attribute name or SAColumn name.
    """
    entry = __TABLE_COLUMNS_MAP__.get(table_name)
    if entry is None:
        return None
    mapping = entry["columns"] if not reverse else entry["rev_columns"]
    return mapping.get(column_name)

apply_change

apply_change(
    session: Session,
    table: Table,
    table_id: str,
    values: dict[Column, str | int | float | None],
) -> None

This function upserts multiple changes into a table based on the table_id as the primary key.

All the values will be inserted as a new row, and if the id already exists, the values will be updated.

This function has no return value, as the insert statement was crafter to execute as quick as possible.

Source code in actual/database.py
def apply_change(session: Session, table: Table, table_id: str, values: dict[Column, str | int | float | None]) -> None:
    """
    This function upserts multiple changes into a table based on the `table_id` as the primary key.

    All the `values` will be inserted as a new row, and if the `id` already exists, the values will be updated.

    This function has no return value, as the insert statement was crafter to execute as quick as possible.
    """
    insert_stmt = (
        insert(table).values({"id": table_id, **values}).on_conflict_do_update(index_elements=["id"], set_=values)
    )
    session.exec(insert_stmt)

strong_reference_session

strong_reference_session(session: Session)

References a session so that all object instances created on the session can be tracked.

This is used to make sure that every update on the budget via the library can be converted to a sync request that will be sent to the Actual server.

Source code in actual/database.py
def strong_reference_session(session: Session):
    """
    References a session so that all object instances created on the session can be tracked.

    This is used to make sure that every update on the budget via the library can be converted to a sync request that
    will be sent to the Actual server.
    """

    @event.listens_for(session, "before_flush")
    def before_flush(sess, flush_context, instances):
        if len(sess.deleted):
            raise ActualInvalidOperationError(
                "Actual does not allow deleting entries, set the `tombstone` to 1 instead or call the .delete() method"
            )
        if "messages" not in sess.info:
            sess.info["messages"] = messages = []
        else:
            messages = sess.info["messages"]
        # convert entries from the model
        for instance in sess.new:
            # all entries that were added new
            messages.extend(instance.convert(is_new=True))
        for instance in sess.dirty:
            # all entries that were modified
            messages.extend(instance.convert(is_new=False))

    @event.listens_for(session, "after_commit")
    @event.listens_for(session, "after_soft_rollback")
    def after_commit_or_rollback(
        sess,
        previous_transaction=None,
    ):
        if sess.info.get("messages"):
            del sess.info["messages"]

    return session