Skip to content

Commit ee8eeea

Browse files
committed
Update README with type information
1 parent e32f9a1 commit ee8eeea

File tree

1 file changed

+174
-34
lines changed

1 file changed

+174
-34
lines changed

README.md

Lines changed: 174 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -209,59 +209,76 @@ WHERE [r].[resource_type] = 'Patient'
209209

210210
### Basic usage
211211

212-
```javascript
212+
```typescript
213213
import {SqlOnFhir} from 'sof-mssql';
214214

215-
// Create an instance with default configuration
216215
const sqlOnFhir = new SqlOnFhir();
216+
```
217217

218-
// Transpile a ViewDefinition to T-SQL
219-
const viewDefinition = {
220-
resourceType: 'ViewDefinition',
221-
resource: 'Patient',
222-
name: 'patient_demographics',
223-
select: [
218+
Create a ViewDefinition to transpile:
219+
220+
```json
221+
{
222+
"resourceType": "ViewDefinition",
223+
"resource": "Patient",
224+
"name": "patient_demographics",
225+
"select": [
224226
{
225-
column: [
227+
"column": [
226228
{
227-
name: 'id',
228-
path: 'id',
229-
type: 'id'
229+
"name": "id",
230+
"path": "id",
231+
"type": "id"
230232
},
231233
{
232-
name: 'family_name',
233-
path: 'name.family',
234-
type: 'string'
234+
"name": "family_name",
235+
"path": "name.family",
236+
"type": "string"
235237
},
236238
{
237-
name: 'birth_date',
238-
path: 'birthDate',
239-
type: 'date'
239+
"name": "birth_date",
240+
"path": "birthDate",
241+
"type": "date"
240242
}
241243
]
242244
}
243245
]
244-
};
246+
}
247+
```
248+
249+
Transpile the ViewDefinition to T-SQL:
245250

251+
```typescript
246252
const result = sqlOnFhir.transpile(viewDefinition);
247253

248254
console.log(result.sql);
249-
// Output:
250-
// SELECT
251-
// r.id AS [id],
252-
// JSON_VALUE(r.json, '$.name[0].family') AS [family_name],
253-
// CAST(JSON_VALUE(r.json, '$.birthDate') AS DATETIME2) AS [birth_date]
254-
// FROM [dbo].[fhir_resources] AS [r]
255-
// WHERE [r].[resource_type] = 'Patient'
256-
257-
// Access column metadata
255+
```
256+
257+
Generated SQL output:
258+
259+
```sql
260+
SELECT
261+
r.id AS [id],
262+
JSON_VALUE(r.json, '$.name[0].family') AS [family_name],
263+
CAST(JSON_VALUE(r.json, '$.birthDate') AS DATETIME2) AS [birth_date]
264+
FROM [dbo].[fhir_resources] AS [r]
265+
WHERE [r].[resource_type] = 'Patient'
266+
```
267+
268+
Access column metadata:
269+
270+
```typescript
258271
console.log(result.columns);
259-
// Output:
260-
// [
261-
// { name: 'id', type: 'NVARCHAR(64)', nullable: true },
262-
// { name: 'family_name', type: 'NVARCHAR(MAX)', nullable: true },
263-
// { name: 'birth_date', type: 'DATETIME2', nullable: true }
264-
// ]
272+
```
273+
274+
Column metadata output:
275+
276+
```json
277+
[
278+
{ "name": "id", "type": "VARCHAR(64)", "nullable": true },
279+
{ "name": "family_name", "type": "NVARCHAR(MAX)", "nullable": true },
280+
{ "name": "birth_date", "type": "VARCHAR(10)", "nullable": true }
281+
]
265282
```
266283

267284
### Custom table configuration
@@ -292,8 +309,131 @@ const fhirResource = {
292309
// ... rest of ViewDefinition
293310
};
294311
const result2 = sqlOnFhir.transpile(fhirResource);
312+
````
313+
314+
### Type mappings and type hints
315+
316+
#### Default type mappings
317+
318+
By default, FHIR primitive types are mapped to the following T-SQL types:
319+
320+
| FHIR Type | Default T-SQL Type | Rationale |
321+
|-----------------------------------------|--------------------|-------------------------------------------|
322+
| `id` | `VARCHAR(64)` | ASCII-only, fixed max length |
323+
| `boolean` | `BIT` | Native boolean |
324+
| `integer`, `positiveint`, `unsignedint` | `INT` | 32-bit integer |
325+
| `integer64` | `BIGINT` | 64-bit integer |
326+
| `decimal` | `VARCHAR(MAX)` | Preserves arbitrary precision |
327+
| `date` | `VARCHAR(10)` | Preserves partial dates (e.g., "2024-01") |
328+
| `datetime` | `VARCHAR(50)` | Preserves partial datetimes and timezones |
329+
| `instant` | `VARCHAR(50)` | Preserves full ISO 8601 format |
330+
| `time` | `VARCHAR(20)` | Preserves partial times |
331+
| `string`, `markdown`, `code` | `NVARCHAR(MAX)` | Unicode-capable text |
332+
| `uri`, `url`, `canonical` | `NVARCHAR(MAX)` | Can contain Unicode (IRIs) |
333+
| `uuid` | `VARCHAR(100)` | ASCII UUID format |
334+
| `oid` | `VARCHAR(255)` | ASCII OID format |
335+
| `base64binary` | `VARBINARY(MAX)` | Binary data |
336+
337+
**Design principle:** Default mappings use `VARCHAR` for temporal and numeric types to preserve FHIR semantics (partial dates, arbitrary precision decimals) rather than forcing conversion to SQL native types.
338+
339+
#### Using type hints
340+
341+
You can override default type mappings using the `tag` array on column definitions. Two tag types are supported:
342+
343+
**`tsql/type` - Direct T-SQL type specification:**
344+
345+
```json
346+
{
347+
"name": "birth_date",
348+
"path": "birthDate",
349+
"type": "date",
350+
"tag": [
351+
{ "name": "tsql/type", "value": "DATE" }
352+
]
353+
}
295354
```
296355

356+
This generates a CAST expression: `CAST(JSON_VALUE(r.json, '$.birthDate') AS DATE) AS [birth_date]`
357+
358+
**`ansi/type` - ANSI/ISO SQL standard types (automatically converted to T-SQL):**
359+
360+
```json
361+
{
362+
"name": "age",
363+
"path": "age",
364+
"type": "integer",
365+
"tag": [
366+
{ "name": "ansi/type", "value": "INTEGER" }
367+
]
368+
}
369+
```
370+
371+
The ANSI type `INTEGER` is automatically converted to T-SQL `INT`.
372+
373+
```json
374+
{
375+
"name": "active",
376+
"path": "active",
377+
"type": "boolean",
378+
"tag": [
379+
{ "name": "ansi/type", "value": "BOOLEAN" }
380+
]
381+
}
382+
```
383+
384+
The ANSI type `BOOLEAN` is automatically converted to T-SQL `BIT`.
385+
386+
**Type precedence:** `tsql/type` > `ansi/type` > FHIR type defaults
387+
388+
**Supported ANSI types:**
389+
- Character: `CHARACTER`, `CHARACTER VARYING`, `NATIONAL CHARACTER VARYING`
390+
- Numeric: `INTEGER`, `SMALLINT`, `BIGINT`, `DECIMAL`, `NUMERIC`, `FLOAT`, `REAL`, `DOUBLE PRECISION`
391+
- Temporal: `DATE`, `TIME`, `TIMESTAMP` (converted to `DATETIME2`)
392+
- Boolean: `BOOLEAN` (converted to `BIT`)
393+
394+
**Example with multiple columns:**
395+
396+
This example demonstrates how different type hints affect the resulting SQL types:
397+
398+
```json
399+
{
400+
"resourceType": "ViewDefinition",
401+
"resource": "Patient",
402+
"select": [
403+
{
404+
"column": [
405+
{
406+
"name": "id",
407+
"path": "id",
408+
"type": "id"
409+
},
410+
{
411+
"name": "birth_date",
412+
"path": "birthDate",
413+
"type": "date",
414+
"tag": [
415+
{ "name": "tsql/type", "value": "DATE" }
416+
]
417+
},
418+
{
419+
"name": "deceased",
420+
"path": "deceasedBoolean",
421+
"type": "boolean",
422+
"tag": [
423+
{ "name": "ansi/type", "value": "BOOLEAN" }
424+
]
425+
}
426+
]
427+
}
428+
]
429+
}
430+
```
431+
432+
Type behaviour for each column:
433+
- `id` - Uses default FHIR type mapping: `VARCHAR(64)`
434+
- `birth_date` - Overrides default `VARCHAR(10)` with T-SQL `DATE` type
435+
- `deceased` - Uses ANSI `BOOLEAN` type, automatically converted to T-SQL `BIT`
436+
297437
## Database setup
298438

299439
### Table structure

0 commit comments

Comments
 (0)