Skip to content

Commit

Permalink
Update canonical URI and package ID
Browse files Browse the repository at this point in the history
  • Loading branch information
johngrimes committed Sep 20, 2024
1 parent 42208a6 commit 91f3bdd
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 116 deletions.
2 changes: 1 addition & 1 deletion ig.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[IG]
ig = fsh-generated/resources/ImplementationGuide-hl7.fhir.uv.sql-on-fhir.json
ig = fsh-generated/resources/ImplementationGuide-org.sql-on-fhir.ig.json
template = #custom-template
4 changes: 2 additions & 2 deletions input/fsh/examples.fsh
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ Usage: #example
* status = #draft
* resource = #Patient
* meta
* profile[+] = "http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ShareableViewDefinition"
* profile[+] = "http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/TabularViewDefinition"
* profile[+] = "https://sql-on-fhir.org/ig/StructureDefinition/ShareableViewDefinition"
* profile[+] = "https://sql-on-fhir.org/ig/StructureDefinition/TabularViewDefinition"
* select[+]
* column[+]
* path = "getResourceKey()"
Expand Down
4 changes: 2 additions & 2 deletions input/fsh/models.fsh
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ criteria are defined by FHIRPath expressions.
be used to represent the value within an ANSI SQL database.
"""
* value 1..1 string "Value of tag"
* select 0..* contentReference http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition#ViewDefinition.select "Nested select relative to a parent expression." """
* select 0..* contentReference https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition#ViewDefinition.select "Nested select relative to a parent expression." """
Nested select relative to a parent expression. If the parent `select` has a `forEach` or `forEachOrNull`, this child select will apply for each item in that expression.
"""
* forEach 0..1 string "A FHIRPath expression to retrieve the parent element(s) used in the containing select. The default is effectively `$this`." """
Expand All @@ -124,7 +124,7 @@ criteria are defined by FHIRPath expressions.
with a Patient resource, a `forEachOrNull` on address will produce a row for each patient even if there are no addresses; it will
simply set the address columns to `null`.
"""
* unionAll 0..* contentReference http://hl7.org/fhir/uv/sql-on-fhir/StructureDefinition/ViewDefinition#ViewDefinition.select "Creates a union of all rows in the given selection structures." """
* unionAll 0..* contentReference https://sql-on-fhir.org/ig/StructureDefinition/ViewDefinition#ViewDefinition.select "Creates a union of all rows in the given selection structures." """
A `unionAll` combines the results of multiple selection structures. Each structure under the `unionAll` must produce the same column names
and types. The results from each nested selection will then have their own row.
"""
Expand Down
2 changes: 1 addition & 1 deletion legacy-tests/tests.schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$id": "http://hl7.org/fhir/uv/sql-on-fhir/tests",
"$id": "https://sql-on-fhir.org/ig/tests",
"title": "SQL on FHIR Tests Schema",
"description": "Schema for tests",
"type": "object",
Expand Down
57 changes: 29 additions & 28 deletions sof-js/src/path.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ function getResourceKey(nodes) {
}

function getReferenceKey(nodes, opts) {
let resource = opts?.name;
let resource = opts?.name
return nodes.flatMap((node) => {
const parts = node.reference.replaceAll('//', '').split('/_history')[0].split('/')
const type = parts[parts.length - 2];
const key = parts[parts.length - 1];
if(!resource) {
return [key];
} else if(resource && resource == type) {
return [key];
const type = parts[parts.length - 2]
const key = parts[parts.length - 1]
if (!resource) {
return [key]
} else if (resource && resource == type) {
return [key]
} else {
return []
}
Expand All @@ -29,10 +29,9 @@ function ofType(ctx, nodes, a1, a2, a3) {
return 'ups'
}


function rewrite_path(path) {
if(path.startsWith('$this')){
path = 'identity()' + path.slice('$this'.length)
if (path.startsWith('$this')) {
path = 'identity()' + path.slice('$this'.length)
}
const ofTypeRegex = /\.ofType\(([^)]+)\)/g
let match
Expand All @@ -43,43 +42,45 @@ function rewrite_path(path) {
const replacement = match[1].charAt(0).toUpperCase() + match[1].slice(1)
path = path.replace(match[0], `${replacement}`)
}
return path;
return path
}


let fhirpath_options = {
userInvocationTable: {
getResourceKey: { fn: getResourceKey, arity: { 0: [] } },
getReferenceKey: { fn: getReferenceKey, arity: { 0: [], 1: ['TypeSpecifier'] } },
identity: { fn: (nodes) => nodes, arity: { 0: [] } },
}
getResourceKey: { fn: getResourceKey, arity: { 0: [] } },
getReferenceKey: {
fn: getReferenceKey,
arity: { 0: [], 1: ['TypeSpecifier'] },
},
identity: { fn: (nodes) => nodes, arity: { 0: [] } },
},
}

function process_constants(constants) {
return constants.reduce((acc, x) => {
let name, val;
let name, val
for (const key in x) {
if (key === "name") {
name = x[key];
if (key === 'name') {
name = x[key]
}
if (key.startsWith("value")) {
val = x[key];
if (key.startsWith('value')) {
val = x[key]
}
}
acc[name] = val;
return acc;
}, {});
acc[name] = val
return acc
}, {})
}

export function fhirpath_evaluate(data, path, constants = []) {
return fhirpath.evaluate(data, rewrite_path(path), process_constants(constants), null, fhirpath_options);
return fhirpath.evaluate(data, rewrite_path(path), process_constants(constants), null, fhirpath_options)
}

export function fhirpath_validate(path) {
try {
fhirpath.compile(path, null, fhirpath_options);
return true;
fhirpath.compile(path, null, fhirpath_options)
return true
} catch (e) {
return false;
return false
}
}
144 changes: 72 additions & 72 deletions sof-js/src/validate.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
import Ajv from 'ajv'
import { fhirpath_validate } from './path';
import { fhirpath_validate } from './path'

let array = "array";
let string = {type: "string"};
let object = "object";
let bool = {type: "boolean"};
let fhirpath_string = {type: "string" , format: "fhirpath-expression"}
let array = 'array'
let string = { type: 'string' }
let object = 'object'
let bool = { type: 'boolean' }
let fhirpath_string = { type: 'string', format: 'fhirpath-expression' }
// todo regex
let identifier = {type: "string", minLength: 1}
let identifier = { type: 'string', minLength: 1 }

function $ref(name) {
return {$ref: `#/$defs/${name}`}
return { $ref: `#/$defs/${name}` }
}

function const_value(name, type = string) {
return {
type: object,
required: [name],
properties: { [name]: type }
};
properties: { [name]: type },
}
}


function viewdef_schema(for_tests = false) {
let column_required_fields
let id = "http://hl7.org/fhir/uv/sql-on-fhir/ViewDefinition"
let id = 'https://sql-on-fhir.org/ig/ViewDefinition'
if (for_tests) {
column_required_fields = ["path", "name", "type"]
id = id + "_test"
column_required_fields = ['path', 'name', 'type']
id = id + '_test'
} else {
column_required_fields = ["path", "name"]
column_required_fields = ['path', 'name']
}

let schema = {
$id: id,
title: "ViewDefinition",
description: "validate FHIR ViewDefinition schema",
title: 'ViewDefinition',
description: 'validate FHIR ViewDefinition schema',
type: object,
required: ["resource", "select"],
required: ['resource', 'select'],
additionalProperties: false,
properties: {
title: string,
Expand All @@ -53,48 +52,48 @@ function viewdef_schema(for_tests = false) {
allOf: [
{
type: object,
required: ["name"],
properties: { name: string }
}, {
required: ['name'],
properties: { name: string },
},
{
oneOf: [
const_value("valueBase64Binary"),
const_value("valueBoolean", bool),
const_value("valueCanonical"),
const_value("valueCode"),
const_value("valueDate"),
const_value("valueDateTime"),
const_value("valueDecimal", { type: "number" }),
const_value("valueId"),
const_value("valueInstant"),
const_value("valueInteger", { type: "integer" }),
const_value("valueInteger64"),
const_value("valueOid"),
const_value("valueString"),
const_value("valuePositiveInt", { type: "integer", minimum: 1 }),
const_value("valueTime"),
const_value("valueUnsignedInt", { type: "integer", minimum: 0 }),
const_value("valueUri"),
const_value("valueUrl"),
const_value("valueUuid")
]
}
]
}
const_value('valueBase64Binary'),
const_value('valueBoolean', bool),
const_value('valueCanonical'),
const_value('valueCode'),
const_value('valueDate'),
const_value('valueDateTime'),
const_value('valueDecimal', { type: 'number' }),
const_value('valueId'),
const_value('valueInstant'),
const_value('valueInteger', { type: 'integer' }),
const_value('valueInteger64'),
const_value('valueOid'),
const_value('valueString'),
const_value('valuePositiveInt', { type: 'integer', minimum: 1 }),
const_value('valueTime'),
const_value('valueUnsignedInt', { type: 'integer', minimum: 0 }),
const_value('valueUri'),
const_value('valueUrl'),
const_value('valueUuid'),
],
},
],
},
},
select: $ref('select'),
where:
{
where: {
type: array,
items: {
type: object,
required: ["path"],
required: ['path'],
additionalProperties: false,
properties: {
path: fhirpath_string,
description: string
}
}
}
description: string,
},
},
},
},
$defs: {
tag: {
Expand All @@ -104,9 +103,9 @@ function viewdef_schema(for_tests = false) {
additionalProperties: false,
properties: {
name: string,
value: string
}
}
value: string,
},
},
},
column: {
type: array,
Expand All @@ -121,9 +120,9 @@ function viewdef_schema(for_tests = false) {
collection: bool,
description: string,
type: string,
tag: $ref('tag')
}
}
tag: $ref('tag'),
},
},
},
select: {
type: array,
Expand All @@ -136,40 +135,41 @@ function viewdef_schema(for_tests = false) {
unionAll: $ref('select'),
forEach: fhirpath_string,
forEachOrNull: fhirpath_string,
select: $ref('select')
}
}
}
}
select: $ref('select'),
},
},
},
},
}

return schema
}


const ajv = new Ajv({ allErrors: true })

function validate_fhirpath(path) {
return fhirpath_validate(path)
}
ajv.addFormat('fhirpath-expression',{type: 'string', validate: validate_fhirpath})

let schema_test = viewdef_schema(true);
let schema_playground = viewdef_schema(false);
ajv.addFormat('fhirpath-expression', { type: 'string', validate: validate_fhirpath })

let schema_test = viewdef_schema(true)
let schema_playground = viewdef_schema(false)

export function validate(viewdef, for_tests = true) {
let validate_schema
if (for_tests) {
validate_schema = ajv.compile(schema_test);
validate_schema = ajv.compile(schema_test)
} else {
validate_schema = ajv.compile(schema_playground);
validate_schema = ajv.compile(schema_playground)
}
validate_schema(viewdef);
return validate_schema;
validate_schema(viewdef)
return validate_schema
}

export function errors(viewdef) {
const validate_schema = validate(viewdef);
return validate_schema.errors;
const validate_schema = validate(viewdef)
return validate_schema.errors
}

// console.log(errors({select: [{forEach: 'name'}]}))
7 changes: 6 additions & 1 deletion sof-js/tests/internal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ describe('internal tests', () => {
{
forEach: 'contact',
column: [{ name: 'contact_type', path: 'type' }],
select: [{ forEach: 'person', column: [{ name: 'name', path: 'name' }] }],
select: [
{
forEach: 'person',
column: [{ name: 'name', path: 'name' }],
},
],
},
],
}),
Expand Down
Loading

0 comments on commit 91f3bdd

Please sign in to comment.