oehrpy 0.1.0__py3-none-any.whl

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,362 @@
1
+ Metadata-Version: 2.3
2
+ Name: oehrpy
3
+ Version: 0.1.0
4
+ Summary: A Python SDK for openEHR with type-safe Reference Model classes, template builders, and EHRBase client
5
+ Project-URL: Homepage, https://github.com/platzhersh/oehrpy
6
+ Project-URL: Documentation, https://github.com/platzhersh/oehrpy#readme
7
+ Project-URL: Repository, https://github.com/platzhersh/oehrpy
8
+ Project-URL: Issues, https://github.com/platzhersh/oehrpy/issues
9
+ Author: Open CIS Project
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: aql,clinical,ehr,ehrbase,healthcare,openehr,pydantic,sdk
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Healthcare Industry
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: defusedxml>=0.7
26
+ Requires-Dist: httpx>=0.25
27
+ Requires-Dist: pydantic>=2.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: mypy>=1.0; extra == 'dev'
30
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
31
+ Requires-Dist: pytest>=7.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.1; extra == 'dev'
33
+ Requires-Dist: types-defusedxml>=0.7; extra == 'dev'
34
+ Provides-Extra: generator
35
+ Requires-Dist: jinja2>=3.0; extra == 'generator'
36
+ Requires-Dist: lxml>=4.9; extra == 'generator'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # oehrpy - Python openEHR SDK
40
+
41
+ > **Pronunciation:** /oʊ.ɛər.paɪ/ ("o-air-pie") — short for "openehrpy", where "ehr" is pronounced like "air" (as in openEHR).
42
+
43
+ A comprehensive Python SDK for openEHR that provides type-safe Reference Model classes, template-specific composition builders, EHRBase client, and AQL query builder.
44
+
45
+ ## Overview
46
+
47
+ This project addresses the gap in the openEHR ecosystem where no comprehensive, actively maintained Python SDK exists. It eliminates the need for developers to manually construct complex nested JSON structures when working with openEHR compositions.
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ pip install oehrpy
53
+ ```
54
+
55
+ Or install from source:
56
+
57
+ ```bash
58
+ git clone https://github.com/platzhersh/oehrpy.git
59
+ cd oehrpy
60
+ pip install -e .
61
+ ```
62
+
63
+ ## Compatibility
64
+
65
+ - **Python:** 3.10+
66
+ - **openEHR RM:** 1.1.0
67
+ - **EHRBase:** 2.26.0+ (uses new FLAT format with composition tree IDs)
68
+
69
+ > **Note:** EHRBase 2.0+ introduced breaking changes to the FLAT format. This SDK implements the **new format** used by EHRBase 2.26.0. For details, see [FLAT Format Versions](docs/FLAT_FORMAT_VERSIONS.md).
70
+
71
+ ## Features
72
+
73
+ - **Type-safe RM Classes**: 134 Pydantic models for openEHR Reference Model 1.1.0 types (includes BASE types)
74
+ - **Template Builders**: Pre-built composition builders for common templates (Vital Signs)
75
+ - **OPT Parser & Generator**: Parse OPT files and auto-generate type-safe builder classes
76
+ - **FLAT Format**: Full support for EHRBase 2.26.0+ FLAT format serialization
77
+ - **Canonical JSON**: Convert RM objects to/from openEHR canonical JSON format
78
+ - **EHRBase Client**: Async REST client for EHRBase CDR operations
79
+ - **AQL Builder**: Fluent API for building type-safe AQL queries
80
+ - **IDE Support**: Full autocomplete and type checking support
81
+ - **Validation**: Pydantic v2 validation for all fields
82
+
83
+ ## Quick Start
84
+
85
+ ### Creating RM Objects
86
+
87
+ ```python
88
+ from openehr_sdk.rm import (
89
+ DV_QUANTITY, DV_TEXT, DV_CODED_TEXT,
90
+ CODE_PHRASE, TERMINOLOGY_ID
91
+ )
92
+
93
+ # Create a simple text value
94
+ text = DV_TEXT(value="Patient vital signs recorded")
95
+
96
+ # Create a quantity (e.g., blood pressure)
97
+ bp_systolic = DV_QUANTITY(
98
+ magnitude=120.0,
99
+ units="mm[Hg]",
100
+ property=CODE_PHRASE(
101
+ terminology_id=TERMINOLOGY_ID(value="openehr"),
102
+ code_string="382"
103
+ )
104
+ )
105
+ print(f"Blood pressure: {bp_systolic.magnitude} {bp_systolic.units}")
106
+ ```
107
+
108
+ ### Template Builders
109
+
110
+ Build compositions using type-safe builders without knowing FLAT paths:
111
+
112
+ ```python
113
+ from openehr_sdk.templates import VitalSignsBuilder
114
+
115
+ # Create a vital signs composition
116
+ builder = VitalSignsBuilder(composer_name="Dr. Smith")
117
+ builder.add_blood_pressure(systolic=120, diastolic=80)
118
+ builder.add_pulse(rate=72)
119
+ builder.add_temperature(37.2)
120
+ builder.add_respiration(rate=16)
121
+ builder.add_oxygen_saturation(spo2=98)
122
+
123
+ # Get FLAT format for EHRBase submission
124
+ flat_data = builder.build()
125
+ # {
126
+ # "vital_signs_observations/language|code": "en",
127
+ # "vital_signs_observations/territory|code": "US",
128
+ # "vital_signs_observations/composer|name": "Dr. Smith",
129
+ # "vital_signs_observations/category|code": "433",
130
+ # "vital_signs_observations/vital_signs/blood_pressure/systolic|magnitude": 120,
131
+ # "vital_signs_observations/vital_signs/blood_pressure/systolic|unit": "mm[Hg]",
132
+ # "vital_signs_observations/vital_signs/body_temperature/temperature|unit": "°C",
133
+ # ...
134
+ # }
135
+ ```
136
+
137
+ ### Generate Builders from OPT Files
138
+
139
+ Automatically generate template-specific builder classes from OPT (Operational Template) files:
140
+
141
+ ```python
142
+ from openehr_sdk.templates import generate_builder_from_opt, parse_opt
143
+
144
+ # Parse an OPT file
145
+ template = parse_opt("path/to/your-template.opt")
146
+ print(f"Template: {template.template_id}")
147
+ print(f"Observations: {len(template.list_observations())}")
148
+
149
+ # Generate Python builder code
150
+ code = generate_builder_from_opt("path/to/your-template.opt")
151
+ print(code) # Full Python class ready to use
152
+
153
+ # Or save directly to a file
154
+ from openehr_sdk.templates import BuilderGenerator
155
+
156
+ generator = BuilderGenerator()
157
+ generator.generate_to_file(template, "my_template_builder.py")
158
+ ```
159
+
160
+ **Command-line tool:**
161
+ ```bash
162
+ python examples/generate_builder_from_opt.py path/to/template.opt
163
+ ```
164
+
165
+ This eliminates the need to manually code builders - just provide your OPT file and get a fully type-safe builder class with methods for each observation type.
166
+
167
+ ### Canonical JSON Serialization
168
+
169
+ ```python
170
+ from openehr_sdk.rm import DV_QUANTITY, CODE_PHRASE, TERMINOLOGY_ID
171
+ from openehr_sdk.serialization import to_canonical, from_canonical
172
+
173
+ # Serialize to canonical JSON (with _type fields)
174
+ quantity = DV_QUANTITY(magnitude=120.0, units="mm[Hg]", ...)
175
+ canonical = to_canonical(quantity)
176
+ # {"_type": "DV_QUANTITY", "magnitude": 120.0, "units": "mm[Hg]", ...}
177
+
178
+ # Deserialize back to Python object
179
+ restored = from_canonical(canonical, expected_type=DV_QUANTITY)
180
+ ```
181
+
182
+ ### FLAT Format Builder
183
+
184
+ ```python
185
+ from openehr_sdk.serialization import FlatBuilder
186
+
187
+ # For EHRBase 2.26.0+, use composition tree ID as prefix
188
+ builder = FlatBuilder(composition_prefix="vital_signs_observations")
189
+ builder.context(language="en", territory="US", composer_name="Dr. Smith")
190
+ builder.set_quantity("vital_signs_observations/vital_signs/blood_pressure/systolic", 120.0, "mm[Hg]")
191
+ builder.set_coded_text("vital_signs_observations/vital_signs/blood_pressure/position", "Sitting", "at0001")
192
+
193
+ flat_data = builder.build()
194
+ # Automatically includes required fields: category, context/start_time, context/setting
195
+ ```
196
+
197
+ ### EHRBase REST Client
198
+
199
+ ```python
200
+ from openehr_sdk.client import EHRBaseClient
201
+
202
+ async with EHRBaseClient(
203
+ base_url="http://localhost:8080/ehrbase",
204
+ username="admin",
205
+ password="admin",
206
+ ) as client:
207
+ # Create an EHR
208
+ ehr = await client.create_ehr()
209
+ print(f"Created EHR: {ehr.ehr_id}")
210
+
211
+ # Create a composition
212
+ result = await client.create_composition(
213
+ ehr_id=ehr.ehr_id,
214
+ template_id="IDCR - Vital Signs Encounter.v1",
215
+ composition=flat_data,
216
+ format="FLAT",
217
+ )
218
+ print(f"Created composition: {result.uid}")
219
+
220
+ # Query compositions
221
+ query_result = await client.query(
222
+ "SELECT c FROM EHR e CONTAINS COMPOSITION c WHERE e/ehr_id/value = :ehr_id",
223
+ query_parameters={"ehr_id": ehr.ehr_id},
224
+ )
225
+ ```
226
+
227
+ ### AQL Query Builder
228
+
229
+ ```python
230
+ from openehr_sdk.aql import AQLBuilder
231
+
232
+ # Build complex queries with a fluent API
233
+ query = (
234
+ AQLBuilder()
235
+ .select("c/uid/value", alias="composition_id")
236
+ .select("c/context/start_time/value", alias="time")
237
+ .from_ehr()
238
+ .contains_composition()
239
+ .contains_observation(archetype_id="openEHR-EHR-OBSERVATION.blood_pressure.v1")
240
+ .where_ehr_id()
241
+ .order_by_time(descending=True)
242
+ .limit(100)
243
+ .build()
244
+ )
245
+
246
+ print(query.to_string())
247
+ # SELECT c/uid/value AS composition_id, c/context/start_time/value AS time
248
+ # FROM EHR e CONTAINS COMPOSITION c CONTAINS OBSERVATION o[...]
249
+ # WHERE e/ehr_id/value = :ehr_id
250
+ # ORDER BY c/context/start_time/value DESC
251
+ # LIMIT 100
252
+ ```
253
+
254
+ ## Available RM Types
255
+
256
+ The SDK includes all major openEHR RM 1.1.0 types:
257
+
258
+ **Data Types:**
259
+ - `DV_TEXT`, `DV_CODED_TEXT`, `CODE_PHRASE`
260
+ - `DV_QUANTITY`, `DV_COUNT`, `DV_PROPORTION`, `DV_SCALE` *(new in 1.1.0)*
261
+ - `DV_ORDINAL` *(integer values only - use DV_SCALE for decimal scale values)*
262
+ - `DV_DATE_TIME`, `DV_DATE`, `DV_TIME`, `DV_DURATION`
263
+ - `DV_BOOLEAN`, `DV_IDENTIFIER`, `DV_URI`, `DV_EHR_URI`
264
+ - `DV_MULTIMEDIA`, `DV_PARSABLE`
265
+
266
+ **Structures:**
267
+ - `COMPOSITION`, `SECTION`, `ENTRY`
268
+ - `OBSERVATION`, `EVALUATION`, `INSTRUCTION`, `ACTION`
269
+ - `ITEM_TREE`, `ITEM_LIST`, `CLUSTER`, `ELEMENT`
270
+ - `HISTORY`, `EVENT`, `POINT_EVENT`, `INTERVAL_EVENT`
271
+
272
+ **Support:**
273
+ - `PARTY_IDENTIFIED`, `PARTY_SELF`, `PARTICIPATION`
274
+ - `OBJECT_REF`, `OBJECT_ID`, `HIER_OBJECT_ID`
275
+ - `ARCHETYPED`, `LOCATABLE`, `PATHABLE`
276
+
277
+ ### New in RM 1.1.0
278
+
279
+ - **DV_SCALE**: Data type for scales/scores with decimal values (extends DV_ORDINAL for non-integer scales)
280
+ - **preferred_term**: New optional field in DV_CODED_TEXT for terminology mapping
281
+ - **Enhanced Folder support**: Archetypeable meta-data in EHR folders
282
+
283
+ For details, see [ADR-0001: Support RM 1.1.0](docs/adr/0001-odin-parsing-and-rm-1.1.0-support.md).
284
+
285
+ ## Development
286
+
287
+ ### Prerequisites
288
+
289
+ - Python 3.10+
290
+ - pip
291
+
292
+ ### Setup
293
+
294
+ ```bash
295
+ # Clone the repository
296
+ git clone https://github.com/platzhersh/oehrpy.git
297
+ cd oehrpy
298
+
299
+ # Install development dependencies
300
+ pip install -e ".[dev,generator]"
301
+ ```
302
+
303
+ ### Running Tests
304
+
305
+ ```bash
306
+ pytest tests/ -v
307
+ ```
308
+
309
+ ### Type Checking
310
+
311
+ ```bash
312
+ mypy src/openehr_sdk
313
+ ```
314
+
315
+ ### Regenerating RM Classes
316
+
317
+ The RM classes are generated from openEHR BMM specifications:
318
+
319
+ ```bash
320
+ python -m generator.pydantic_generator
321
+ ```
322
+
323
+ ## Project Structure
324
+
325
+ ```text
326
+ oehrpy/
327
+ ├── src/openehr_sdk/ # Main package
328
+ │ ├── rm/ # Generated RM + BASE classes (134 types)
329
+ │ ├── serialization/ # JSON serialization (canonical + FLAT)
330
+ │ ├── client/ # EHRBase REST client
331
+ │ ├── templates/ # Template builders (Vital Signs, etc.)
332
+ │ └── aql/ # AQL query builder
333
+ ├── generator/ # Code generation tools
334
+ │ ├── bmm_parser.py # BMM JSON parser
335
+ │ ├── pydantic_generator.py # Pydantic code generator
336
+ │ └── bmm/ # BMM specification files
337
+ ├── tests/ # Test suite (66 tests)
338
+ └── docs/ # Documentation
339
+ ```
340
+
341
+ ## Contributing
342
+
343
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on how to get started.
344
+
345
+ ## License
346
+
347
+ MIT
348
+
349
+ ## Documentation
350
+
351
+ - [FLAT Format Versions](docs/FLAT_FORMAT_VERSIONS.md) - Understanding EHRBase 2.0+ FLAT format changes
352
+ - [FLAT Format Learnings](docs/flat-format-learnings.md) - Comprehensive FLAT format guide
353
+ - [ADR-0001: RM 1.1.0 Support](docs/adr/0001-odin-parsing-and-rm-1.1.0-support.md)
354
+ - [ADR-0002: Integration Testing](docs/adr/0002-integration-testing-with-ehrbase.md)
355
+ - [PRD-0000: Python openEHR SDK](docs/prd/PRD-0000-python-openehr-sdk.md)
356
+
357
+ ## References
358
+
359
+ - [openEHR BMM Specifications](https://github.com/openEHR/specifications-ITS-BMM)
360
+ - [openEHR RM Specification](https://specifications.openehr.org/releases/RM/latest)
361
+ - [EHRBase](https://ehrbase.org/)
362
+ - [EHRBase Documentation](https://docs.ehrbase.org/) *(Note: FLAT format docs may be outdated, see our [FLAT Format Versions](docs/FLAT_FORMAT_VERSIONS.md) guide)*
@@ -0,0 +1,18 @@
1
+ openehr_sdk/__init__.py,sha256=Rzs3NFgVa-P2ljZu2-OXcgkKBrhE_mAwWf9HnnVwrB8,1295
2
+ openehr_sdk/aql/__init__.py,sha256=auR0SKnnnAhzRzq2nU0YZSzUPKmAzYoXXdWs9Kxzoq8,958
3
+ openehr_sdk/aql/builder.py,sha256=APYpX-MhgKllz8USb1XLnW8zI4BN3ZTe5Wxv1DjIex4,17053
4
+ openehr_sdk/client/__init__.py,sha256=swqiwHCbwyIvq_newgkUEfGq6FvHV_CFfU_fYw2rw08,626
5
+ openehr_sdk/client/ehrbase.py,sha256=kTY6j0cTDWfJxinWizODzhZ2xO9NcAGjkyFgaYArvtQ,20740
6
+ openehr_sdk/rm/__init__.py,sha256=yS5JAFaUuoo3D-k_Q9V78j2cBQKTW4EMK9LYEl34ZAc,457
7
+ openehr_sdk/rm/rm_types.py,sha256=QQtWk5QZD-Xh8VAPScPQYnXu-zoQar94ZFv2JPSzQUc,50511
8
+ openehr_sdk/serialization/__init__.py,sha256=aucmds3NXlq1nQrjQNZnYR6PzqT63lAcCLh3og2AtM8,748
9
+ openehr_sdk/serialization/canonical.py,sha256=hQMLaKWne9Ep_mv0VrT7kJa0y89C37YEB5owRpACRag,6325
10
+ openehr_sdk/serialization/flat.py,sha256=w8hh6jGGsVHzvnjm1RlMoAhAxuhLumfuV_rrC5sH60A,13122
11
+ openehr_sdk/templates/__init__.py,sha256=_9Fwua5Mw_mM5n9CaKqXql12GSQyVvqdc_-J-jxv7BE,804
12
+ openehr_sdk/templates/builder_generator.py,sha256=oTYcsvmwGasUfGU3zmW9O79eCFyyprO4hkGJ5SvMB5I,13679
13
+ openehr_sdk/templates/builders.py,sha256=CJuOrobrCNWBbEyHbVJTzGqxApZ7CAyZrhUmY9ctvWg,13665
14
+ openehr_sdk/templates/opt_parser.py,sha256=WzOFYUHgAYTn7hk8LWghqP2gjiG9t3LWlYpQ3-999pg,12423
15
+ oehrpy-0.1.0.dist-info/METADATA,sha256=Tf-pVSj8lJ4wPt7rFBMnAkTjRgcnznH8p2ZC5WYm91E,11972
16
+ oehrpy-0.1.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
17
+ oehrpy-0.1.0.dist-info/licenses/LICENSE,sha256=2RQ4UN7dGDVJh_e9NTzuaUzdMWMDsy1jgLPxKxJahus,1073
18
+ oehrpy-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.24.2
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Open CIS Project
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,49 @@
1
+ """
2
+ oehrpy - A Python SDK for openEHR.
3
+
4
+ This package provides:
5
+ - Type-safe Pydantic models for all openEHR Reference Model 1.1.0 types
6
+ - Template-specific composition builders (e.g., Vital Signs)
7
+ - Serialization support for canonical JSON and FLAT formats
8
+ - Async REST client for EHRBase CDR
9
+ - AQL query builder
10
+
11
+ Quick Start:
12
+ >>> from openehr_sdk.rm import DV_QUANTITY, DV_TEXT
13
+ >>> from openehr_sdk import to_canonical, from_canonical
14
+ >>>
15
+ >>> # Create RM objects
16
+ >>> text = DV_TEXT(value="Hello")
17
+ >>>
18
+ >>> # Serialize to canonical JSON
19
+ >>> json_data = to_canonical(text)
20
+ >>> # {"_type": "DV_TEXT", "value": "Hello"}
21
+
22
+ For template-based compositions:
23
+ >>> from openehr_sdk.templates import VitalSignsBuilder
24
+ >>>
25
+ >>> builder = VitalSignsBuilder(composer_name="Dr. Smith")
26
+ >>> builder.add_blood_pressure(systolic=120, diastolic=80)
27
+ >>> builder.add_pulse(rate=72)
28
+ >>> flat_data = builder.build()
29
+ """
30
+
31
+ __version__ = "0.1.0"
32
+
33
+ # Re-export main components for convenient access
34
+ from openehr_sdk.serialization import (
35
+ FlatBuilder,
36
+ FlatContext,
37
+ from_canonical,
38
+ to_canonical,
39
+ )
40
+
41
+ __all__ = [
42
+ "__version__",
43
+ # Canonical JSON
44
+ "to_canonical",
45
+ "from_canonical",
46
+ # FLAT format
47
+ "FlatBuilder",
48
+ "FlatContext",
49
+ ]
@@ -0,0 +1,40 @@
1
+ """
2
+ AQL (Archetype Query Language) query builder.
3
+
4
+ This module provides a fluent API for building type-safe AQL queries
5
+ for openEHR Clinical Data Repositories.
6
+
7
+ Example:
8
+ >>> from openehr_sdk.aql import AQLBuilder
9
+ >>>
10
+ >>> query = (
11
+ ... AQLBuilder()
12
+ ... .select("c/uid/value", alias="composition_id")
13
+ ... .select("c/context/start_time/value", alias="start_time")
14
+ ... .from_ehr("e")
15
+ ... .contains_composition("c", "IDCR - Vital Signs Encounter.v1")
16
+ ... .where("e/ehr_id/value = :ehr_id")
17
+ ... .order_by("c/context/start_time/value", descending=True)
18
+ ... .limit(10)
19
+ ... .build()
20
+ ... )
21
+ >>> print(query.to_string())
22
+ """
23
+
24
+ from .builder import (
25
+ AQLBuilder,
26
+ AQLQuery,
27
+ FromClause,
28
+ OrderByClause,
29
+ SelectClause,
30
+ WhereClause,
31
+ )
32
+
33
+ __all__ = [
34
+ "AQLBuilder",
35
+ "AQLQuery",
36
+ "SelectClause",
37
+ "FromClause",
38
+ "WhereClause",
39
+ "OrderByClause",
40
+ ]