json2sql-sql 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: json2sql-sql
3
+ Version: 0.1.2
4
+ Summary: Convert JSON data into SQL queries
5
+ Author: NaveenKumar
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Dynamic: requires-python
9
+
10
+ # json2sql
11
+
12
+ A simple Python library to convert JSON data into SQL queries.
13
+
14
+ ## Features
15
+
16
+ - Auto table creation
17
+ - Insert query generation
18
+ - Schema detection
19
+ - Nested JSON flattening
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install -r requirements.txt
@@ -0,0 +1,15 @@
1
+ # json2sql
2
+
3
+ A simple Python library to convert JSON data into SQL queries.
4
+
5
+ ## Features
6
+
7
+ - Auto table creation
8
+ - Insert query generation
9
+ - Schema detection
10
+ - Nested JSON flattening
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pip install -r requirements.txt
@@ -0,0 +1,3 @@
1
+ from .converter import Converter
2
+
3
+ __all__ = ["Converter"]
@@ -0,0 +1,80 @@
1
+ from typing import Any, Dict, List, Optional
2
+
3
+ from .loader import load_json, normalize_json_data
4
+ from .flattener import flatten_json
5
+ from .schema import detect_schema
6
+ from .generator import generate_create_table_query, generate_insert_queries
7
+ from .exporter import export_sql
8
+
9
+
10
+ class Converter:
11
+ """
12
+ Main class for converting JSON data into SQL queries.
13
+ """
14
+
15
+ def __init__(self, source: Any, flatten: bool = True, separator: str = "_") -> None:
16
+ """
17
+ source can be:
18
+ - file path to JSON
19
+ - dict
20
+ - list of dicts
21
+ """
22
+ self.source = source
23
+ self.flatten = flatten
24
+ self.separator = separator
25
+
26
+ self.records: List[Dict[str, Any]] = []
27
+ self.schema: Dict[str, str] = {}
28
+ self.table_name: Optional[str] = None
29
+ self.create_query: Optional[str] = None
30
+ self.insert_queries: List[str] = []
31
+
32
+ self._load_and_prepare()
33
+
34
+ def _load_and_prepare(self) -> None:
35
+ if isinstance(self.source, str):
36
+ raw_records = load_json(self.source)
37
+ else:
38
+ raw_records = normalize_json_data(self.source)
39
+
40
+ if self.flatten:
41
+ self.records = [flatten_json(record, sep=self.separator) for record in raw_records]
42
+ else:
43
+ self.records = raw_records
44
+
45
+ self.schema = detect_schema(self.records)
46
+
47
+ def create_table(self, table_name: str) -> str:
48
+ self.table_name = table_name
49
+ self.create_query = generate_create_table_query(table_name, self.schema)
50
+ return self.create_query
51
+
52
+ def insert_data(self, table_name: Optional[str] = None) -> List[str]:
53
+ if table_name:
54
+ self.table_name = table_name
55
+
56
+ if not self.table_name:
57
+ raise ValueError("Table name is not set. Call create_table(table_name) first.")
58
+
59
+ self.insert_queries = generate_insert_queries(self.table_name, self.records, self.schema)
60
+ return self.insert_queries
61
+
62
+ def convert(self, table_name: str) -> str:
63
+ """
64
+ Generate full SQL as a single string.
65
+ """
66
+ create_query = self.create_table(table_name)
67
+ insert_queries = self.insert_data()
68
+
69
+ sql_parts = [create_query, ""]
70
+ sql_parts.extend(insert_queries)
71
+ return "\n".join(sql_parts)
72
+
73
+ def export(self, output_path: str) -> None:
74
+ if not self.create_query:
75
+ raise ValueError("Create query not generated. Call create_table(table_name) first.")
76
+
77
+ if not self.insert_queries:
78
+ raise ValueError("Insert queries not generated. Call insert_data() first.")
79
+
80
+ export_sql(output_path, self.create_query, self.insert_queries)
@@ -0,0 +1,10 @@
1
+ class Json2SqlError(Exception):
2
+ """Base exception for json2sql library."""
3
+
4
+
5
+ class InvalidJsonError(Json2SqlError):
6
+ """Raised when JSON input is invalid."""
7
+
8
+
9
+ class SchemaDetectionError(Json2SqlError):
10
+ """Raised when schema detection fails."""
@@ -0,0 +1,11 @@
1
+ from typing import List
2
+
3
+
4
+ def export_sql(output_path: str, create_query: str, insert_queries: List[str]) -> None:
5
+ """
6
+ Export SQL queries to a .sql file.
7
+ """
8
+ with open(output_path, "w", encoding="utf-8") as file:
9
+ file.write(create_query + "\n\n")
10
+ for query in insert_queries:
11
+ file.write(query + "\n")
@@ -0,0 +1,31 @@
1
+ from typing import Any, Dict
2
+
3
+
4
+ def flatten_json(data: Dict[str, Any], parent_key: str = "", sep: str = "_") -> Dict[str, Any]:
5
+ """
6
+ Flatten nested JSON.
7
+ Example:
8
+ {
9
+ "id": 1,
10
+ "address": {"city": "Chennai"}
11
+ }
12
+ becomes:
13
+ {
14
+ "id": 1,
15
+ "address_city": "Chennai"
16
+ }
17
+ """
18
+ items: Dict[str, Any] = {}
19
+
20
+ for key, value in data.items():
21
+ new_key = f"{parent_key}{sep}{key}" if parent_key else key
22
+
23
+ if isinstance(value, dict):
24
+ items.update(flatten_json(value, new_key, sep))
25
+ elif isinstance(value, list):
26
+ # Store lists as JSON-like strings in first version
27
+ items[new_key] = str(value)
28
+ else:
29
+ items[new_key] = value
30
+
31
+ return items
@@ -0,0 +1,48 @@
1
+ from typing import Any, Dict, List
2
+
3
+ from .utils import sanitize_identifier, sql_escape
4
+
5
+
6
+ def generate_create_table_query(table_name: str, schema: Dict[str, str]) -> str:
7
+ """
8
+ Generate CREATE TABLE query.
9
+ """
10
+ safe_table = sanitize_identifier(table_name)
11
+
12
+ columns = []
13
+ for column_name, sql_type in schema.items():
14
+ safe_column = sanitize_identifier(column_name)
15
+ columns.append(f" {safe_column} {sql_type}")
16
+
17
+ columns_sql = ",\n".join(columns)
18
+
19
+ return f"CREATE TABLE {safe_table} (\n{columns_sql}\n);"
20
+
21
+
22
+ def generate_insert_queries(table_name: str, records: List[Dict[str, Any]], schema: Dict[str, str]) -> List[str]:
23
+ """
24
+ Generate INSERT INTO queries.
25
+ """
26
+ safe_table = sanitize_identifier(table_name)
27
+ ordered_columns = list(schema.keys())
28
+ queries: List[str] = []
29
+
30
+ for record in records:
31
+ values = []
32
+ for column in ordered_columns:
33
+ original_value = None
34
+
35
+ for key, value in record.items():
36
+ if sanitize_identifier(key) == column:
37
+ original_value = value
38
+ break
39
+
40
+ values.append(sql_escape(original_value))
41
+
42
+ columns_sql = ", ".join(ordered_columns)
43
+ values_sql = ", ".join(values)
44
+
45
+ query = f"INSERT INTO {safe_table} ({columns_sql}) VALUES ({values_sql});"
46
+ queries.append(query)
47
+
48
+ return queries
@@ -0,0 +1,38 @@
1
+ import json
2
+ from typing import Any, List, Dict
3
+
4
+ from .exceptions import InvalidJsonError
5
+
6
+
7
+ def load_json(source: str) -> List[Dict[str, Any]]:
8
+ """
9
+ Load JSON data from a file path.
10
+
11
+ Supported input:
12
+ - list of dictionaries
13
+ - single dictionary (converted to list with one item)
14
+ """
15
+ try:
16
+ with open(source, "r", encoding="utf-8") as file:
17
+ data = json.load(file)
18
+ except FileNotFoundError as exc:
19
+ raise InvalidJsonError(f"JSON file not found: {source}") from exc
20
+ except json.JSONDecodeError as exc:
21
+ raise InvalidJsonError(f"Invalid JSON format in file: {source}") from exc
22
+
23
+ return normalize_json_data(data)
24
+
25
+
26
+ def normalize_json_data(data: Any) -> List[Dict[str, Any]]:
27
+ """
28
+ Normalize JSON input into a list of dictionaries.
29
+ """
30
+ if isinstance(data, dict):
31
+ return [data]
32
+
33
+ if isinstance(data, list):
34
+ if all(isinstance(item, dict) for item in data):
35
+ return data
36
+ raise InvalidJsonError("JSON list must contain only objects/dictionaries.")
37
+
38
+ raise InvalidJsonError("JSON must be a dictionary or a list of dictionaries.")
@@ -0,0 +1,74 @@
1
+ from typing import Any, Dict, List
2
+
3
+ from .exceptions import SchemaDetectionError
4
+ from .utils import sanitize_identifier
5
+
6
+
7
+ def detect_sql_type(value: Any) -> str:
8
+ """
9
+ Detect SQL type from Python value.
10
+ """
11
+ if value is None:
12
+ return "TEXT"
13
+
14
+ if isinstance(value, bool):
15
+ return "BOOLEAN"
16
+
17
+ if isinstance(value, int) and not isinstance(value, bool):
18
+ return "INTEGER"
19
+
20
+ if isinstance(value, float):
21
+ return "REAL"
22
+
23
+ return "TEXT"
24
+
25
+
26
+ def merge_sql_types(type1: str, type2: str) -> str:
27
+ """
28
+ Merge conflicting SQL types into a safer common type.
29
+ """
30
+ priority = ["BOOLEAN", "INTEGER", "REAL", "TEXT"]
31
+
32
+ if type1 == type2:
33
+ return type1
34
+
35
+ # If either is TEXT, safest is TEXT
36
+ if "TEXT" in (type1, type2):
37
+ return "TEXT"
38
+
39
+ # INTEGER + REAL => REAL
40
+ if {"INTEGER", "REAL"} == {type1, type2}:
41
+ return "REAL"
42
+
43
+ # BOOLEAN mixed with anything else => TEXT
44
+ if "BOOLEAN" in (type1, type2):
45
+ return "TEXT"
46
+
47
+ return priority[max(priority.index(type1), priority.index(type2))]
48
+
49
+
50
+ def detect_schema(records: List[Dict[str, Any]]) -> Dict[str, str]:
51
+ """
52
+ Detect schema from list of flattened records.
53
+ Returns dict like:
54
+ {
55
+ "id": "INTEGER",
56
+ "name": "TEXT"
57
+ }
58
+ """
59
+ if not records:
60
+ raise SchemaDetectionError("No records found for schema detection.")
61
+
62
+ schema: Dict[str, str] = {}
63
+
64
+ for record in records:
65
+ for key, value in record.items():
66
+ safe_key = sanitize_identifier(key)
67
+ current_type = detect_sql_type(value)
68
+
69
+ if safe_key in schema:
70
+ schema[safe_key] = merge_sql_types(schema[safe_key], current_type)
71
+ else:
72
+ schema[safe_key] = current_type
73
+
74
+ return schema
@@ -0,0 +1,40 @@
1
+ import re
2
+ from typing import Any
3
+
4
+
5
+ def sanitize_identifier(name: str) -> str:
6
+ """
7
+ Convert any string into a safe SQL identifier.
8
+ Example: 'user name' -> 'user_name'
9
+ """
10
+ if not isinstance(name, str):
11
+ name = str(name)
12
+
13
+ name = name.strip().lower()
14
+ name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
15
+ name = re.sub(r"_+", "_", name)
16
+
17
+ if not name:
18
+ name = "column"
19
+
20
+ if name[0].isdigit():
21
+ name = f"col_{name}"
22
+
23
+ return name
24
+
25
+
26
+ def sql_escape(value: Any) -> str:
27
+ """
28
+ Escape Python values for SQL INSERT statements.
29
+ """
30
+ if value is None:
31
+ return "NULL"
32
+
33
+ if isinstance(value, bool):
34
+ return "TRUE" if value else "FALSE"
35
+
36
+ if isinstance(value, (int, float)):
37
+ return str(value)
38
+
39
+ value = str(value).replace("'", "''")
40
+ return f"'{value}'"
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: json2sql-sql
3
+ Version: 0.1.2
4
+ Summary: Convert JSON data into SQL queries
5
+ Author: NaveenKumar
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Dynamic: requires-python
9
+
10
+ # json2sql
11
+
12
+ A simple Python library to convert JSON data into SQL queries.
13
+
14
+ ## Features
15
+
16
+ - Auto table creation
17
+ - Insert query generation
18
+ - Schema detection
19
+ - Nested JSON flattening
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install -r requirements.txt
@@ -0,0 +1,18 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ json2sql-sql/__init__.py
5
+ json2sql-sql/converter.py
6
+ json2sql-sql/exceptions.py
7
+ json2sql-sql/exporter.py
8
+ json2sql-sql/flattener.py
9
+ json2sql-sql/generator.py
10
+ json2sql-sql/loader.py
11
+ json2sql-sql/schema.py
12
+ json2sql-sql/utils.py
13
+ json2sql_sql.egg-info/PKG-INFO
14
+ json2sql_sql.egg-info/SOURCES.txt
15
+ json2sql_sql.egg-info/dependency_links.txt
16
+ json2sql_sql.egg-info/top_level.txt
17
+ tests/__init__.py
18
+ tests/test_basic.py
@@ -0,0 +1,2 @@
1
+ json2sql-sql
2
+ tests
@@ -0,0 +1,14 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "json2sql-sql"
7
+ version = "0.1.2"
8
+ description = "Convert JSON data into SQL queries"
9
+ authors = [
10
+ { name = "NaveenKumar" }
11
+ ]
12
+ readme = "README.md"
13
+ requires-python = ">=3.9"
14
+ dependencies = []
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,11 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="json2sql-sql",
5
+ version="0.1.2",
6
+ description="Convert JSON data into SQL queries",
7
+ author="Your Name",
8
+ packages=find_packages(),
9
+ install_requires=[],
10
+ python_requires=">=3.8",
11
+ )
File without changes
@@ -0,0 +1,17 @@
1
+ from json2sql import Converter
2
+
3
+
4
+ def test_basic_conversion():
5
+ data = [
6
+ {"id": 1, "name": "Naveen", "address": {"city": "Chennai"}},
7
+ {"id": 2, "name": "Kumar", "address": {"city": "Madurai"}}
8
+ ]
9
+
10
+ converter = Converter(data)
11
+ sql = converter.convert("users")
12
+
13
+ assert "CREATE TABLE users" in sql
14
+ assert "id INTEGER" in sql
15
+ assert "name TEXT" in sql
16
+ assert "address_city TEXT" in sql
17
+ assert "INSERT INTO users" in sql