Skip to content

Commit

Permalink
table.virtual_table_using property, closes #196
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Nov 5, 2020
1 parent 43eae8b commit 59d8689
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 1 deletion.
6 changes: 6 additions & 0 deletions docs/python-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,12 @@ The ``detect_fts()`` method returns the associated SQLite FTS table name, if one
>> db["authors"].detect_fts()
"authors_fts"
The ``.virtual_table_using`` property reveals if a table is a virtual table. It returns ``None`` for regular tables and the upper case version of the type of virtual table otherwise. For example::
>> db["authors"].enable_fts(["name"])
>> db["authors_fts"].virtual_table_using
"FTS5"
.. _python_api_fts:
Enabling full-text search
Expand Down
28 changes: 28 additions & 0 deletions sqlite_utils/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,32 @@
import json
import os
import pathlib
import re
import sys
import textwrap
import uuid

SQLITE_MAX_VARS = 999

_virtual_table_using_re = re.compile(
r"""
^ # Start of string
\s*CREATE\s+VIRTUAL\s+TABLE\s+ # CREATE VIRTUAL TABLE
(
'(?P<squoted_table>[^']*(?:''[^']*)*)' | # single quoted name
"(?P<dquoted_table>[^"]*(?:""[^"]*)*)" | # double quoted name
`(?P<backtick_table>[^`]+)` | # `backtick` quoted name
\[(?P<squarequoted_table>[^\]]+)\] | # [...] quoted name
(?P<identifier> # SQLite non-quoted identifier
[A-Za-z_\u0080-\uffff] # \u0080-\uffff = "any character larger than u007f"
[A-Za-z_\u0080-\uffff0-9\$]* # zero-or-more alphanemuric or $
)
)
\s+(IF\s+NOT\s+EXISTS\s+)? # IF NOT EXISTS (optional)
USING\s+(?P<using>\w+) # e.g. USING FTS5
""",
re.VERBOSE | re.IGNORECASE,
)

try:
import pandas as pd
Expand Down Expand Up @@ -676,6 +696,14 @@ def foreign_keys(self):
)
return fks

@property
def virtual_table_using(self):
"Returns type of virtual table or None if this is not a virtual table"
match = _virtual_table_using_re.match(self.schema)
if match is None:
return None
return match.groupdict()["using"].upper()

@property
def indexes(self):
sql = 'PRAGMA index_list("{}")'.format(self.name)
Expand Down
48 changes: 47 additions & 1 deletion tests/test_introspect.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sqlite_utils.db import Index, View
from sqlite_utils.db import Index, View, Database
import pytest


Expand Down Expand Up @@ -142,3 +142,49 @@ def test_triggers(fresh_db):
(t.name, t.table) for t in fresh_db["authors"].triggers
}
assert [] == fresh_db["other"].triggers


@pytest.mark.parametrize(
"sql,expected_name,expected_using",
[
(
"""
CREATE VIRTUAL TABLE foo USING FTS5(name)
""",
"foo",
"FTS5",
),
(
"""
CREATE VIRTUAL TABLE "foo" USING FTS4(name)
""",
"foo",
"FTS4",
),
(
"""
CREATE VIRTUAL TABLE IF NOT EXISTS `foo` USING FTS4(name)
""",
"foo",
"FTS4",
),
(
"""
CREATE VIRTUAL TABLE IF NOT EXISTS `foo` USING fts5(name)
""",
"foo",
"FTS5",
),
(
"""
CREATE TABLE IF NOT EXISTS `foo` (id integer primary key)
""",
"foo",
None,
),
],
)
def test_virtual_table_using(sql, expected_name, expected_using):
db = Database(memory=True)
db.execute(sql)
assert db[expected_name].virtual_table_using == expected_using

0 comments on commit 59d8689

Please sign in to comment.