Skip to content

Commit dbf75f4

Browse files
Add initial project structure and implementation for json2sqlite tool
1 parent 32a8dff commit dbf75f4

File tree

7 files changed

+178
-1
lines changed

7 files changed

+178
-1
lines changed

README.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,53 @@
1-
# json2sqlite
1+
# json2sqlite 🚀
2+
3+
## Description 📄
4+
`json2sqlite` is a tool that allows importing data from a JSON file into an SQLite database. This project is useful for anyone who wants to transfer structured data from a JSON format to a relational database quickly and easily.
5+
6+
## Project Structure 📁
7+
The project structure is as follows:
8+
```
9+
json2sqlite/
10+
│-- data/
11+
│ ├── data.json # JSON file to be imported (to be placed manually in this directory)
12+
│-- src/
13+
│ ├── __init__.py # Module initialization file
14+
│ ├── config.py # Database and JSON file configuration
15+
│ ├── json_reader.py # Module for reading the JSON file
16+
│ ├── logger.py # Module for log management
17+
│ ├── main.py # Main script for data import
18+
│ ├── sqlite_handler.py # Module for SQLite database management
19+
│-- README.md # Project documentation
20+
```
21+
22+
## Requirements 📋
23+
- Python 3.x
24+
- Python modules: `sqlite3`, `json`, `logging`
25+
26+
## Installation 💻
27+
1. Clone the repository:
28+
```sh
29+
git clone https://github.com/stefanopaolonii/json2sqlite.git
30+
cd json2sqlite
31+
```
32+
33+
## Configuration ⚙️
34+
Edit the `config.py` file to specify:
35+
- The path to the JSON file (which must be placed in the `data/` directory)
36+
- The name of the SQLite database
37+
- The name of the table
38+
39+
Example configuration:
40+
```python
41+
DB_FILE = 'database.sqlite'
42+
TABLE_NAME = 'my_table'
43+
JSON_FILE = 'data/data.json'
44+
```
45+
46+
## Usage ▶️
47+
To run the script and import the JSON data into the SQLite database, execute the following command:
48+
```sh
49+
python -m src.main
50+
```
51+
52+
## License 📜
53+
This project is distributed under the MIT license. See the `LICENSE` file for more details.

src/__init__.py

Whitespace-only changes.

src/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
DB_FILE= 'database.sqlite'
2+
TABLE_NAME='my_table'
3+
JSON_FILE='data/data.json'

src/json_reader.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import json
2+
from src.logger import logger
3+
4+
def load_json(file_path):
5+
try:
6+
with open(file_path, 'r') as file:
7+
data = json.load(file)
8+
logger.info(f'Loaded JSON file from {file_path}')
9+
return data
10+
except FileNotFoundError:
11+
logger.error(f'File not found: {file_path}')
12+
except json.JSONDecodeError:
13+
logger.error(f'Invalid JSON file: {file_path}')
14+
except Exception as e:
15+
logger.error(f'Error loading JSON file: {file_path}')
16+
raise

src/logger.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import logging
2+
3+
def setup_logger():
4+
logger = logging.getLogger('json_to_sqlite')
5+
logger.setLevel(logging.DEBUG)
6+
7+
console_handler = logging.StreamHandler()
8+
console_handler.setLevel(logging.INFO)
9+
10+
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
11+
console_handler.setFormatter(formatter)
12+
13+
logger.addHandler(console_handler)
14+
15+
return logger
16+
17+
logger = setup_logger()

src/main.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from src.config import DB_FILE, JSON_FILE, TABLE_NAME
2+
from src.json_reader import load_json
3+
from src.sqlite_handler import create_table, insert_data, connect_db
4+
from src.logger import logger
5+
6+
def json_to_sqlite():
7+
try:
8+
data = load_json(JSON_FILE)
9+
10+
if not data:
11+
logger.warning("The JSON file is empty!")
12+
return
13+
14+
with connect_db(DB_FILE) as conn:
15+
columns = data[0].keys()
16+
create_table(conn, TABLE_NAME, columns)
17+
18+
insert_data(conn, TABLE_NAME, data)
19+
20+
logger.info(f"Data from the JSON file has been inserted into the database {DB_FILE}")
21+
22+
except Exception as e:
23+
logger.error(f"An error occurred: {e}")
24+
25+
if __name__ == "__main__":
26+
json_to_sqlite()

src/sqlite_handler.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import sqlite3
2+
import json
3+
from typing import Any, Dict, List, Optional
4+
from src.logger import logger
5+
6+
def infer_column_type(value: Any) -> str:
7+
type_mapping = {
8+
type(None): "NULL",
9+
int: "INTEGER",
10+
float: "REAL",
11+
bool: "INTEGER",
12+
str: "TEXT",
13+
list: "TEXT",
14+
dict: "TEXT"
15+
}
16+
return type_mapping.get(type(value), "TEXT")
17+
18+
def create_table(conn: sqlite3.Connection, table_name: str, columns: List[str]) -> None:
19+
column_definitions = [
20+
f"{col} {infer_column_type(None)}" for col in columns
21+
]
22+
columns_str = ', '.join(column_definitions)
23+
create_table_query = f"CREATE TABLE IF NOT EXISTS {table_name} ({columns_str});"
24+
25+
try:
26+
with conn:
27+
conn.execute(create_table_query)
28+
logger.info(f"Table '{table_name}' created successfully with correct data types.")
29+
except sqlite3.DatabaseError as e:
30+
logger.error(f"Error creating table '{table_name}': {e}")
31+
32+
def insert_data(conn: sqlite3.Connection, table_name: str, data: List[Dict[str, Any]]) -> None:
33+
if not data:
34+
logger.warning("No data provided for insertion.")
35+
return
36+
37+
columns = data[0].keys()
38+
columns_str = ', '.join(columns)
39+
placeholders = ', '.join(['?'] * len(columns))
40+
insert_query = f"INSERT INTO {table_name} ({columns_str}) VALUES ({placeholders})"
41+
42+
try:
43+
with conn:
44+
for row in data:
45+
row_values = [
46+
json.dumps(value) if isinstance(value, (dict, list)) else value
47+
for value in row.values()
48+
]
49+
conn.execute(insert_query, tuple(row_values))
50+
logger.info(f"{len(data)} records successfully inserted into table '{table_name}'.")
51+
except sqlite3.IntegrityError as e:
52+
logger.error(f"Integrity error inserting into table '{table_name}': {e}")
53+
except sqlite3.DatabaseError as e:
54+
logger.error(f"Database error inserting data into table '{table_name}': {e}")
55+
56+
def connect_db(db_file: str) -> Optional[sqlite3.Connection]:
57+
try:
58+
conn = sqlite3.connect(db_file)
59+
logger.info(f"Connected to database '{db_file}' successfully.")
60+
return conn
61+
except sqlite3.Error as e:
62+
logger.error(f"Error connecting to database '{db_file}': {e}")
63+
return None

0 commit comments

Comments
 (0)