Implemented Delete feature in DataGridsManager.py. There is still a bug as DBEngine.delete is not implemented
Improved readability for tests using matcher
This commit is contained in:
@@ -15,7 +15,7 @@ class DataGridsRegistry(SingleInstance):
|
||||
|
||||
def put(self, namespace, name, datagrid_id):
|
||||
"""
|
||||
|
||||
|
||||
:param namespace:
|
||||
:param name:
|
||||
:param datagrid_id:
|
||||
@@ -25,6 +25,18 @@ class DataGridsRegistry(SingleInstance):
|
||||
all_entries[datagrid_id] = (namespace, name)
|
||||
self._db_manager.save(DATAGRIDS_REGISTRY_ENTRY_KEY, all_entries)
|
||||
|
||||
def remove(self, datagrid_id):
|
||||
"""
|
||||
Remove a datagrid from the registry.
|
||||
|
||||
Args:
|
||||
datagrid_id: ID of the datagrid to remove
|
||||
"""
|
||||
all_entries = self._db_manager.load(DATAGRIDS_REGISTRY_ENTRY_KEY)
|
||||
if datagrid_id in all_entries:
|
||||
del all_entries[datagrid_id]
|
||||
self._db_manager.save(DATAGRIDS_REGISTRY_ENTRY_KEY, all_entries)
|
||||
|
||||
def get_all_tables(self):
|
||||
all_entries = self._get_all_entries()
|
||||
return [f"{namespace}.{name}" for (namespace, name) in all_entries.values()]
|
||||
@@ -45,28 +57,28 @@ class DataGridsRegistry(SingleInstance):
|
||||
try:
|
||||
as_fullname_dict = self._get_entries_as_full_name_dict()
|
||||
grid_id = as_fullname_dict[table_name]
|
||||
|
||||
|
||||
# load dataframe from dedicated store
|
||||
store = self._db_manager.load(f"{grid_id}#df")
|
||||
df = store["ne_df"] if store else None
|
||||
return df[column_name].tolist() if df is not None else []
|
||||
|
||||
|
||||
except KeyError:
|
||||
return []
|
||||
|
||||
|
||||
def get_row_count(self, table_name):
|
||||
try:
|
||||
as_fullname_dict = self._get_entries_as_full_name_dict()
|
||||
grid_id = as_fullname_dict[table_name]
|
||||
|
||||
|
||||
# load dataframe from dedicated store
|
||||
store = self._db_manager.load(f"{grid_id}#df")
|
||||
df = store["ne_df"] if store else None
|
||||
return len(df) if df is not None else 0
|
||||
|
||||
|
||||
except KeyError:
|
||||
return 0
|
||||
|
||||
|
||||
def get_column_type(self, table_name, column_name):
|
||||
"""
|
||||
Get the type of a column.
|
||||
@@ -81,11 +93,11 @@ class DataGridsRegistry(SingleInstance):
|
||||
try:
|
||||
as_fullname_dict = self._get_entries_as_full_name_dict()
|
||||
grid_id = as_fullname_dict[table_name]
|
||||
|
||||
|
||||
# load datagrid state
|
||||
state_id = f"{grid_id}#state"
|
||||
state = self._db_manager.load(state_id)
|
||||
|
||||
|
||||
if state and "columns" in state:
|
||||
for col in state["columns"]:
|
||||
if col.col_id == column_name:
|
||||
|
||||
@@ -3,7 +3,8 @@ import inspect
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
from typing import Optional
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Literal
|
||||
|
||||
from myutils.observable import NotObservableError, ObservableResultCollector
|
||||
|
||||
@@ -15,6 +16,19 @@ logger = logging.getLogger("Commands")
|
||||
AUTO_SWAP_OOB = "__auto_swap_oob__"
|
||||
|
||||
|
||||
@dataclass
|
||||
class BoundCommand:
|
||||
"""
|
||||
Represents a command bound to another command.
|
||||
|
||||
Attributes:
|
||||
command: The command to execute
|
||||
when: When to execute the bound command ("before" or "after" the main command)
|
||||
"""
|
||||
command: 'Command'
|
||||
when: Literal["before", "after"] = "after"
|
||||
|
||||
|
||||
class Command:
|
||||
"""
|
||||
Represents the base command class for defining executable actions.
|
||||
@@ -128,19 +142,31 @@ class Command:
|
||||
def execute(self, client_response: dict = None):
|
||||
logger.debug(f"Executing command {self.name} with arguments {client_response=}")
|
||||
with ObservableResultCollector(self._bindings) as collector:
|
||||
# Execute "before" bound commands
|
||||
ret_from_before_commands = []
|
||||
if self.owner:
|
||||
before_commands = [bc for bc in self.owner.get_bound_commands(self.name) if bc.when == "before"]
|
||||
for bound_cmd in before_commands:
|
||||
logger.debug(f" will execute bound command {bound_cmd.command.name} BEFORE...")
|
||||
r = bound_cmd.command.execute(client_response)
|
||||
ret_from_before_commands.append(r)
|
||||
|
||||
# Execute main callback
|
||||
kwargs = self._create_kwargs(self.default_kwargs,
|
||||
client_response,
|
||||
{"client_response": client_response or {}})
|
||||
ret = self.callback(*self.default_args, **kwargs)
|
||||
|
||||
ret_from_bound_commands = []
|
||||
|
||||
# Execute "after" bound commands
|
||||
ret_from_after_commands = []
|
||||
if self.owner:
|
||||
for command in self.owner.get_bound_commands(self.name):
|
||||
logger.debug(f" will execute bound command {command.name}...")
|
||||
r = command.execute(client_response)
|
||||
ret_from_bound_commands.append(r) # it will be flatten if needed later
|
||||
|
||||
all_ret = flatten(ret, ret_from_bound_commands, collector.results)
|
||||
after_commands = [bc for bc in self.owner.get_bound_commands(self.name) if bc.when == "after"]
|
||||
for bound_cmd in after_commands:
|
||||
logger.debug(f" will execute bound command {bound_cmd.command.name} AFTER...")
|
||||
r = bound_cmd.command.execute(client_response)
|
||||
ret_from_after_commands.append(r)
|
||||
|
||||
all_ret = flatten(ret, ret_from_before_commands, ret_from_after_commands, collector.results)
|
||||
|
||||
# Set the hx-swap-oob attribute on all elements returned by the callback
|
||||
if self._htmx_extra[AUTO_SWAP_OOB]:
|
||||
|
||||
@@ -3,6 +3,7 @@ import uuid
|
||||
from typing import Optional
|
||||
|
||||
from myfasthtml.controls.helpers import Ids
|
||||
from myfasthtml.core.commands import BoundCommand
|
||||
from myfasthtml.core.constants import NO_DEFAULT_VALUE
|
||||
from myfasthtml.core.utils import pascal_to_snake, get_class, snake_to_pascal
|
||||
|
||||
@@ -109,9 +110,18 @@ class BaseInstance:
|
||||
parent = self.get_parent()
|
||||
return parent.get_full_id() if parent else None
|
||||
|
||||
def bind_command(self, command, command_to_bind):
|
||||
def bind_command(self, command, command_to_bind, when="after"):
|
||||
"""
|
||||
Bind a command to another command.
|
||||
|
||||
Args:
|
||||
command: Command name or Command instance to bind to
|
||||
command_to_bind: Command to execute when the main command is triggered
|
||||
when: "before" or "after" - when to execute the bound command (default: "after")
|
||||
"""
|
||||
command_name = command.name if hasattr(command, "name") else command
|
||||
self._bound_commands.setdefault(command_name, []).append(command_to_bind)
|
||||
bound = BoundCommand(command=command_to_bind, when=when)
|
||||
self._bound_commands.setdefault(command_name, []).append(bound)
|
||||
|
||||
def get_bound_commands(self, command_name):
|
||||
return self._bound_commands.get(command_name, [])
|
||||
|
||||
Reference in New Issue
Block a user