⍝ Test script for ddb:
⍝
⍝      test'ddb'            ⍝ run test: no news → good news.
⍝    1 test'ddb'            ⍝ run test, showing progress.

⍝---------------------------------------------------⍝ general tests:

    (ddb.remove'ddb test')/'Old file removed!'      ⍝ ensure file removed.

    defns←('name' 80 20)('age' 83)('shape' 83 3)    ⍝ field definitions.

    disp defns
┌→───────────┬────────┬────────────┐
│┌→───┬──┬──┐│┌→──┬──┐│┌→────┬──┬─┐│
││name│80│20│││age│83│││shape│83│3││
│└───→┴~─┴~─┘│└──→┴~─┘│└────→┴~─┴─┘│
└───────────→┴───────→┴───────────→┘

    {}'ddb test' ddb.create defns                   ⍝ create table (show size).

    disp ddb.defs 'ddb test'                        ⍝ field defs from table,
┌→───────────┬────────┬────────────┐
│┌→───┬──┬──┐│┌→──┬──┐│┌→────┬──┬─┐│
││name│80│20│││age│83│││shape│83│3││
│└───→┴~─┴~─┘│└──→┴~─┘│└────→┴~─┴─┘│
└───────────→┴───────→┴───────────→┘

    disp ddb.defs ddb.open 'ddb test'               ⍝ ... or table handle.
┌→───────────┬────────┬────────────┐
│┌→───┬──┬──┐│┌→──┬──┐│┌→────┬──┬─┐│
││name│80│20│││age│83│││shape│83│3││
│└───→┴~─┴~─┘│└──→┴~─┘│└────→┴~─┴─┘│
└───────────→┴───────→┴───────────→┘

    +'ddb test' ddb.append 'john' 56 (38 42 46)     ⍝ append row to table.
72

    block←(↑'pete' 'jessica')(55 23)(↑(44 32 34)(48 24 36))

    disp block                                      ⍝ block of rows.
┌→──────┬─────┬────────┐
│pete   │55 23│44 32 34│
│jessica↓     │48 24 36↓
└──────→┴~───→┴~──────→┘

    +'ddb test' ddb.append block                    ⍝ append block of rows.
120

    tab←ddb.open 'ddb test'                         ⍝ handle for table.

    tab ddb.get 'name'                              ⍝ get field from table.
john                
pete                
jessica             

    disp tab ddb.get 'name' 'age' 'shape'           ⍝ get all fields.
┌→───────────────────┬────────┬────────┐
│john                │        │38 42 46│
│pete                │56 55 23│44 32 34│
│jessica             ↓        │48 24 36↓
└───────────────────→┴~──────→┴~──────→┘

    disp tab ddb.get (1 1 1)('name' 'age' 'shape')  ⍝ test mask vector.
┌→───────────────────┬────────┬────────┐
│john                │        │38 42 46│
│pete                │56 55 23│44 32 34│
│jessica             ↓        │48 24 36↓
└───────────────────→┴~──────→┴~──────→┘

    disp tab ddb.get 1('name' 'age' 'shape')        ⍝ test mask scalar.
┌→───────────────────┬────────┬────────┐
│john                │        │38 42 46│
│pete                │56 55 23│44 32 34│
│jessica             ↓        │48 24 36↓
└───────────────────→┴~──────→┴~──────→┘

    {}⎕ex'tab'                                      ⍝ remove mapping handle.

    disp (ddb.open'ddb test')ddb.get'age' 'shape'   ⍝ use transient handle.
┌→───────┬────────┐
│        │38 42 46│
│56 55 23│44 32 34│
│        │48 24 36↓
└~──────→┴~──────→┘

    disp 'ddb test' ddb.get 'age' 'shape'           ⍝ use table name.
┌→───────┬────────┐
│        │38 42 46│
│56 55 23│44 32 34│
│        │48 24 36↓
└~──────→┴~──────→┘

    ⎕dr 'ddb test' ddb.put 'age' (88 77 21)         ⍝ replace age values.
83

    'ddb test' ddb.get 'age'                        ⍝ check update.
88 77 21

    tab←'w' ddb.open 'ddb test'                     ⍝ open table for write.

    jays←^/∨\'j'=tab ddb.get 'name'                 ⍝ names starting with 'j'.

    tab ddb.get jays 'shape'                        ⍝ shapes of     ..  ..
38 42 46
48 24 36

    +tab ddb.put jays 'age' (66 22)                 ⍝ replace selected ages.
66 22
     tab ddb.get 'age'                              ⍝ check update.
66 77 22

    +⎕ex'tab'                                       ⍝ release table.
1
    +'ddb test' ddb.retain jays                     ⍝ retain only j-names.
96
    'ddb test' ddb.get 'name'                       ⍝ compressed table.
john                
jessica             

    disp ddb.(get∘⊃¨∘defs∘⊃⍨∘⊂∘open)'ddb test'      ⍝ open and get all fields.
┌→───────────────────┬─────┬────────┐
│john                │66 22│38 42 46│
│jessica             ↓     │48 24 36↓
└───────────────────→┴~───→┴~──────→┘

    disp ddb.(get∘(⊃¨∘defs)⍨∘open)'ddb test'        ⍝ open and get all fields.
┌→───────────────────┬─────┬────────┐
│john                │66 22│38 42 46│
│jessica             ↓     │48 24 36↓
└───────────────────→┴~───→┴~──────→┘

    tab←'w'ddb.open 'ddb test'                      ⍝ reopen table for write.
                                                    ⍝ to check for demote probs,
    disp tab ddb.put 'age' 'shape'{⍺⍵}(,\2 3)⍴¨0    ⍝   set all numbers to 0.
┌→──┬─────┐
│0 0│0 0 0│
│   │0 0 0↓
└~─→┴~───→┘

    disp ddb.(get∘⊃¨∘defs∘⊃⍨∘⊂)tab                  ⍝ get all fields.
┌→───────────────────┬───┬─────┐
│john                │0 0│0 0 0│
│jessica             ↓   │0 0 0↓
└───────────────────→┴~─→┴~───→┘

    {}⎕ex'tab'                                      ⍝ release table.

    get←ddb.((open'ddb test')∘get)                  ⍝ bind handle with get fn.

    disp get(∨/'o'=get'name')('age' 'shape')        ⍝ compound selection.
┌→┬─────┐
│0│0 0 0↓
└→┴~───→┘

    {}⎕ex'get'                                      ⍝ release and

    +ddb.remove 'ddb test'                          ⍝   remove table.
1

⍝---------------------------------------------------⍝ test single field table:

    tab←'ddb test' ddb.create 'single' 323          ⍝ create table.
    +tab ddb.append ⍳10                             ⍝ append some values
68
    tab ddb.get 'single'                            ⍝ retrieve values.
1 2 3 4 5 6 7 8 9 10
    +ddb.remove tab                                 ⍝ remove table.
1

⍝---------------------------------------------------⍝ test higher ranks (simple)

    defs←('vec' 83)('mat' 83 3)('cube' 83 3 4)('hype' 83 3 4 5)

    tab←'ddb test' ddb.create defs                  ⍝ create table.

    +tab ddb.append (,\2 3 4 5)⍴¨⊂⍳120              ⍝ append some values.
228

    disp ddb.(get∘(⊃¨)∘defs)⍨tab                    ⍝ retrieve values.
┌→──┬─────┬───────────┬───────────────────┐
│   │     │           │  1   2   3   4   5│
│   │     │           │  6   7   8   9  10│
│   │     │           │ 11  12  13  14  15│
│   │     │           │ 16  17  18  19  20│
│   │     │           │                   │
│   │     │           │ 21  22  23  24  25│
│   │     │           │ 26  27  28  29  30│
│   │     │           │ 31  32  33  34  35│
│   │     │           │ 36  37  38  39  40│
│   │     │           │                   │
│   │     │           │ 41  42  43  44  45│
│   │     │ 1  2  3  4│ 46  47  48  49  50│
│   │     │ 5  6  7  8│ 51  52  53  54  55│
│   │     │ 9 10 11 12│ 56  57  58  59  60│
│1 2│1 2 3│           │                   │
│   │4 5 6│13 14 15 16│                   │
│   │     │17 18 19 20│ 61  62  63  64  65│
│   │     │21 22 23 24│ 66  67  68  69  70│
│   │     │           │ 71  72  73  74  75│
│   │     │           │ 76  77  78  79  80│
│   │     │           │                   │
│   │     │           │ 81  82  83  84  85│
│   │     │           │ 86  87  88  89  90│
│   │     │           │ 91  92  93  94  95│
│   │     │           │ 96  97  98  99 100│
│   │     │           │                   │
│   │     │           │101 102 103 104 105│
│   │     │           │106 107 108 109 110│
│   │     │           │111 112 113 114 115│
│   │     ↓           ⍒116 117 118 119 120⍒
└~─→┴~───→┴~─────────→┴~─────────────────→┘

    +ddb.remove tab                                 ⍝ remove table.
1

⍝---------------------------------------------------⍝ test higher ranks (nested)

    defs←('vecs' 83 ¯3)('mats' 83 ¯3 ¯4)('cubes' 83 ¯3 ¯4 ¯5)

    tab←'ddb test' ddb.create defs                  ⍝ create table.

    vals ← {+⌿¨1⊂[⎕io]⍵}¨1↓(,\2 3 4 5)⍴¨⊂⍳×/2 3 4 5

    +tab ddb.append vals                            ⍝ append some values.
243

    disp tab ddb.get tab.names                      ⍝ retrieve values.
┌→────────────┬────────────────────────┬────────────────────────────────────┐
│             │                        │┌→─────────────┬───────────────────┐│
│             │                        ││ 1  2  3  4  5│ 61  62  63  64  65││
│             │                        ││ 6  7  8  9 10│ 66  67  68  69  70││
│             │                        ││11 12 13 14 15│ 71  72  73  74  75││
│             │                        ││16 17 18 19 20│ 76  77  78  79  80││
│             │┌→─────────┬───────────┐││              │                   ││
│┌→────┬─────┐││1  2  3  4│13 14 15 16│││21 22 23 24 25│ 81  82  83  84  85││
││1 2 3│4 5 6│││5  6  7  8│17 18 19 20│││26 27 28 29 30│ 86  87  88  89  90││
│└~───→┴~───→┘││9 10 11 12↓21 22 23 24↓││31 32 33 34 35│ 91  92  93  94  95││
│             │└~────────→┴~─────────→┘││36 37 38 39 40│ 96  97  98  99 100││
│             │                        ││              │                   ││
│             │                        ││41 42 43 44 45│101 102 103 104 105││
│             │                        ││46 47 48 49 50│106 107 108 109 110││
│             │                        ││51 52 53 54 55│111 112 113 114 115││
│             │                        ││56 57 58 59 60⍒116 117 118 119 120⍒│
│             │                        │└~────────────→┴~─────────────────→┘│
└────────────→┴───────────────────────→┴───────────────────────────────────→┘

    +ddb.remove tab                                 ⍝ remove table.
1

⍝---------------------------------------------------⍝ test char vex:

    defs←('vex' 80 ¯10)('mat' 80 10)                ⍝ matrix and vectors.

    tab←'ddb test' ddb.create defs                  ⍝ create table.

    vex←'one' 'two' 'and  three'                    ⍝ data vectors.
    mat←↑vex

    +tab ddb.append vex mat                         ⍝ append some values.
105
    disp tab ddb.get 'mat' 'vex'                    ⍝ retrieve values.
┌→─────────┬────────────────────┐
│one       │┌→──┬───┬──────────┐│
│two       ││one│two│and  three││
│and  three↓└──→┴──→┴─────────→┘│
└─────────→┴───────────────────→┘

    ⎕dr tab ddb.put 'vex' ('un' 'deux' 'trois')     ⍝ replace values.
326
    disp tab ddb.get tab.names                      ⍝ retrieve new values.
┌→──────────────┬──────────┐
│┌→─┬────┬─────┐│one       │
││un│deux│trois││two       │
│└─→┴───→┴────→┘│and  three↓
└──────────────→┴─────────→┘

    +ddb.remove tab                                 ⍝ remove table.
1

⍝---------------------------------------------------⍝ test numeric vex:

    defs←('vex' 83 ¯4)('mat' 83 4)                  ⍝ matrix and vectors.

    tab←'ddb test' ddb.create defs                  ⍝ create table.

    vex←⍳¨⍳4                                        ⍝ data vectors.
    mat←↑vex

    +tab ddb.append vex mat                         ⍝ append some values.
81
    disp tab ddb.get 'mat' 'vex'                    ⍝ retrieve values.
┌→──────┬─────────────────────┐
│1 0 0 0│┌→┬───┬─────┬───────┐│
│1 2 0 0││1│1 2│1 2 3│1 2 3 4││
│1 2 3 0│└→┴~─→┴~───→┴~─────→┘│
│1 2 3 4↓                     │
└~─────→┴────────────────────→┘

    ⎕dr tab ddb.put (0 1 0 1) 'vex' (↓11×2 2⍴⍳4)    ⍝ replace some values.
326
    disp tab ddb.get tab.names                      ⍝ retrieve new values.
┌→────────────────────┬───────┐
│┌→┬─────┬─────┬─────┐│1 0 0 0│
││1│11 22│1 2 3│33 44││1 2 0 0│
│└→┴~───→┴~───→┴~───→┘│1 2 3 0│
│                     │1 2 3 4↓
└────────────────────→┴~─────→┘

    +ddb.remove tab                                 ⍝ remove table.
1
⍝---------------------------------------------------⍝ test nested cases

    mats ← {⍵++\(¯1+⍳⍴⍵)*2}{⍵ ⍵⍴⍳⍵×⍵}¨⍳5            ⍝ nested matrices.

    disp mats
┌→┬───┬────────┬───────────┬──────────────┐
│ │   │        │15 16 17 18│31 32 33 34 35│
│ │2 3│ 6  7  8│19 20 21 22│36 37 38 39 40│
│1│4 5│ 9 10 11│23 24 25 26│41 42 43 44 45│
│ │   │12 13 14│27 28 29 30│46 47 48 49 50│
│ ↓   ↓        ↓           ↓51 52 53 54 55↓
└→┴~─→┴~──────→┴~─────────→┴~────────────→┘

⍝---------------------------------------------------⍝ simple simple

    tab←'ddb test' ddb.create 'mats' 83 5 5

    tab ddb.append ↑mats
175
    disp tab ddb.get 'mats'
 1  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
              
 2  3  0  0  0
 4  5  0  0  0
 0  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
              
 6  7  8  0  0
 9 10 11  0  0
12 13 14  0  0
 0  0  0  0  0
 0  0  0  0  0
              
15 16 17 18  0
19 20 21 22  0
23 24 25 26  0
27 28 29 30  0
 0  0  0  0  0
              
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
51 52 53 54 55

    (↑mats) ≡ tab ddb.get 'mats'
1
    {}⎕ex'tab'

    ddb.remove'ddb test'
1

⍝---------------------------------------------------⍝ simple nested

    tab←'ddb test' ddb.create 'mats' 83 5 ¯5

    tab ddb.append mats
182
    disp tab ddb.get 'mats'
┌→┬───┬────────┬───────────┬──────────────┐
│1│2 3│ 6  7  8│15 16 17 18│31 32 33 34 35│
│0│4 5│ 9 10 11│19 20 21 22│36 37 38 39 40│
│0│0 0│12 13 14│23 24 25 26│41 42 43 44 45│
│0│0 0│ 0  0  0│27 28 29 30│46 47 48 49 50│
│0↓0 0↓ 0  0  0↓ 0  0  0  0↓51 52 53 54 55↓
└→┴~─→┴~──────→┴~─────────→┴~────────────→┘

    (5↑[1]¨mats) ≡ tab ddb.get 'mats'
1
    {}⎕ex'tab'

    ddb.remove'ddb test'
1

⍝---------------------------------------------------⍝ nested simple

    tab←'ddb test' ddb.create 'mats' 83 ¯5 5

    tab ddb.append mats
182
    disp tab ddb.get 'mats'
┌→────────┬─────────┬────────────┬─────────────┬──────────────┐
│         │         │            │15 16 17 18 0│31 32 33 34 35│
│         │2 3 0 0 0│ 6  7  8 0 0│19 20 21 22 0│36 37 38 39 40│
│1 0 0 0 0│4 5 0 0 0│ 9 10 11 0 0│23 24 25 26 0│41 42 43 44 45│
│         │         │12 13 14 0 0│27 28 29 30 0│46 47 48 49 50│
│         ↓         ↓            ↓             ↓51 52 53 54 55↓
└~───────→┴~───────→┴~──────────→┴~───────────→┴~────────────→┘

    (5↑[2]¨mats) ≡ tab ddb.get 'mats'
1
    {}⎕ex'tab'

    ddb.remove'ddb test'
1

⍝---------------------------------------------------⍝ nested nested

    tab←'ddb test' ddb.create 'mats' 83 ¯5 ¯5

    tab ddb.append mats
189
    disp tab ddb.get 'mats'
┌→┬───┬────────┬───────────┬──────────────┐
│ │   │        │15 16 17 18│31 32 33 34 35│
│ │2 3│ 6  7  8│19 20 21 22│36 37 38 39 40│
│1│4 5│ 9 10 11│23 24 25 26│41 42 43 44 45│
│ │   │12 13 14│27 28 29 30│46 47 48 49 50│
│ ↓   ↓        ↓           ↓51 52 53 54 55↓
└→┴~─→┴~──────→┴~─────────→┴~────────────→┘

    mats ≡ tab ddb.get 'mats'
1
    {}⎕ex'tab'

    ddb.remove'ddb test'
1

⍝---------------------------------------------------⍝ test large fields:

    defs←('nest' 80 ¯2 ¯300 ¯2)('simp' 80 2 300 2)  ⍝ nested and simple.

    tab←'ddb test' ddb.create defs                  ⍝ create table.

    nest←3⍴⊂1 11 1⍴'hello world'                    ⍝ nested values.
    simp←↑nest                                      ⍝ simple values.

    +tab ddb.append nest simp                       ⍝ append values.
9624

    nest≡tab ddb.get'nest'                          ⍝ check nested.
1
    (tab ddb.get'simp')≡(3,¯3↑⊃⌽ddb.defs tab)↑simp  ⍝ check simple.
1
    nest←3⍴⊂2 300 2⍴'hello world'                   ⍝ full nested values.
    simp←↑nest                                      ⍝ full simple values.

    +tab ddb.append nest simp                       ⍝ check full data.
16842
    +ddb.remove tab                                 ⍝ remove table.
1

⍝---------------------------------------------------⍝ test errors:

    defs←('nest' 80 ¯5)('simp' 80 5)                ⍝ nested and simple fields.

    nest←'hello' 'world'                            ⍝ nested values.
    simp←↑nest                                      ⍝ simple values.

    ddb.open 'ddb test'                             ⍝ non-existent table.
22::BAD TABLE NAME

    'ddb test' ddb.create defs,⊂'bad' 84            ⍝ bad field type.
11::BAD FIELD TYPE

    tab←'ddb test' ddb.create defs                  ⍝ create good table.

    'ddb test' ddb.create defs                      ⍝ table already exists.
22::BAD TABLE NAME

    +tab ddb.append nest simp                       ⍝ append values.
66
    tab ddb.get 'Nest'                              ⍝ mis-spelled field name.
6::BAD NAME "Nest" 

    tab ddb.append 'too' 'many' 'fields'            ⍝ wrong number of fields.
5::LENGTH ERROR

    tab ddb.append nest 's'                         ⍝ scalar val for vector fld.
4::BAD RANK in "simp"

    tab ddb.append (↑,↓nest) simp                   ⍝ matrix val for vector fld.
4::BAD RANK in "nest"

    tab ddb.append 'vect' (2 3)                     ⍝ numeric val for char fld.
11::BAD TYPE in "simp"

    tab ddb.append 'vect' 'too long'                ⍝ data truncated.
10::BAD SIZE in "simp"

    tab ddb.append 'vect' (simp simp)               ⍝ nested val for char fld.
11::BAD DEPTH in "simp"

    tab ddb.get (1 0 1) tab.names                   ⍝ wrong length mask.
5::LENGTH ERROR

    {}⎕ex'tab'                                      ⍝ release and
    tab←ddb.open 'ddb test'                         ⍝ reopen table (read-only).

    tab ddb.append nest simp                        ⍝ attempt append.
19::READ-ONLY TABLE

    tab ddb.put nest simp                           ⍝ attempt put.
19::READ-ONLY TABLE

    tab ddb.retain 0 0                              ⍝ attempt to remove rows.
19::READ-ONLY TABLE
                                                    ⍝ try remove using file name
    ddb.remove 'ddb test'                           ⍝ while handle "tab" exists.
19::TABLE OPEN

    {}⎕ex'tab'                                      ⍝ expunge handle, then
    +ddb.remove'ddb test'                           ⍝ remove table using name.
1
    ⍬≡⎕nnums                                        ⍝ check no file ties.
1

⍝---------------------------------------------------⍝ regression tests.

      {}'ddb test'ddb.create'prob' 80 ¯10
      'ddb test'ddb.append 'reopen' 'failed'
55
      disp 'ddb test'ddb.get'prob'
┌→─────┬──────┐
│reopen│failed│
└─────→┴─────→┘
    +ddb.remove'ddb test'
1

    tab←'ddb test'ddb.create'ret' 80 3          ⍝ Access error corrupted table.

    tab ddb.append↑'tab' 'not' 'bad'            ⍝ append three rows.
36
    'ddb test'ddb.retain 1 0 1                  ⍝ table already open: fails.
19::TABLE OPEN

    tab ddb.get'ret'                            ⍝ table not changed.
tab
not
bad

    tab ddb.retain 0 1 1                        ⍝ OK if handle used.
33

    tab ddb.get'ret'                            ⍝ retain succeeds.
not
bad

    +ddb.remove'ddb test'{⍺}⎕ex'tab'            ⍝ remove handle and table.
1

⍝---------------------------------------------------⍝ finished!
⍝   
⍝   Back to: Contents