- Best practicies
- BS video library (meetup records)
- Learning materials
- SNOMED and Snowstorm
- React Native tips
- kubectl/k8s cheat sheet
- Tutorials
// To see all the requests in the chrome Dev tools in the network tab.
XMLHttpRequest = GLOBAL.originalXMLHttpRequest ?
GLOBAL.originalXMLHttpRequest :
GLOBAL.XMLHttpRequest;
Don't forget to remove it before pushing!
xcrun simctl openurl booted link-goes-here
There's a module.js
, for example:
export const calculate = (a, b) => a + b;
How to mock it?
Mock a module with jest.mock
Common approach is to use jest.mock
to automatically set all exports of a module to the Mock Function.
import * as module from "./module";
jest.mock("./module.js");
test("calls module.calculate", () => {
module.calculate(1, 2);
expect(module.calculate).toHaveBeenCalledWith(1, 2);
});
Mock a function with jest.spyOn + mockImplementation
You can mock a function then restore the original implementation:
import * as module from "./module";
test("calls math.calculate", () => {
const calculateMock = jest.spyOn(module, "calculate");
calculateMock.mockImplementation(() => 42);
expect(module.calculate(1, 2)).toEqual(42);
calculateMock.mockRestore();
expect(calculateMock).toHaveBeenCalledWith(1, 2);
});
sudo xcode-select --switch /Applications/Xcode.app
Good tutorial how to add custom fonts: https://medium.com/@mehran.khan/ultimate-guide-to-use-custom-fonts-in-react-native-77fcdf859cf4
const sleepMeasurements: (number | undefined)[]
const filteredMeasurements = sleepMeasurements.filter((v) => v !== undefined)) // will be (number | undefined)[]
// now use type predicate
const filteredMeasurements = sleepMeasurements.filter((v): v is number => v !== undefined)) // will be (number)[]
You can read more here User-Defined Type Guards
type Some = ['A', 'B', 'C']
type AnyOfSome = Some[number] // type AnyOfSome = 'A' | 'B' | 'C'
Aidbox accepts both id and _id search params. But according to spec https://www.hl7.org/fhir/search.html the only valid param is _id
. This is causing problems with access policies and may cause potential issues in future.
So it'd be better to always use "_id" instead of "id" search params on frontend as well as backend part of an app.
Mistakenly we use "string" as SearchParameter.type for some attributes with type "text", but it leads to serious issues, because FHIR search works as full-text search with substring partial matching. Example: SearchParameter User.email must have "token" type.
See FHIR Search specification about how different SearchParameter types work.
If you need to mutate the original resource before/after save - use the custom operation to do it. It has some benefits:
- Version id won't be increased twice
- Easier to test
- You can make transactional queries: all or nothing
Using display
in references is a bad idea because it is denormalization and the original title can be changed so that you will need to actualize it. Actualization is a very difficult process and has some drawbacks:
- It changes version ID --- our UI usually can't handle version mismatch
- It takes time - you need to go through the database and find all references
- It can't work with other subscriptions (because actualization is a best practice for subscriptions)
If you don't want to have a headache with these problems, consider using _include
every time to get the actual value.
User resources must contain only credentials and links to appropriate Patient/Practitioner.
Practitioners can be used for admin roles and other roles (see FHIR spec for details).
Using references to User
should be forbidden because makes a potential vulnerability (because of _include/_assoc that is not forbidden by default). Instead of this, always make references to appropriate Patient/Practitioner.
They always should have additionalProperties: false
for search params to forbid passing _assoc/_include/_revinclude
.
Using access_policy
argument in the customer operation makes it difficult to maintain policies for different roles
In many countries there is a Daylight saving time shifting. While generating future time ranges it is necessary to consider such shiftings.
In Israel, DST->STD in 2020 is occuring on October 25. For example, there is a task to generate a datetime range from October 20 for 7 days with the 1 day step.
This code will prevent to an error starting from October 25, because datetime.timedelta
doesn't consider the DST->STD time shift:
while current_date < end_date:
# datetime.timedelta doesn't consider time shifting
current_date += datetime.timedelta(days=1)
To fix this use DST shift adding/subtraction:
next_date = current_date + datetime.timedelta(days=1)
# Normalize datetime to the local timezone considering DST/STD
next_date = next_date.tzinfo.normalize(next_date)
# Add/subtract DST (3600 seconds) /STD (0 seconds) time shift
next_date = next_date + (current.dst() - next_date.dst())
Do not forget to cover this logic with tests by checking that all time values (hours, minutes, etc) in your range are equal and the range parts quantity is correct
Bad
organization = sdk.client.resource(
"Organization",
name="beda.software",
active=False,
someAttribute="attribute value"
)
Good
organization = sdk.client.resource(
"Organization",
**{"name": "beda.software", "active": False, "someAttribute": "attribute value"}
)
Bad
"Encounter.hasInvoice": {
"name": "hasInvoice",
#...
},
Good
"Encounter.has-invoice": {
"name": "has-invoice",
#...
},
Bad
@sdk.operation(["GET"], ["Resource", {"name": "resource_id"}, "$operation_with_resource"])
or
@sdk.operation(["GET"], ["Resource", {"name": "resourceId"}, "$operationWithResource"])
Good
@sdk.operation(["GET"], ["Resource", {"name": "resource-id"}, "$operation-with-resource"])
Use module path the function is looked up in (it might be different from the module that defines the function). Official unittest documentation has a detailed description
We can use Aidbox REST Console to run SQL queries.
Reference: Postgres JSON Functions and Operators
Updated resource example (the filter attribute to be deleted):
id: d6fdcc6a-4513-45df-8f06-797a4727ce7f
resourceType: MedicalRule
sourceQuery:
id: Source
type: batch
entry:
- request:
url: $snowstorm
method: POST
resource:
ecl: '<< 372586001 |Hypotensive agent (substance)|'
filter: '...' // <- to be deleted
resourceType: SnowstormRequest
Migration SQL query (for all resources of this type):
update medicalrule
set resource = jsonb_set(
resource,
'{sourceQuery,entry,0,resource}',
(resource #> '{sourceQuery,entry,0,resource}')- 'filter'
)
"Condition.property": {
"path": ["property"],
"resource": {"resourceType": "Entity", "id": "Condition"},
"extensionUrl": "http://beda.software/fhir-extensions/condition-property",
"schema": {"type": "object"},
},
It is better to return Exception or HTTPError in form of OperationOutcome resource.
You need fhirpy or aidboxpy version 1.3.0 or higher to import OperationOutcome. You need aidbox-python-sdk to enable sdk operations return relevant HTTPError if OperationOutcome exception raised.
Usage example:
from app.sdk import sdk
from fhirpy.base.exceptions import OperationOutcome, IssueType, IssueSeverity
@sdk.operation(["POST"], ["Observation", "$create"], )
async def observation_custom_create(operation, request):
try:
observation_data = request["resource"]["observation_data"]
except KeyError as e:
error_text = f"Attribute: {str(e)} is required"
raise OperationOutcome(reason=error_text, code=IssueType.required.value, severity=IssueSeverity.error.value)
docker-compose up -d devbox-db
cat backup.dump | docker exec -i environment_devbox-db_1 pg_restore -d devbox
Crash with watching hidden files
https://github.com/facebook/create-react-app/pull/10706/files
curl https://raw.githubusercontent.com/facebook/create-react-app/a3dd649530f4c0c305fc183842399c9d36ecf97f/packages/react-dev-utils/ignoredFiles.js > node_modules/react-dev-utils/ignoredFiles.js
curl https://raw.githubusercontent.com/facebook/create-react-app/a3dd649530f4c0c305fc183842399c9d36ecf97f/packages/react-dev-utils/ignoredFiles.js > ./node_modules/react-scripts/node_modules/react-dev-utils/ignoredFiles.js