Source-control-storable database.
A text-based data format that is "just markdown". It is nearly a strict subset of CommonMark (version 0.31.2) with the Pandoc pipe tables extension.
-*- mode: markdown -*-
vim: set filetype=markdown tabstop=2 shiftwidth=2 formatoptions+=cn expandtab
# hospital
ACME hospital records. Distribution is expressly prohibited outside the
organization by applicable law.
## people
This table houses **all** the people in the database.
|person_id|firstname|lastname|birth-year|birth-month|birth-day|
|-:|-|-|-|-:|-:|-:|-:|
|1|Daniel|Haskin|1901|01|01|
|2|Joshua|Melburn|1982|04|06|
|3|Fay|Bingham|2022|07|15|
|4|Jordan|Slinger|1995|03|28|
|5|Bo|Kent|1951|09|03|
## departments
A root list of department entities.
|did|name|slug|
|-:|-|:-|
|1|Podiatry|pod_dept|
|2|Pediatric Medicine|ped_dept|
## doctors
A *many-to-one* relation between doctors and departments.
|doctor_id|person_id|department_id|
|-:|-:|-:|
|1|2|2|
|2|5|2|
## patients
A *many-to-many* relation between doctors and patients.
|patient_id|person_id|doctor_id|
|-:|-:|-:|
|1|1|1|
|2|5|1|
|3|3|2|
|4|3|1|
Should look like this:
-- mode: markdown -- vim: set filetype=markdown tabstop=2 shiftwidth=2 formatoptions+=cn expandtab
ACME hospital records. Distribution is expressly prohibited outside the organization by applicable law.
This table houses all the people in the database.
|person_id|firstname|lastname|birth-year|birth-month|birth-day| |-:|-|-|-|-:|-:|-:|-:| |1|Daniel|Haskin|1901|01|01| |2|Joshua|Melburn|1982|04|06| |3|Fay|Bingham|2022|07|15| |4|Jordan|Slinger|1995|03|28| |5|Bo|Kent|1951|09|03|
A root list of department entities.
did name slug 1 Podiatry pod_dept 2 Pediatric Medicine ped_dept A many-to-one relation between doctors and departments.
doctor_id person_id department_id 1 2 2 2 5 2 A many-to-many relation between doctors and patients.
patient_id person_id doctor_id 1 1 1 2 5 1 3 3 2 4 3 1
-
Be a first-class citizen within a code SCM repository. Therefore, be text-based way to record and manipulate data.
-
Support most "normal" SQL operations, particularly joins.
-
Support accurate recording of JSON data types within record fields.
-
Support whole-column types (rather than field-specific types).
-
Please the eye.
-
Follow the principle of least-surprise.
-
Don't make developers learn a new format.
-
Support easy, single-character-lookahead parsing.
-
Support comments and descriptions.
-
Support the Lisp symbol type.
- No need to support all of SQL.
- No stored procedures
- No non-nullable columns
It's just a subset of markdown as described above. Here is that subset:
Everything is line-based. Lines are separated by one carriage return or one newline character or one CR followed by one LF. This is called a "line separation".
Comments are written as they would have to be in markdown:
<!-- Like this -->.
Each document starts with a single hash followed by a space (# ). What follows
thereafter is the database name until a line separation is found.
An optional set of lines may be present that do not start with either a pipe or a hash character. These lines will be collected as a multi-line string comprising the database description.
A database consists of zero or more tables.
A table has a name, a description, column names within a header, a columns type line, and zero or more rows. If there are zero rows, there must still be types and headers lines.
Each table starts with a line starting with two hashes followed by a space (## ). What follows thereafter is the table name until a line separation is found.
An optional set of lines may be present that do not start with either a pipe or a hash character. These lines will be collected as a multi-line string comprising the table description.
Thereafter, there MUST be a line starting with a pipe character (|). This line
is a pipe-separated list of column names in the table. Spaces are not trimmed or
removed; all characters between the pipes are taken literally as the table name.
The line must end with a pipe character followed by a line separation.
The next line is the dash line. It specifies the types that will be in different columns. It should start with the pipe character and have just as many pipe-separated fields as the table header. Each field MUST be one of the following:
-
The character
-as a string indicator. This indicates the column is a string. -
:-as an atom or symbol character. This indicates the column is a keyword, symbol, atom, or string, in that order, if the parsing language has a concept of one of these. -
-:means the field contains a number, as parsed like JSON. -
:-:means the field contains a boolean value oftrueorfalse.
As previously stated, each field must be separated by others via the pipe character. The line must end with a pipe character just before the line separation.
Each subsequent line must start with a pipe. It must contain as many pipe-separated fields as the header and table type lines. It must end with a pipe before the line separation. Fields in the JSON number columns or JSON boolean columns must conform to that spec during parsing. Empty fields are always allowed by the spec, and signify a JSON-like null value.
Strings must not contain non-printables, tabs, or line separation characters.
They support backslash escaping of any ASCII punctuation character (to be
conformant with CommonMark), \a for alarm, \b for backspace, \f for form
feed, \n for line feed, \r for carriage return, \v for vertical tab, \t
for tab, and \uXXXX for 16-bit unicode character encoding. In particular,
dashes, colons, and pipes MUST be escaped. A single unescaped dash (-) in the
table cell lines indicates an empty string. All characters between the pipes of
the cell are considered part of the string; there is no trimming, whitespace or
otherwise. From an SQL perspective, all columns (even the first one) are
considered nullable, at least for the purposes of the serialization format.
Keywords are serialized just as strings are, except that they indicate a keyword, atom, or symbol. This string "means something".
Just like JSON numbers.
Just like JSON booleans.
cr = %0d
lf = %0a
line-sep = [cr] lf
pipe = %7c
dash = %2d
colon = %3a
hash = %23
space = %20
backslash = %5c
ascii-punct = %21 - %2f
/ %3a - %40
/ %5b - %60
/ %7b - %7e
nonzero-digit = %31 - %39
zero = %30
digit = zero / nonzero-digit
point = %2e
exp = %45 ; E
/ %65 ; e
integer = zero
/ [dash] nonzero-digit *digit
number = integer [point *digit] [exp integer]
hex = %30 - %39 ; digits
/ %41 - %46 ; A-F
escaped = %61 ; a (alarm/bell)
/ %62 ; b (backspace)
/ %6e ; n (newline)
/ %76 ; v (vertical tab)
/ %74 ; t (tab)
/ %75 4hex ; u (unicode escape)
/ ascii-punct
unescaped-char = %32 - %2c ; Up to dash
/ %2e - %39 ; Past dash, up to colon
/ %3b - %5b ; Past colon, up to backslash
/ %5d - %7b ; Past backslash, up to pipe
/ %7d - %ff ; Past pipe
string-char = backslash escaped
/ unescaped-char
nonempty-string = 1*string-char
empty-string = dash
string = nonempty-string
/ empty-string
boolean = "true"
/ "false"
non-eol = %00 - %09 ; Up to line feed
/ %0b - %0c ; Past line feed, up to carriage return
/ %0e - %ff ; Past carriage return
description-start = %00 - %09 ; Up to line feed
/ %0b - %0c ; Past line feed, up to carriage return
/ %0e - %22 ; Past carriage return, up to hash
/ %24 - %7b ; Past hash, up to pipe
/ %7d - %ff ; Past pipe
description-line = *1( description-start *non-eol ) line-sep
description = *description-line
column-name = nonempty-string
table-header = pipe 1*(column-name pipe) line-sep
column-type-string = dash
column-type-keyword = colon dash
column-type-boolean = colon dash colon
column-type-number = dash colon
column-type = column-type-string
/ column-type-keyword
/ column-type-boolean
/ column-type-number
table-typespec = pipe 1*(column-type pipe) line-sep
field-data = *1( string
/ keyword
/ number
/ boolean )
table-record = pipe 1*(field-data pipe) line-sep
table-name = 1*non-eol
table-title = hash hash space table-name line-sep
table-description = description
table-data = table-header table-typespec *table-record
table = table-title table-description table-data
database-name = 1*non-eol
database-title = hash space database-name line-sep
database-description = description
database = database-title database-description *table