예제 #1
0
    def Drop(self, are_you_sure_about_this_flag: bool = False):
        """Drop the database, irreverisbly destroying it.

    Be careful with this! After calling this method an a Database instance, no
    further operations can be made on it, and any Sessions should be discarded.

    Args:
      are_you_sure_about_this_flag: You should be sure.

    Raises:
      ValueError: In case you're not 100% sure.
    """
        if not are_you_sure_about_this_flag:
            raise ValueError("Let's take a minute to think things over")

        if self.url.startswith("mysql://"):
            engine = sql.create_engine("/".join(self.url.split("/")[:-1]))
            database = self.url.split("/")[-1].split("?")[0]
            logging.Log(logging.GetCallingModuleName(), 1, "database %s",
                        database)
            engine.execute(f"DROP DATABASE IF EXISTS `{database}`")
        elif self.url == "sqlite://":
            # In-memory databases do not dropping.
            pass
        elif self.url.startswith("sqlite:///"):
            path = pathlib.Path(self.url[len("sqlite:///"):])
            assert path.is_file()
            path.unlink()
        else:
            raise NotImplementedError(
                f"Unsupported operation DROP for database: '{self.url}'", )
예제 #2
0
def ResilientAddManyAndCommit(db: Database, mapped: typing.Iterable[Base]):
    """Attempt to commit all mapped objects and return those that fail.

  This method creates a session and commits the given mapped objects.
  In case of error, this method will recurse up to O(log(n)) times, committing
  as many objects that can be as possible.

  Args:
    db: The database to add the objects to.
    mapped: A sequence of objects to commit.

  Returns:
    Any items in `mapped` which could not be committed, if any. Relative order
    of items is preserved.
  """
    failures = []

    if not mapped:
        return failures

    mapped = list(mapped)
    try:
        with db.Session(commit=True) as session:
            session.add_all(mapped)
    except sql.exc.SQLAlchemyError as e:
        logging.Log(
            logging.GetCallingModuleName(),
            1,
            "Caught error while committing %d mapped objects: %s",
            len(mapped),
            e,
        )

        # Divide and conquer. If we're committing only a single object, then a
        # failure to commit it means that we can do nothing other than return it.
        # Else, divide the mapped objects in half and attempt to commit as many of
        # them as possible.
        if len(mapped) == 1:
            return mapped
        else:
            mid = int(len(mapped) / 2)
            left = mapped[:mid]
            right = mapped[mid:]
            failures += ResilientAddManyAndCommit(db, left)
            failures += ResilientAddManyAndCommit(db, right)

    return failures
예제 #3
0
def Log(level: int, msg, *args, **kwargs):
    """Logs a message at the given level.

  Per-module verbose level. The argument has to contain a comma-separated
  list of <module name>=<log level>. <module name> is a glob pattern (e.g., "
    "gfs* for all modules whose name starts with \"gfs\"), matched against the "
    "filename base (that is, name ignoring .py). <log level> overrides any "
    "value given by --v."
  """
    logging.Log(
        logging.GetCallingModuleName(),
        level,
        _MaybeColorizeLog(
            shell.ShellEscapeCodes.YELLOW
            if level > 1 else shell.ShellEscapeCodes.CYAN,
            msg,
            *args,
        ),
        **kwargs,
    )
예제 #4
0
def GetOrAdd(
    session: sql.orm.session.Session,
    model,
    defaults: typing.Dict[str, object] = None,
    **kwargs,
):
    """Instantiate a mapped database object.

  If the object is not in the database,
  add it. Note that no change is written to disk until commit() is called on the
  session.

  Args:
    session: The database session.
    model: The database table class.
    defaults: Default values for mapped objects.
    kwargs: The values for the table row.

  Returns:
    An instance of the model class, with the values specified.
  """
    instance = session.query(model).filter_by(**kwargs).first()
    if not instance:
        params = {
            k: v
            for k, v in kwargs.items()
            if not isinstance(v, sql.sql.expression.ClauseElement)
        }
        params.update(defaults or {})
        instance = model(**params)
        session.add(instance)
        logging.Log(
            logging.GetCallingModuleName(),
            5,
            "New record: %s(%s)",
            model.__name__,
            params,
        )
    return instance
예제 #5
0
def GetVerbosity() -> int:
    """Get the verbosity level.

  This can be set per-module using --vmodule flag.
  """
    return logging.GetModuleVerbosity(logging.GetCallingModuleName())