ExtractPropertiesToSQLite - add typing for created columns

This commit is contained in:
Andrej730
2026-03-04 17:57:34 +05:00
parent adaf33b74f
commit ecc82a52f5
2 changed files with 65 additions and 30 deletions
@@ -2287,6 +2287,11 @@ class QueryLinkedElement(bpy.types.Operator):
region_2d_to_origin_3d, region_2d_to_origin_3d,
region_2d_to_vector_3d, region_2d_to_vector_3d,
) )
from ifcpatch.recipes.ExtractPropertiesToSQLite import (
ElementRow,
PropertyRow,
RelationshipRow,
)
LinksData.linked_data = {} LinksData.linked_data = {}
props = tool.Project.get_project_props() props = tool.Project.get_project_props()
@@ -2352,7 +2357,7 @@ class QueryLinkedElement(bpy.types.Operator):
self.c = self.db.cursor() self.c = self.db.cursor()
self.c.execute(f"SELECT * FROM elements WHERE global_id = '{guid}' LIMIT 1") self.c.execute(f"SELECT * FROM elements WHERE global_id = '{guid}' LIMIT 1")
element = self.c.fetchone() element = ElementRow(*self.c.fetchone())
attributes: dict[str, Any] = {} attributes: dict[str, Any] = {}
for i, attr in enumerate(["GlobalId", "IFC Class", "Predefined Type", "Name", "Description"]): for i, attr in enumerate(["GlobalId", "IFC Class", "Predefined Type", "Name", "Description"]):
@@ -2360,14 +2365,14 @@ class QueryLinkedElement(bpy.types.Operator):
attributes[attr] = element[i + 1] attributes[attr] = element[i + 1]
self.c.execute("SELECT * FROM properties WHERE element_id = ?", (element[0],)) self.c.execute("SELECT * FROM properties WHERE element_id = ?", (element[0],))
rows = self.c.fetchall() rows = [PropertyRow(*row) for row in self.c.fetchall()]
properties = {} properties: defaultdict[str, dict[str, str]] = defaultdict(dict)
for row in rows: for row in rows:
properties.setdefault(row[1], {})[row[2]] = row[3] properties[row.pset_name][row.name] = row.value
self.c.execute("SELECT * FROM relationships WHERE from_id = ?", (element[0],)) self.c.execute("SELECT * FROM relationships WHERE from_id = ?", (element[0],))
relationships = self.c.fetchall() relationships = [RelationshipRow(*row) for row in self.c.fetchall()]
relating_type_id = None relating_type_id = None
@@ -2375,12 +2380,12 @@ class QueryLinkedElement(bpy.types.Operator):
if relationship[1] == "IfcRelDefinesByType": if relationship[1] == "IfcRelDefinesByType":
relating_type_id = relationship[2] relating_type_id = relationship[2]
type_properties = {} type_properties: defaultdict[str, dict[str, str]] = defaultdict(dict)
if relating_type_id is not None: if relating_type_id is not None:
self.c.execute("SELECT * FROM properties WHERE element_id = ?", (relating_type_id,)) self.c.execute("SELECT * FROM properties WHERE element_id = ?", (relating_type_id,))
rows = self.c.fetchall() rows = [PropertyRow(*row) for row in self.c.fetchall()]
for row in rows: for row in rows:
type_properties.setdefault(row[1], {})[row[2]] = row[3] type_properties[row.pset_name][row.name] = row.value
LinksData.linked_data = { LinksData.linked_data = {
"attributes": attributes, "attributes": attributes,
@@ -19,17 +19,40 @@
import logging import logging
import tempfile import tempfile
from typing import NamedTuple
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcpatch import ifcpatch
try: try:
import sqlite3 import sqlite3 # noqa: F401
except: except:
print("No SQLite support") print("No SQLite support")
class ElementRow(NamedTuple):
element_id: int
guid: str
class_: str
predefined_type: str | None
name: str | None
description: str | None
class PropertyRow(NamedTuple):
element_id: int
pset_name: str
name: str
value: str
class RelationshipRow(NamedTuple):
element_id: int
rel_ifc_class: str
to_id: int
class Patcher(ifcpatch.BasePatcher): class Patcher(ifcpatch.BasePatcher):
def __init__( def __init__(
self, self,
@@ -94,20 +117,21 @@ class Patcher(ifcpatch.BasePatcher):
elements = self.file.by_type("IfcObjectDefinition") elements = self.file.by_type("IfcObjectDefinition")
rows = [] rows: list[ElementRow] = []
properties = [] properties: list[PropertyRow] = []
relationships = [] relationships: list[RelationshipRow] = []
id_map = {e.id(): i for i, e in enumerate(elements)} id_map = {e.id(): i for i, e in enumerate(elements)}
for i, element in enumerate(elements): for i, element in enumerate(elements):
rows.append( rows.append(
[ ElementRow(
i, i,
element[0], # IfcRoot.GlobalId element[0], # IfcRoot.GlobalId
element.is_a(), element.is_a(),
ifcopenshell.util.element.get_predefined_type(element), ifcopenshell.util.element.get_predefined_type(element),
element[2], # IfcRoot.Name element[2], # IfcRoot.Name
element[3], # IfcRoot.Description element[3], # IfcRoot.Description
] )
) )
psets = ifcopenshell.util.element.get_psets(element, should_inherit=False) psets = ifcopenshell.util.element.get_psets(element, should_inherit=False)
for pset_name, pset_data in psets.items(): for pset_name, pset_data in psets.items():
@@ -118,49 +142,55 @@ class Patcher(ifcpatch.BasePatcher):
value = "True" if value else "False" value = "True" if value else "False"
elif not isinstance(value, str): elif not isinstance(value, str):
value = str(value) value = str(value)
properties.append([i, pset_name, prop_name, value]) properties.append(PropertyRow(i, pset_name, prop_name, value))
material = ifcopenshell.util.element.get_material(element, should_skip_usage=True) material = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
if material: if material:
name = getattr(material, "Name", getattr(material, "LayerSetName", None)) or "Unnamed" name = getattr(material, "Name", getattr(material, "LayerSetName", None)) or "Unnamed"
properties.append([i, "IFC Material", "Name", name]) properties.append(PropertyRow(i, "IFC Material", "Name", name))
properties.append([i, "IFC Material", "Class", material.is_a()]) properties.append(PropertyRow(i, "IFC Material", "Class", material.is_a()))
if material.is_a("IfcMaterial"): if material.is_a("IfcMaterial"):
materials = [] materials = []
elif material.is_a("IfcMaterialLayerSet"): elif material.is_a("IfcMaterialLayerSet"):
for idx, item in enumerate(material.MaterialLayers or []): for idx, item in enumerate(material.MaterialLayers or []):
material = item.Material material = item.Material
properties.append([i, "IFC Material", f"Layer {idx + 1} Name", getattr(item, "Name", None)]) properties.append(
properties.append([i, "IFC Material", f"Layer {idx + 1} Material", material.Name]) PropertyRow(i, "IFC Material", f"Layer {idx + 1} Name", getattr(item, "Name", None))
)
properties.append(PropertyRow(i, "IFC Material", f"Layer {idx + 1} Material", material.Name))
if category := getattr(material, "Category", None): if category := getattr(material, "Category", None):
properties.append([i, "IFC Material", f"Layer {idx + 1} Category", category]) properties.append(PropertyRow(i, "IFC Material", f"Layer {idx + 1} Category", category))
elif material.is_a("IfcMaterialProfileSet"): elif material.is_a("IfcMaterialProfileSet"):
for idx, item in enumerate(material.MaterialProfiles or []): for idx, item in enumerate(material.MaterialProfiles or []):
material = item.Material material = item.Material
properties.append([i, "IFC Material", f"Profile {idx + 1} Name", item.Name]) properties.append(PropertyRow(i, "IFC Material", f"Profile {idx + 1} Name", item.Name))
properties.append([i, "IFC Material", f"Profile {idx + 1} Material", material.Name]) properties.append(PropertyRow(i, "IFC Material", f"Profile {idx + 1} Material", material.Name))
if category := getattr(material, "Category", None): if category := getattr(material, "Category", None):
properties.append([i, "IFC Material", f"Profile {idx + 1} Category", category]) properties.append(PropertyRow(i, "IFC Material", f"Profile {idx + 1} Category", category))
elif material.is_a("IfcMaterialConstituentSet"): elif material.is_a("IfcMaterialConstituentSet"):
for idx, item in enumerate(material.MaterialConstituents or []): for idx, item in enumerate(material.MaterialConstituents or []):
material = item.Material material = item.Material
properties.append([i, "IFC Material", f"Constituent {idx + 1} Name", item.Name]) properties.append(PropertyRow(i, "IFC Material", f"Constituent {idx + 1} Name", item.Name))
properties.append([i, "IFC Material", f"Constituent {idx + 1} Material", material.Name]) properties.append(
PropertyRow(i, "IFC Material", f"Constituent {idx + 1} Material", material.Name)
)
if category := getattr(material, "Category", None): if category := getattr(material, "Category", None):
properties.append([i, "IFC Material", f"Constituent {idx + 1} Category", category]) properties.append(
PropertyRow(i, "IFC Material", f"Constituent {idx + 1} Category", category)
)
elif material.is_a("IfcMaterialList"): elif material.is_a("IfcMaterialList"):
for idx, material in enumerate(material.Materials): for idx, material in enumerate(material.Materials):
properties.append([i, "IFC Material", f"Material {idx + 1} Name", material.Name]) properties.append(PropertyRow(i, "IFC Material", f"Material {idx + 1} Name", material.Name))
if category := getattr(material, "Category", None): if category := getattr(material, "Category", None):
properties.append([i, "IFC Material", f"Material {idx + 1} Category", category]) properties.append(PropertyRow(i, "IFC Material", f"Material {idx + 1} Category", category))
layers = ifcopenshell.util.element.get_layers(self.file, element) layers = ifcopenshell.util.element.get_layers(self.file, element)
for idx, layer in enumerate(layers): for idx, layer in enumerate(layers):
properties.append([i, "IFC Presentation Layer Assignment", f"Layer {idx + 1}", layer.Name]) properties.append(PropertyRow(i, "IFC Presentation Layer Assignment", f"Layer {idx + 1}", layer.Name))
relating_type = ifcopenshell.util.element.get_type(element) relating_type = ifcopenshell.util.element.get_type(element)
if relating_type and relating_type != element: if relating_type and relating_type != element:
relationships.append([i, "IfcRelDefinesByType", id_map[relating_type.id()]]) relationships.append(RelationshipRow(i, "IfcRelDefinesByType", id_map[relating_type.id()]))
self.c.executemany("INSERT INTO elements VALUES (?, ?, ?, ?, ?, ?);", rows) self.c.executemany("INSERT INTO elements VALUES (?, ?, ?, ?, ?, ?);", rows)
self.c.executemany("INSERT INTO properties VALUES (?, ?, ?, ?);", properties) self.c.executemany("INSERT INTO properties VALUES (?, ?, ?, ?);", properties)