ducpy 3.5.0__tar.gz → 3.6.0__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.
Files changed (64) hide show
  1. {ducpy-3.5.0 → ducpy-3.6.0}/Cargo.lock +1 -1
  2. ducpy-3.6.0/Cargo.toml +20 -0
  3. {ducpy-3.5.0 → ducpy-3.6.0}/PKG-INFO +6 -4
  4. {ducpy-3.5.0 → ducpy-3.6.0}/README.md +2 -2
  5. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducpy/crate/Cargo.toml +1 -1
  6. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/README.md +1 -1
  7. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/duc.sql +159 -13
  8. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/migrations/3000001_to_3000002.sql +1 -0
  9. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/migrations/3000002_to_3000003.sql +15 -0
  10. ducpy-3.6.0/packages/ducrs/schema/migrations/3000005_to_3000006.sql +42 -0
  11. ducpy-3.6.0/packages/ducrs/schema/migrations/3000006_to_3000007.sql +280 -0
  12. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/version_control.sql +1 -1
  13. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/api/version_control.rs +47 -29
  14. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/db/bootstrap.rs +35 -0
  15. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/parse.rs +476 -98
  16. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/serialize.rs +296 -34
  17. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/types.rs +152 -2
  18. {ducpy-3.5.0 → ducpy-3.6.0}/pyproject.toml +3 -1
  19. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/__init__.py +1 -1
  20. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/element_builders.py +8 -0
  21. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/sql_builder.py +15 -6
  22. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/state_builders.py +238 -9
  23. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/classes/DataStateClass.py +117 -4
  24. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/classes/ElementsClass.py +1 -0
  25. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/parse.py +2 -2
  26. ducpy-3.6.0/src/ducpy/search/image_ocr.py +189 -0
  27. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/search/search_elements.py +0 -6
  28. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/serialize.py +9 -1
  29. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/utils/io.py +7 -0
  30. ducpy-3.5.0/Cargo.toml +0 -7
  31. ducpy-3.5.0/src/ducpy/search/image_ocr.py +0 -79
  32. {ducpy-3.5.0 → ducpy-3.6.0}/LICENSE +0 -0
  33. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducpy/crate/src/lib.rs +0 -0
  34. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/Cargo.toml +0 -0
  35. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/LICENSE +0 -0
  36. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/build.rs +0 -0
  37. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/migrations/3000000_to_3000001.sql +0 -0
  38. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/migrations/3000003_to_3000004.sql +0 -0
  39. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/migrations/3000004_to_3000005.sql +0 -0
  40. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/schema/search.sql +0 -0
  41. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/api/document.rs +0 -0
  42. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/api/meta.rs +0 -0
  43. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/api/mod.rs +0 -0
  44. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/db/mod.rs +0 -0
  45. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/db/native.rs +0 -0
  46. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/db/wasm.rs +0 -0
  47. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/lib.rs +0 -0
  48. {ducpy-3.5.0 → ducpy-3.6.0}/packages/ducrs/src/serde_utils.rs +0 -0
  49. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/__init__.py +0 -0
  50. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/block_instance_builder.py +0 -0
  51. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/block_utils.py +0 -0
  52. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/mutate_builder.py +0 -0
  53. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/builders/style_builders.py +0 -0
  54. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/classes/__init__.py +0 -0
  55. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/enums.py +0 -0
  56. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/search/__init__.py +0 -0
  57. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/search/search_external_files.py +0 -0
  58. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/search/search_pdf.py +0 -0
  59. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/utils/__init__.py +0 -0
  60. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/utils/constants.py +0 -0
  61. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/utils/convert.py +0 -0
  62. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/utils/mutate_utils.py +0 -0
  63. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy/utils/rand_utils.py +0 -0
  64. {ducpy-3.5.0 → ducpy-3.6.0}/src/ducpy_native/__init__.py +0 -0
@@ -412,7 +412,7 @@ dependencies = [
412
412
 
413
413
  [[package]]
414
414
  name = "ducpy-native"
415
- version = "3.5.0"
415
+ version = "3.6.0"
416
416
  dependencies = [
417
417
  "duc",
418
418
  "pyo3",
ducpy-3.6.0/Cargo.toml ADDED
@@ -0,0 +1,20 @@
1
+ [workspace]
2
+ resolver = "2"
3
+ members = ["packages/ducrs", "packages/ducpy/crate"]
4
+
5
+ [workspace.metadata.wasm-pack]
6
+ "wasm-pack" = "0.14.0"
7
+
8
+ [profile.dev]
9
+ opt-level = 0
10
+
11
+ [profile.release]
12
+ opt-level = "s"
13
+ lto = true
14
+
15
+ [profile.release-small]
16
+ inherits = "release"
17
+ opt-level = "z"
18
+ codegen-units = 1
19
+ strip = true
20
+ panic = "abort"
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ducpy
3
- Version: 3.5.0
3
+ Version: 3.6.0
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Requires-Dist: nanoid>=2.0.0
6
6
  Requires-Dist: pypdf>=4.2.0
7
- Requires-Dist: rapidocr-onnxruntime>=1.3.24 ; extra == 'ocr'
7
+ Requires-Dist: rapidocr==3.8.1 ; extra == 'ocr'
8
+ Requires-Dist: onnxruntime ; extra == 'ocr'
9
+ Requires-Dist: huggingface-hub>=0.20.0 ; extra == 'ocr'
8
10
  Requires-Dist: numpy>=1.20.0 ; extra == 'ocr'
9
11
  Provides-Extra: ocr
10
12
  License-File: LICENSE
@@ -33,7 +35,7 @@ Project-URL: Source, https://github.com/ducflair/duc/tree/main/packages/ducpy
33
35
  </p>
34
36
  </p>
35
37
 
36
- The `ducpy` package is the official Python implementation of the `.duc` 2D CAD file format. It is built on top of the [`duc`](../ducrs) Rust crate, exposed as the `ducpy_native` extension. A `.duc` file is a zlib-compressed SQLite database — `ducpy` gives you both a high-level builder DSL and direct low-level access to that schema, plus parsing, serialization, and search helpers.
38
+ The `ducpy` package is the official Python implementation of the `.duc` 2D CAD file format. It is built on top of the [`duc`](../ducrs) Rust crate, exposed as the `ducpy_native` extension. A `.duc` file is a gzip-compressed SQLite database — `ducpy` gives you both a high-level builder DSL and direct low-level access to that schema, plus parsing, serialization, and search helpers.
37
39
 
38
40
  ## Installation
39
41
 
@@ -69,7 +71,7 @@ See the worked examples:
69
71
 
70
72
  ### SQL Builder (Low-level)
71
73
 
72
- A `.duc` file is a zlib-compressed SQLite database. Use `duc.builders.sql_builder` (`DucSQL`) for direct schema access, bulk queries, and low-level manipulation.
74
+ A `.duc` file is a gzip-compressed SQLite database. Use `duc.builders.sql_builder` (`DucSQL`) for direct schema access, bulk queries, and low-level manipulation.
73
75
 
74
76
  See the worked example: [SQL Builder](src/examples/sql_builder_demo.py) — `DucSQL.new()` to create a `.duc` from scratch, `DucSQL(path)` to query an existing one.
75
77
 
@@ -12,7 +12,7 @@
12
12
  </p>
13
13
  </p>
14
14
 
15
- The `ducpy` package is the official Python implementation of the `.duc` 2D CAD file format. It is built on top of the [`duc`](../ducrs) Rust crate, exposed as the `ducpy_native` extension. A `.duc` file is a zlib-compressed SQLite database — `ducpy` gives you both a high-level builder DSL and direct low-level access to that schema, plus parsing, serialization, and search helpers.
15
+ The `ducpy` package is the official Python implementation of the `.duc` 2D CAD file format. It is built on top of the [`duc`](../ducrs) Rust crate, exposed as the `ducpy_native` extension. A `.duc` file is a gzip-compressed SQLite database — `ducpy` gives you both a high-level builder DSL and direct low-level access to that schema, plus parsing, serialization, and search helpers.
16
16
 
17
17
  ## Installation
18
18
 
@@ -48,7 +48,7 @@ See the worked examples:
48
48
 
49
49
  ### SQL Builder (Low-level)
50
50
 
51
- A `.duc` file is a zlib-compressed SQLite database. Use `duc.builders.sql_builder` (`DucSQL`) for direct schema access, bulk queries, and low-level manipulation.
51
+ A `.duc` file is a gzip-compressed SQLite database. Use `duc.builders.sql_builder` (`DucSQL`) for direct schema access, bulk queries, and low-level manipulation.
52
52
 
53
53
  See the worked example: [SQL Builder](src/examples/sql_builder_demo.py) — `DucSQL.new()` to create a `.duc` from scratch, `DucSQL(path)` to query an existing one.
54
54
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ducpy-native"
3
- version = "3.5.0"
3
+ version = "3.6.0"
4
4
  edition = "2021"
5
5
  description = "Python native extension for the duc file format (used by ducpy)"
6
6
  publish = false
@@ -14,7 +14,7 @@
14
14
 
15
15
  The `duc` crate is the canonical Rust implementation of the `.duc` 2D CAD file format and the **root of the entire Duc ecosystem**. [`ducpy`](https://pypi.org/project/ducpy/), [`ducjs`](https://www.npmjs.com/package/ducjs), and the rest of the toolchain are all built on top of the types, parsers and storage layer defined here.
16
16
 
17
- A `.duc` file is a standard zlib compressed **SQLite database file** following the schema in `schema/duc.sql`. This crate wraps that database in a strongly-typed Rust API for reading, writing and manipulating `.duc` documents.
17
+ A `.duc` file is a standard gzip-compressed **SQLite database file** following the schema in `schema/duc.sql`. This crate wraps that database in a strongly-typed Rust API for reading, writing and manipulating `.duc` documents.
18
18
 
19
19
 
20
20
  ----
@@ -1,7 +1,7 @@
1
1
  -- "DUC_" in ASCII
2
2
  -- Apply in order: duc.sql → version_control.sql → search.sql
3
3
  PRAGMA application_id = 1146569567;
4
- PRAGMA user_version = 3000005;
4
+ PRAGMA user_version = 3000007;
5
5
  PRAGMA journal_mode = WAL;
6
6
  PRAGMA foreign_keys = ON;
7
7
  PRAGMA synchronous = NORMAL;
@@ -42,7 +42,6 @@ PRAGMA synchronous = NORMAL;
42
42
  -- Project-wide settings shared by all users, saved with the document.
43
43
  CREATE TABLE duc_global_state (
44
44
  id INTEGER PRIMARY KEY CHECK (id = 1),
45
- name TEXT, -- drawing name
46
45
  view_background_color TEXT NOT NULL, -- drawing background color
47
46
  main_scope TEXT NOT NULL, -- master unit (mm, cm, m, in, ft…)
48
47
  scope_exponent_threshold INTEGER NOT NULL DEFAULT 3 -- +/- tolerance for scope switching
@@ -91,7 +90,7 @@ CREATE TABLE duc_document (
91
90
  version TEXT NOT NULL, -- format version string
92
91
  source TEXT NOT NULL, -- originating application
93
92
  data_type TEXT NOT NULL, -- file data type identifier
94
- thumbnail BLOB -- binary thumbnail image
93
+ thumbnail BLOB -- binary thumbnail image
95
94
  ) WITHOUT ROWID;
96
95
 
97
96
  -- Key-value string dictionary for the document.
@@ -101,6 +100,142 @@ CREATE TABLE document_dictionary (
101
100
  ) WITHOUT ROWID;
102
101
 
103
102
 
103
+ -- ===========================================================================
104
+ -- PROJECT CHARTER
105
+ -- ===========================================================================
106
+
107
+ CREATE TABLE duc_charter (
108
+ id INTEGER PRIMARY KEY CHECK (id = 1),
109
+ title TEXT NOT NULL DEFAULT '',
110
+ description TEXT,
111
+ objective TEXT NOT NULL DEFAULT '',
112
+ phase TEXT NOT NULL DEFAULT 'intent' CHECK (phase IN ('intent', 'review', 'delivery', 'closed')),
113
+ closed_reason TEXT,
114
+ updated_at INTEGER NOT NULL DEFAULT 0
115
+ );
116
+
117
+ CREATE TABLE duc_charter_requirements (
118
+ id TEXT PRIMARY KEY,
119
+ statement TEXT NOT NULL,
120
+ must INTEGER NOT NULL DEFAULT 1,
121
+ sort_order INTEGER NOT NULL DEFAULT 0
122
+ ) WITHOUT ROWID;
123
+
124
+ CREATE TABLE duc_charter_requirement_acceptance_criteria (
125
+ requirement_id TEXT NOT NULL REFERENCES duc_charter_requirements(id) ON DELETE CASCADE,
126
+ sort_order INTEGER NOT NULL DEFAULT 0,
127
+ criterion TEXT NOT NULL,
128
+ PRIMARY KEY (requirement_id, sort_order)
129
+ ) WITHOUT ROWID;
130
+
131
+ CREATE TABLE duc_charter_constraints (
132
+ id TEXT PRIMARY KEY,
133
+ statement TEXT NOT NULL,
134
+ hard INTEGER NOT NULL DEFAULT 1,
135
+ sort_order INTEGER NOT NULL DEFAULT 0
136
+ ) WITHOUT ROWID;
137
+
138
+ CREATE TABLE duc_charter_decisions (
139
+ id TEXT PRIMARY KEY,
140
+ accepted INTEGER NOT NULL DEFAULT 1,
141
+ decision TEXT NOT NULL,
142
+ rationale TEXT NOT NULL,
143
+ decided_at INTEGER NOT NULL DEFAULT 0,
144
+ sort_order INTEGER NOT NULL DEFAULT 0
145
+ ) WITHOUT ROWID;
146
+
147
+ CREATE TABLE duc_charter_decision_issue_ids (
148
+ decision_id TEXT NOT NULL REFERENCES duc_charter_decisions(id) ON DELETE CASCADE,
149
+ issue_id TEXT NOT NULL,
150
+ sort_order INTEGER NOT NULL DEFAULT 0,
151
+ PRIMARY KEY (decision_id, sort_order)
152
+ ) WITHOUT ROWID;
153
+
154
+ CREATE TABLE duc_charter_stakeholders (
155
+ sort_order INTEGER PRIMARY KEY,
156
+ actor_identifier TEXT NOT NULL,
157
+ actor_name TEXT,
158
+ role TEXT NOT NULL
159
+ );
160
+
161
+
162
+ -- ===========================================================================
163
+ -- ISSUES
164
+ -- ===========================================================================
165
+
166
+ CREATE TABLE duc_issues (
167
+ id TEXT PRIMARY KEY,
168
+ local_id INTEGER NOT NULL,
169
+ title TEXT NOT NULL,
170
+ status TEXT NOT NULL CHECK (status IN ('open', 'closed', 'dismissed')),
171
+ dismissed_reason TEXT,
172
+ due_date INTEGER,
173
+ author_id TEXT NOT NULL,
174
+ created_at INTEGER NOT NULL,
175
+ updated_at INTEGER NOT NULL,
176
+ deleted_at INTEGER,
177
+ sort_order INTEGER NOT NULL DEFAULT 0
178
+ ) WITHOUT ROWID;
179
+
180
+ CREATE UNIQUE INDEX idx_duc_issues_local_id ON duc_issues(local_id);
181
+ CREATE INDEX idx_duc_issues_status ON duc_issues(status);
182
+ CREATE INDEX idx_duc_issues_updated ON duc_issues(updated_at);
183
+
184
+ CREATE TABLE duc_issue_assignees (
185
+ issue_id TEXT NOT NULL REFERENCES duc_issues(id) ON DELETE CASCADE,
186
+ actor_identifier TEXT NOT NULL,
187
+ sort_order INTEGER NOT NULL DEFAULT 0,
188
+ PRIMARY KEY (issue_id, actor_identifier)
189
+ ) WITHOUT ROWID;
190
+
191
+ CREATE TABLE duc_issue_followers (
192
+ issue_id TEXT NOT NULL REFERENCES duc_issues(id) ON DELETE CASCADE,
193
+ actor_identifier TEXT NOT NULL,
194
+ sort_order INTEGER NOT NULL DEFAULT 0,
195
+ PRIMARY KEY (issue_id, actor_identifier)
196
+ ) WITHOUT ROWID;
197
+
198
+ CREATE TABLE duc_issue_messages (
199
+ id TEXT PRIMARY KEY,
200
+ issue_id TEXT NOT NULL REFERENCES duc_issues(id) ON DELETE CASCADE,
201
+ author_identifier TEXT NOT NULL,
202
+ author_name TEXT,
203
+ content TEXT NOT NULL,
204
+ reply_to_id TEXT,
205
+ created_at INTEGER NOT NULL,
206
+ edited_at INTEGER,
207
+ deleted_at INTEGER,
208
+ sort_order INTEGER NOT NULL DEFAULT 0
209
+ ) WITHOUT ROWID;
210
+
211
+ CREATE INDEX idx_duc_issue_messages_issue ON duc_issue_messages(issue_id, sort_order);
212
+
213
+ CREATE TABLE duc_issue_message_reactions (
214
+ message_id TEXT NOT NULL REFERENCES duc_issue_messages(id) ON DELETE CASCADE,
215
+ emoji TEXT NOT NULL,
216
+ actor_identifier TEXT NOT NULL,
217
+ sort_order INTEGER NOT NULL DEFAULT 0,
218
+ PRIMARY KEY (message_id, emoji, actor_identifier)
219
+ ) WITHOUT ROWID;
220
+
221
+ CREATE TABLE duc_issue_anchors (
222
+ issue_id TEXT PRIMARY KEY REFERENCES duc_issues(id) ON DELETE CASCADE,
223
+ anchor_type TEXT NOT NULL CHECK (anchor_type IN ('canvas', 'element', 'model')),
224
+ canvas_x REAL,
225
+ canvas_y REAL,
226
+ canvas_scope TEXT,
227
+ element_id TEXT,
228
+ anchor_x REAL,
229
+ anchor_y REAL,
230
+ model_point_x REAL,
231
+ model_point_y REAL,
232
+ model_point_z REAL,
233
+ model_normal_x REAL,
234
+ model_normal_y REAL,
235
+ model_normal_z REAL,
236
+ topology_id TEXT
237
+ ) WITHOUT ROWID;
238
+
104
239
  -- ===========================================================================
105
240
  -- STACK-LIKE PROPERTIES (shared base for layers, groups, regions)
106
241
  -- ===========================================================================
@@ -674,7 +809,7 @@ CREATE TABLE element_plot (
674
809
  margin_left REAL NOT NULL DEFAULT 0.0
675
810
  ) WITHOUT ROWID;
676
811
 
677
- -- Shared DocumentGridConfig for document-like elements (PDF, doc).
812
+ -- Shared DocumentGridConfig for document-like elements (PDF, doc, table).
678
813
  -- One row per element that needs grid layout + file reference.
679
814
  CREATE TABLE document_grid_config (
680
815
  element_id TEXT PRIMARY KEY REFERENCES elements(id) ON DELETE CASCADE,
@@ -712,14 +847,11 @@ CREATE TABLE doc_element_referenced_files (
712
847
 
713
848
  CREATE INDEX idx_doc_referenced_files_file ON doc_element_referenced_files(file_id);
714
849
 
715
- -- Table element. Source of truth is the linked xlsx file.
850
+ -- Table element. Grid config and file reference stored in document_grid_config.
716
851
  CREATE TABLE element_table (
717
- element_id TEXT PRIMARY KEY REFERENCES elements(id) ON DELETE CASCADE,
718
- file_id TEXT -- reference to external xlsx file
852
+ element_id TEXT PRIMARY KEY REFERENCES document_grid_config(element_id) ON DELETE CASCADE
719
853
  ) WITHOUT ROWID;
720
854
 
721
- CREATE INDEX idx_element_table_file ON element_table(file_id);
722
-
723
855
  -- Model element (3D parametric, DucModelElement). file_ids in child table.
724
856
  -- Viewer state stored in model_viewer_state table.
725
857
  CREATE TABLE element_model (
@@ -731,10 +863,11 @@ CREATE TABLE element_model (
731
863
 
732
864
  CREATE INDEX idx_element_model_type ON element_model(model_type);
733
865
 
734
- -- 3D viewer state for a model element (Viewer3DState, all sub-structs flattened).
735
- -- At most one row per model element.
866
+ -- 3D viewer state shared by model elements and model issue anchors.
867
+ -- owner_type='element' owner_id=elements.id, or owner_type='issue_anchor' owner_id=duc_issue_anchors.issue_id.
736
868
  CREATE TABLE model_viewer_state (
737
- element_id TEXT PRIMARY KEY REFERENCES elements(id) ON DELETE CASCADE,
869
+ owner_type TEXT NOT NULL CHECK (owner_type IN ('element', 'issue_anchor')),
870
+ owner_id TEXT NOT NULL,
738
871
  -- Viewer3DCamera
739
872
  camera_control TEXT NOT NULL DEFAULT 'orbit', -- 'orbit' | 'trackball'
740
873
  camera_ortho INTEGER NOT NULL DEFAULT 0,
@@ -799,9 +932,22 @@ CREATE TABLE model_viewer_state (
799
932
  zebra_stripe_direction REAL NOT NULL DEFAULT 0.0,
800
933
  zebra_color_scheme TEXT NOT NULL DEFAULT 'blackwhite', -- 'blackwhite' | 'colorful' | 'grayscale'
801
934
  zebra_opacity REAL NOT NULL DEFAULT 1.0,
802
- zebra_mapping_mode TEXT NOT NULL DEFAULT 'reflection' -- 'reflection' | 'normal'
935
+ zebra_mapping_mode TEXT NOT NULL DEFAULT 'reflection', -- 'reflection' | 'normal'
936
+ PRIMARY KEY (owner_type, owner_id)
803
937
  ) WITHOUT ROWID;
804
938
 
939
+ CREATE TRIGGER model_viewer_state_delete_element
940
+ AFTER DELETE ON elements
941
+ BEGIN
942
+ DELETE FROM model_viewer_state WHERE owner_type = 'element' AND owner_id = OLD.id;
943
+ END;
944
+
945
+ CREATE TRIGGER model_viewer_state_delete_issue_anchor
946
+ AFTER DELETE ON duc_issue_anchors
947
+ BEGIN
948
+ DELETE FROM model_viewer_state WHERE owner_type = 'issue_anchor' AND owner_id = OLD.issue_id;
949
+ END;
950
+
805
951
  -- External files connected to a model element (STEP, STL, DXF, etc.).
806
952
  CREATE TABLE model_element_files (
807
953
  element_id TEXT NOT NULL REFERENCES elements(id) ON DELETE CASCADE,
@@ -28,6 +28,7 @@ CREATE TABLE external_file_revisions (
28
28
  last_retrieved INTEGER
29
29
  ) WITHOUT ROWID;
30
30
 
31
+ DROP INDEX IF EXISTS idx_external_file_revisions_file;
31
32
  CREATE INDEX idx_external_file_revisions_file ON external_file_revisions(file_id);
32
33
 
33
34
  INSERT INTO external_file_revisions (id, file_id, size_bytes, checksum, source_name, mime_type, message, created, last_retrieved)
@@ -21,6 +21,9 @@ CREATE VIRTUAL TABLE search_elements USING fts5(
21
21
  prefix='2 3 4 5 6 7 8 9 10'
22
22
  );
23
23
 
24
+ DROP TRIGGER IF EXISTS trg_elements_ai;
25
+ DROP TRIGGER IF EXISTS trg_elements_ad;
26
+ DROP TRIGGER IF EXISTS trg_elements_au;
24
27
  CREATE TRIGGER trg_elements_ai AFTER INSERT ON elements BEGIN
25
28
  INSERT INTO search_elements(rowid, label, description)
26
29
  VALUES (NEW.rowid, NEW.label, NEW.description);
@@ -46,6 +49,9 @@ CREATE VIRTUAL TABLE search_element_text USING fts5(
46
49
  prefix='2 3 4 5 6 7 8 9 10'
47
50
  );
48
51
 
52
+ DROP TRIGGER IF EXISTS trg_element_text_ai;
53
+ DROP TRIGGER IF EXISTS trg_element_text_ad;
54
+ DROP TRIGGER IF EXISTS trg_element_text_au;
49
55
  CREATE TRIGGER trg_element_text_ai AFTER INSERT ON element_text BEGIN
50
56
  INSERT INTO search_element_text(rowid, text, original_text)
51
57
  VALUES (NEW.rowid, NEW.text, NEW.original_text);
@@ -70,6 +76,9 @@ CREATE VIRTUAL TABLE search_element_doc USING fts5(
70
76
  prefix='2 3 4 5 6 7 8 9 10'
71
77
  );
72
78
 
79
+ DROP TRIGGER IF EXISTS trg_element_doc_ai;
80
+ DROP TRIGGER IF EXISTS trg_element_doc_ad;
81
+ DROP TRIGGER IF EXISTS trg_element_doc_au;
73
82
  CREATE TRIGGER trg_element_doc_ai AFTER INSERT ON element_doc BEGIN
74
83
  INSERT INTO search_element_doc(rowid, text)
75
84
  VALUES (NEW.rowid, NEW.text);
@@ -94,6 +103,9 @@ CREATE VIRTUAL TABLE search_element_model USING fts5(
94
103
  prefix='2 3 4 5 6 7 8 9 10'
95
104
  );
96
105
 
106
+ DROP TRIGGER IF EXISTS trg_element_model_ai;
107
+ DROP TRIGGER IF EXISTS trg_element_model_ad;
108
+ DROP TRIGGER IF EXISTS trg_element_model_au;
97
109
  CREATE TRIGGER trg_element_model_ai AFTER INSERT ON element_model BEGIN
98
110
  INSERT INTO search_element_model(rowid, code)
99
111
  VALUES (NEW.rowid, NEW.code);
@@ -119,6 +131,9 @@ CREATE VIRTUAL TABLE search_blocks USING fts5(
119
131
  prefix='2 3 4 5 6 7 8 9 10'
120
132
  );
121
133
 
134
+ DROP TRIGGER IF EXISTS trg_blocks_ai;
135
+ DROP TRIGGER IF EXISTS trg_blocks_ad;
136
+ DROP TRIGGER IF EXISTS trg_blocks_au;
122
137
  CREATE TRIGGER trg_blocks_ai AFTER INSERT ON blocks BEGIN
123
138
  INSERT INTO search_blocks(rowid, label, description)
124
139
  VALUES (NEW.rowid, NEW.label, NEW.description);
@@ -0,0 +1,42 @@
1
+ -- Migration: 3000005 → 3000006
2
+ -- Move table elements onto the shared document_grid_config table so that
3
+ -- file reference and grid layout live in the same place as for PDF/doc elements.
4
+ -- Existing element_table rows are preserved; table-specific columns beyond
5
+ -- file_id can be dropped once all consumers read from document_grid_config.
6
+
7
+ -- 1. Insert missing document_grid_config rows for every table element that
8
+ -- currently stores its file_id in element_table. Use default grid values.
9
+ INSERT INTO document_grid_config (
10
+ element_id,
11
+ file_id,
12
+ grid_columns,
13
+ grid_gap_x,
14
+ grid_gap_y,
15
+ grid_first_page_alone,
16
+ grid_scale
17
+ )
18
+ SELECT
19
+ element_id,
20
+ file_id,
21
+ 1, -- grid_columns
22
+ 0.0, -- grid_gap_x
23
+ 0.0, -- grid_gap_y
24
+ 0, -- grid_first_page_alone
25
+ 1.0 -- grid_scale
26
+ FROM element_table
27
+ WHERE file_id IS NOT NULL
28
+ AND element_id NOT IN (SELECT element_id FROM document_grid_config);
29
+
30
+ -- 2. Re-create element_table without the file_id column so it references only
31
+ -- document_grid_config. This also drops the legacy idx_element_table_file index.
32
+ CREATE TABLE element_table_new (
33
+ element_id TEXT PRIMARY KEY REFERENCES document_grid_config(element_id) ON DELETE CASCADE
34
+ ) WITHOUT ROWID;
35
+
36
+ INSERT INTO element_table_new (element_id)
37
+ SELECT element_id FROM element_table;
38
+
39
+ DROP TABLE element_table;
40
+ ALTER TABLE element_table_new RENAME TO element_table;
41
+
42
+ PRAGMA user_version = 3000006;