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 NAMEasqueel check [TARGET]asqueel shell [TARGET]asqueel db plan [TARGET],asqueel db apply [TARGET]python -m asqueelruns 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.pyof 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;checknever connects db plan/db applycallmigration_plan()/migrate()with the same four options
Next: "Lesson 32 — Integration in a host application".