.table_names and .tables properties plus expanded docs

This commit is contained in:
Simon Willison 2018-07-31 17:35:36 -07:00
commit 515d362ad6
5 changed files with 54 additions and 11 deletions

View file

@ -1,8 +1,8 @@
======= ======================
Table Databases and Tables
======= ======================
Tables are accessed using the indexing operator, like so: Database objects are constructed by passing in a SQLite3 database connection:
.. code-block:: python .. code-block:: python
@ -10,10 +10,28 @@ Tables are accessed using the indexing operator, like so:
import sqlite3 import sqlite3
db = Database(sqlite3.connect("my_database.db")) db = Database(sqlite3.connect("my_database.db"))
Tables are accessed using the indexing operator, like so:
.. code-block:: python
table = db["my_table"] table = db["my_table"]
If the table does not yet exist, it will be created the first time you attempt to insert or upsert data into it. If the table does not yet exist, it will be created the first time you attempt to insert or upsert data into it.
Listing tables
==============
You can list the names of tables in a database using the ``.table_names`` property::
>>> db.table_names
['dogs']
You can also iterate through the table objects themselves using ``.tables``::
>>> db.tables
[<Table dogs>]
Creating tables Creating tables
=============== ===============

View file

@ -20,8 +20,11 @@ class Database:
def __getitem__(self, table_name): def __getitem__(self, table_name):
return Table(self, table_name) return Table(self, table_name)
def __repr__(self):
return "<Database {}>".format(self.conn)
@property @property
def tables(self): def table_names(self):
return [ return [
r[0] r[0]
for r in self.conn.execute( for r in self.conn.execute(
@ -29,6 +32,10 @@ class Database:
).fetchall() ).fetchall()
] ]
@property
def tables(self):
return [self[name] for name in self.table_names]
def create_table(self, name, columns, pk=None, foreign_keys=None): def create_table(self, name, columns, pk=None, foreign_keys=None):
foreign_keys = foreign_keys or [] foreign_keys = foreign_keys or []
foreign_keys_by_name = {fk[0]: fk for fk in foreign_keys} foreign_keys_by_name = {fk[0]: fk for fk in foreign_keys}
@ -69,7 +76,12 @@ class Table:
def __init__(self, db, name): def __init__(self, db, name):
self.db = db self.db = db
self.name = name self.name = name
self.exists = self.name in self.db.tables self.exists = self.name in self.db.table_names
def __repr__(self):
return "<Table {}{}>".format(
self.name, " (does not exist yet)" if not self.exists else ""
)
@property @property
def count(self): def count(self):

View file

@ -4,12 +4,12 @@ import json
def test_create_table(fresh_db): def test_create_table(fresh_db):
assert [] == fresh_db.tables assert [] == fresh_db.table_names
table = fresh_db.create_table( table = fresh_db.create_table(
"test_table", "test_table",
{"text_col": str, "float_col": float, "int_col": int, "bool_col": bool}, {"text_col": str, "float_col": float, "int_col": int, "bool_col": bool},
) )
assert ["test_table"] == fresh_db.tables assert ["test_table"] == fresh_db.table_names
assert [ assert [
{"name": "text_col", "type": "TEXT"}, {"name": "text_col", "type": "TEXT"},
{"name": "float_col", "type": "FLOAT"}, {"name": "float_col", "type": "FLOAT"},
@ -29,7 +29,7 @@ def test_create_table(fresh_db):
) )
def test_create_table_from_example(fresh_db, example, expected_columns): def test_create_table_from_example(fresh_db, example, expected_columns):
fresh_db["people"].insert(example) fresh_db["people"].insert(example)
assert ["people"] == fresh_db.tables assert ["people"] == fresh_db.table_names
assert expected_columns == [ assert expected_columns == [
{"name": col.name, "type": col.type} for col in fresh_db["people"].columns {"name": col.name, "type": col.type} for col in fresh_db["people"].columns
] ]

View file

@ -10,7 +10,7 @@ search_records = [
def test_enable_fts(fresh_db): def test_enable_fts(fresh_db):
table = fresh_db["searchable"] table = fresh_db["searchable"]
table.insert_all(search_records) table.insert_all(search_records)
assert ["searchable"] == fresh_db.tables assert ["searchable"] == fresh_db.table_names
table.enable_fts(["text", "country"]) table.enable_fts(["text", "country"])
assert [ assert [
"searchable", "searchable",
@ -19,7 +19,7 @@ def test_enable_fts(fresh_db):
"searchable_fts_segdir", "searchable_fts_segdir",
"searchable_fts_docsize", "searchable_fts_docsize",
"searchable_fts_stat", "searchable_fts_stat",
] == fresh_db.tables ] == fresh_db.table_names
assert [("tanuki are tricksters", "Japan", "foo")] == table.search("tanuki") assert [("tanuki are tricksters", "Japan", "foo")] == table.search("tanuki")
assert [("racoons are trash pandas", "USA", "bar")] == table.search("usa") assert [("racoons are trash pandas", "USA", "bar")] == table.search("usa")
assert [] == table.search("bar") assert [] == table.search("bar")

View file

@ -1,6 +1,15 @@
from .fixtures import existing_db from .fixtures import existing_db
def test_table_names(existing_db):
assert ["foo"] == existing_db.table_names
def test_tables(existing_db):
assert 1 == len(existing_db.tables)
assert "foo" == existing_db.tables[0].name
def test_count(existing_db): def test_count(existing_db):
assert 3 == existing_db["foo"].count assert 3 == existing_db["foo"].count
@ -14,3 +23,7 @@ def test_columns(existing_db):
def test_schema(existing_db): def test_schema(existing_db):
assert "CREATE TABLE foo (text TEXT)" == existing_db["foo"].schema assert "CREATE TABLE foo (text TEXT)" == existing_db["foo"].schema
def test_table_repr(existing_db):
assert "<Table foo>" == repr(existing_db["foo"])