Tutorial
========
This tutorial will guide you through the basic usage of Nightingale, transforming flat data from an SQLite database into the OCDS format.
Setup
-----
1. **Prepare a Sample SQLite Database:**
Create a SQLite database and populate it with some sample data. Here’s an example script (`create_sample_data.py`) to create a sample database:
.. code-block:: python
import sqlite3
# Connect to the database (or create it if it doesn't exist)
conn = sqlite3.connect('sample_database.db')
cursor = conn.cursor()
# Create tables
cursor.execute('''
CREATE TABLE example_table (
id INTEGER PRIMARY KEY,
name TEXT,
value TEXT
)
''')
cursor.execute('''
CREATE TABLE party_table (
id INTEGER PRIMARY KEY,
name TEXT,
identifier TEXT,
role TEXT
)
''')
# Insert sample data into example_table
cursor.executemany('''
INSERT INTO example_table (name, value) VALUES (?, ?)
''', [
('sample1', 'value1'),
('sample2', 'value2'),
('sample3', 'value3'),
])
# Insert sample data into party_table
cursor.executemany('''
INSERT INTO party_table (name, identifier, role) VALUES (?, ?, ?)
''', [
('party1', 'id1', 'buyer'),
('party2', 'id2', 'supplier'),
('party3', 'id3', 'procuringEntity'),
])
# Commit and close
conn.commit()
conn.close()
Run the script to create `sample_database.db`.
2. **Create a Sample Configuration File:**
Create a `sample_config.toml` file with the following content:
.. code-block:: toml
[datasource]
connection = 'sample_database.db'
[mapping]
file = 'mapping.xlsx'
ocid_prefix = 'ocds-123abc'
force_publish = true
selector = '''
SELECT
example_table.id AS "example_table (id)",
example_table.name AS "example_table (name)",
example_table.value AS "example_table (value)",
party_table.name AS "party_table (name)",
party_table.identifier AS "party_table (identifier)",
party_table.role AS "party_table (role)"
FROM example_table
JOIN party_table ON example_table.id = party_table.id;
'''
[publishing]
publisher = 'Sample Publisher'
base_uri = 'https://example.com'
version = '1.1'
[output]
directory = 'output'
3. **Prepare the Mapping File:**
Use the following configuration for `mapping.xlsx` based on the `ocds field level mapping` template:
**General Sheet:**
.. code-block:: text
| Title | Description | Path | Status | Mapping | Comment
|---------------|---------------|------------------|----------|------------------------------------|--------
| OCID | unique ID | ocid | Required | example_table (id) | -
| Party ID | Party ID | parties/id | Optional | party_table (identifier) | -
| Party Name | Party Name | parties/name | Optional | party_table (name) | -
| Role | Role | parties/roles | Required | party_table (role) | -
**Tender Sheet:**
.. code-block:: text
id | Title | Description | Path | Status | Mapping | Comment
----|----------------|--------------|---------------------|----------|------------------------------------|--------
1 | Tender Title | Tender title | tender/title | Optional | example_table (name) | -
2 | Value | Tender value | tender/value/amount | Optional | example_table (value) | -
Running the Transformation
--------------------------
Run the transformation using the CLI:
.. code-block:: sh
ocdsnightingale --config sample_config.toml --package --loglevel DEBUG
This will produce an output file in the `output` directory.
Mapping Configuration
---------------------
Field-level mapping is specified in the `mapping.xlsx` file. It is formed from the standard `OCDS Field Level Mapping template `_.
For more information about how to fill the mapping file, refer to the `OCDS Field Level Mapping template guidance `_.
Here is a brief description of the columns from mapping sheets in the mapping file:
* **Path**: The path in the OCDS release schema where the field value should be placed.
* **Title**: A human-readable title for the field.
* **Description**: A description of what the field represents.
* **Mapping**: The field in the source data that maps to the OCDS path.
Understanding these mappings will help you configure the transformation correctly for your data.