diff --git a/README.md b/README.md index 31188e7..f5f95a9 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,29 @@ Here's the relational schema of the `.warcdb` file. ![WarcDB Schema](schema.png) +### Views + +In addition to the core tables that map to the WARC record types there are also helper *views* that make it a bit easier to query data: + +#### v_request_http_header + +A view of HTTP headers in WARC request records: + +| Column Name | Column Type | Description | +| -------------- | ----------- | ---------------------------------------------------------------------- | +| warc_record_id | text | The WARC-Record-Id for the *request* record that it was extracted from. | +| name | text | The lowercased HTTP header name (e.g. content-type) | +| value | text | The HTTP header value (e.g. text/html) | + +#### v_response_http_header + +A view of HTTP headers in WARC response records: + +| Column Name | Column Type | Description | +| -------------- | ----------- | ---------------------------------------------------------------------- | +| warc_record_id | text | The WARC-Record-Id for the *response* record that it was extracted from. | +| name | text | The lowercased HTTP header name (e.g. content-type) | +| value | text | The HTTP header value (e.g. text/html) | ## Motivation diff --git a/tests/test_warcdb.py b/tests/test_warcdb.py index bc6b41c..5ba3dc0 100644 --- a/tests/test_warcdb.py +++ b/tests/test_warcdb.py @@ -64,3 +64,28 @@ def test_column_names(): assert re.match(r"^[a-z_]+", col.name), f"column {col.name} named correctly" os.remove(db_file) + + +def test_http_header(): + runner = CliRunner() + runner.invoke( + warcdb_cli, ["import", db_file, str(pathlib.Path("tests/google.warc"))] + ) + + db = sqlite_utils.Database(db_file) + + resp_headers = list(db["v_response_http_header"].rows) + assert len(resp_headers) == 43 + assert { + "name": "content-type", + "value": "text/html; charset=UTF-8", + "warc_record_id": "", + } in resp_headers + + req_headers = list(db["v_request_http_header"].rows) + assert len(req_headers) == 17 + assert { + "name": "user-agent", + "value": "Wget/1.21.3", + "warc_record_id": "", + } in req_headers diff --git a/warcdb/migrations.py b/warcdb/migrations.py index 64925ba..c17ce42 100644 --- a/warcdb/migrations.py +++ b/warcdb/migrations.py @@ -95,3 +95,27 @@ def m001_initial(db): ("warc_concurrent_to", "metadata", "warc_record_id"), ], ) + + +@migration() +def m002_headers(db): + db.create_view( + "v_request_http_header", + """ + SELECT + request.warc_record_id AS warc_record_id, + LOWER(JSON_EXTRACT(header.VALUE, '$.header')) AS name, + JSON_EXTRACT(header.VALUE, '$.value') AS value + FROM request, JSON_EACH(request.http_headers) AS header + """, + ) + db.create_view( + "v_response_http_header", + """ + SELECT + response.warc_record_id AS warc_record_id, + LOWER(JSON_EXTRACT(header.VALUE, '$.header')) AS name, + JSON_EXTRACT(header.VALUE, '$.value') AS value + FROM response, JSON_EACH(response.http_headers) AS header + """, + )