Course / Transactions & operations / Lesson 31

Lesson 31 · Transactions & operations

The command line

Register a configuration folder, validate it, plan and apply migrations, and open a console from the terminal.

about 8 minutes · screenplay estimate9 scenesPrerequisites: lessons 2, 27, 30

Development course · Reading edition · API compatibility

Scene 01

Commands

The package installs a command named asqueel. python dash m asqueel runs the same entry point. Three commands manage a local registry of configuration folders. check validates a configuration without connecting. shell opens a Python console with the database ready. db plan and db apply run the migrations of lesson 30.

Example & screen notes

Slide "asqueel". Bullets:

  • asqueel register NAME FOLDER, asqueel list, asqueel unregister NAME
  • asqueel check [TARGET]
  • asqueel shell [TARGET]
  • asqueel db plan [TARGET], asqueel db apply [TARGET]
  • python -m asqueel runs the same entry point

Scene 02

A configuration folder

A configuration folder contains a file named configure dot py. That file defines exactly one subclass of SqlDatabaseConfig. An imported recipe does not count, so this file subclasses the course recipe. The recipe uses absolute imports. Python package roots that contain the recipe are made importable while it loads. Other modules must already be importable. Here PYTHONPATH points to the folder of the course model. The course recipe reads its DSN from the variable ASQUEEL_DSN, through EnvResolver.

Example & screen notes

Folder tree, then the file.

05-operations/demo/
└── configure.py
"""CLI folder of the course model: the invoicing module must be importable."""
from invoicing import Invoicing


class Configuration(Invoicing):
    """The course recipe, as the single configuration of this folder."""

Terminal line:

export PYTHONPATH=$PWD/temp/course/course_model
export ASQUEEL_DSN="host=127.0.0.1 user=postgres dbname=asqueel_course_p5_cli"

Scene 03

The registry

register stores a card under a name. The card is a JSON file in the folder databases of the asqueel home. The home is tilde slash dot asqueel, or the value of ASQUEEL_HOME. The card holds the absolute path of the folder and nothing else. No configuration value and no credential is copied. register refuses a name that already exists. list prints each name with its folder. A name uses letters, digits, underscores and hyphens.

Example & screen notes

Terminal session.

$ export ASQUEEL_HOME=/tmp/course-home
$ asqueel register course temp/course/05-operations/demo
Registered course.
$ asqueel register course temp/course/05-operations/demo
Error: course is already registered; unregister it before replacing it
$ asqueel list
course  /…/temp/course/05-operations/demo
$ cat $ASQUEEL_HOME/databases/course.json
{
  "folder": "/…/temp/course/05-operations/demo"
}

Scene 04

Targets and check

Every command after the registry commands takes a target. A bare name means a registered card. A path with a slash means a folder or a recipe file. Write dot slash before a relative folder, because a bare name is always a card. module colon Class names an importable recipe class. Without a target, the command reads configure dot py in the current folder. dash dash config is an alternative to the positional target, and you cannot give both. check builds the model and reads the connection settings, including the resolvers. It does not connect to the database.

Example & screen notes

Terminal session.

$ asqueel check course
Configuration valid: 9 tables.
$ asqueel check ./temp/course/05-operations/demo
Configuration valid: 9 tables.
$ asqueel check --config temp/course/course_model/invoicing.py
Configuration valid: 9 tables.
$ asqueel check --config invoicing:Invoicing
Configuration valid: 9 tables.
$ asqueel check course --config invoicing:Invoicing
Error: Choose either a target or --config
$ asqueel check nothere
Error: Unknown registered database: nothere

Bullets:

  • A bare name: a registered card
  • A path with /: a folder or a recipe file
  • module:Class: an importable recipe class
  • No target: configure.py of the current folder

Scene 05

db plan and db apply

db plan calls db dot migration_plan and prints the commands. It changes nothing. db apply calls db dot migrate. It computes a fresh plan, applies it, prints it, and compares again. It never replays a plan printed earlier. Warnings go to standard error, each prefixed with Warning. An empty plan prints No changes.

Example & screen notes

Terminal session, the last lines of each output.

$ asqueel db plan course
CREATE DATABASE "asqueel_course_p5_cli" ENCODING 'UNICODE';
CREATE SCHEMA "invc";
CREATE TABLE "invc"."invc_region"(
…
$ asqueel db apply course
CREATE DATABASE "asqueel_course_p5_cli" ENCODING 'UNICODE';
…
 ADD CONSTRAINT "fk_d5b122fd" FOREIGN KEY ("invoice_id") REFERENCES "invc"."invc_invoice" ("id") ON UPDATE CASCADE;
Migration applied. No remaining commands under the selected removal policy.
$ asqueel db plan course
No changes.

Scene 06

Migration options

db plan and db apply accept four flags. Each flag passes one option of lesson 30. dash dash allow dash removals enables the supported removals, which are columns. dash dash no dash foreign dash keys creates no foreign key constraint. dash dash force converts filled columns, and values that do not convert become NULL. dash dash backup does the same and keeps the old values in a backup column. On an up-to-date database, every combination prints No changes.

Example & screen notes

Terminal session, then a two-column table.

$ asqueel db plan course --allow-removals --no-foreign-keys --force --backup
No changes.
Flag Python option
--allow-removals allow_removals=True
--no-foreign-keys foreignKeys=False
--force force=True
--backup backup=True

Scene 07

The console

shell opens the standard Python console with one variable, db. db is the AsqueelDb of the target. The rules of lesson 27 apply. Leaving the console with control D calls closeConnection, which rolls back. This insert was never committed, so the table is still empty after exit.

Example & screen notes

Terminal session. Then bullets.

$ asqueel shell course
Asqueel Python console: db is ready. Use db.commit() or db.rollback().
Leaving the console rolls back pending work and releases the connection.
>>> db.table('invc.region').insert({'code': 'NO', 'name': 'North'})
{'code': 'NO', 'name': 'North', '__ins_ts': datetime.datetime(…), …}
>>> db.table('invc.region').query().count()
1
>>> ^D
Connection released on console exit.
  • Leaving the console (end of input, Ctrl-D) calls db.closeConnection()
  • Nothing is committed on exit

Scene 08

Errors and exit codes

The exit code is zero on success. It is one when the operation fails, for example an unknown card or a migration error. It is two for a syntax error on the command line. It is one hundred thirty when you interrupt the command. For unexpected errors, the command prints only the exception type. It never prints the exception text, because driver messages can contain resolved credentials. A missing import prints a message about Python dependencies. unregister removes the card only. The folder and the database stay.

Example & screen notes

Terminal session, then a table.

$ asqueel frobnicate
usage: asqueel [-h] {register,list,unregister,check,shell,db} ...
asqueel: error: argument command: invalid choice: 'frobnicate' …
$ echo $?
2
$ asqueel unregister course
Unregistered course; project files and database unchanged.
Exit code Meaning
0 success
1 operation failed
2 command syntax error
130 interrupted

Scene 09

Recap

The registry stores only folder paths, under the asqueel home. A target is a card name, a path or a module and class, and check never connects. db plan and db apply call the same methods as Python, with the same four options. The next lesson places asqueel databases inside a host application.

Example & screen notes

Slide "Recap". Bullets:

  • The registry stores only folder paths under ASQUEEL_HOME/databases
  • A target is a card name, a path, or module:Class; check never connects
  • db plan / db apply call migration_plan() / migrate() with the same four options

Next: "Lesson 32 — Integration in a host application".