-- file DBLoadImpl.mesa
-- created by Donahue, December 28, 1982 10:14 am
-- last edited by Donahue, December 30, 1982 8:37 am

DIRECTORY IO, Rope, DBView, DBLoad;

DBLoadImpl: PROGRAM IMPORTS IO, Rope, DBView EXPORTS DBLoad =
{ OPEN IO, Rope, DBView;
BadInput: ERROR = CODE;
ControlZ: CHARACTER = 032C;

CreateEntity: PUBLIC PROC[ s: IO.STREAM ] RETURNS[ ok: BOOLEAN ] = {
ENABLE BadInput => GOTO Quit;
ok ← TRUE;
SELECT s.GetChar[] FROM
'/ => {dName, eName: ROPE;
  d: Domain;
  dName ← ReadString[s, FALSE];
  d ← DeclareDomain[name: dName, version: Version[OldOnly]
         ! NotFound => { SkipThruCR[s]; GOTO Quit } ];
  eName ← ReadString[s];
  [] ← DBView.CreateEntity[d: d, name: eName ! NonUniqueEntityName =>
            { SkipThruCR[s]; GOTO Quit }] };
ENDCASE => ok ← FALSE;
SkipThruCR[ s ];
EXITS
Quit => RETURN[FALSE]; };

DestroyEntity: PUBLIC PROC[ s: IO.STREAM ] RETURNS[ ok: BOOLEAN ] = {
ENABLE BadInput => GOTO Quit;
ok ← TRUE;
SELECT s.GetChar[] FROM
'/ => {dName, eName: ROPE;
  d: Domain;
  entity: Entity;
  dName ← ReadString[s, FALSE];
  d ← DeclareDomain[name: dName, version: Version[OldOnly]
         ! NotFound => { SkipThruCR[s]; GOTO Quit } ];
  eName ← ReadString[s];
  entity ← GetEntityByName[d, eName ! NotFound =>
              { SkipThruCR[s]; GOTO Quit }];
  DBView.DestroyEntity[ entity ] };
ENDCASE => ok ← FALSE;
SkipThruCR[ s ];
EXITS
Quit => RETURN[FALSE]; };

CreateRelship: PUBLIC PROC[ s: IO.STREAM ] RETURNS[ ok: BOOLEAN ] = {
ENABLE BadInput => GOTO Quit;
ok ← TRUE;
SELECT s.GetChar[] FROM
'\\ =>
{ rName: ROPE;
 r: Relation;
 AttrList: AttributeValueList;
 rName ← ReadString[s, FALSE];
 r ← DeclareRelation[ name: rName, version: Version[OldOnly]
       ! NotFound => { SkipThruCR[s]; GOTO Quit } ];
 AttrList ← CollectAttr[ r, s ];
IF CheckExistingRelship[ r, AttrList ] = NIL THEN
  [] ← DBView.CreateRelship[ r, AttrList ]; };
ENDCASE => { SkipThruCR[s]; ok ← FALSE };
EXITS
Quit => RETURN[FALSE]; };

DestroyRelship: PUBLIC PROC[ s: IO.STREAM ] RETURNS[ ok: BOOLEAN ] = {
ENABLE BadInput => GOTO Quit;
ok ← TRUE;
SELECT s.GetChar[] FROM
'\\ =>
{ rName: ROPE;
 r: Relation;
 AttrList: AttributeValueList;
 relship: Relship;
 rName ← ReadString[s, FALSE];
 r ← DeclareRelation[ name: rName, version: Version[OldOnly]
       ! NotFound => { SkipThruCR[s]; GOTO Quit } ];
 AttrList ← CollectAttr[ r, s ];
 relship ← CheckExistingRelship[ r, AttrList ];
IF relship # NIL THEN DBView.DestroyRelship[ relship ]; };
ENDCASE => { SkipThruCR[s]; ok ← FALSE };
EXITS
Quit => RETURN[FALSE];};

CollectAttr: PROC[ r: Relation, s: IO.STREAM ] RETURNS[ attr: AttributeValueList ] = {
fieldName: ROPE;
field: Attribute;
valString: ROPE;
type: Entity;
val: Value;
attr ← NIL;
UNTIL (fieldName ← ReadName[s]) = NIL DO
field ← DeclareAttribute[r: r, name: fieldName, version: OldOnly
       ! NotFound => ERROR BadInput ];
type ← V2E[GetP[field, aTypeProp]];
valString ← ReadString[s, FALSE];
SELECT type FROM
IntType => { val ← I2V[ IO.GetInt[ IO.RIS[valString] ] ] };
StringType => { val ← S2V[ valString ] };
BoolType => { val ← B2V[ Rope.Equal[valString, "TRUE"] ] };
ENDCASE => { val ← DeclareEntity[ d: type, name: valString ] };
attr ← CONS[ AttributeValue[ field, val ], attr ]
ENDLOOP };

CheckExistingRelship: PROC[r: Relation, attr: AttributeValueList] RETURNS[relship: Relship] =
{ rs: RelshipSet = RelationSubset[ r, attr ];
relship ← IF rs # NIL THEN NextRelship[rs] ELSE NIL;
ReleaseRelshipSet[rs] };

ReadName: PROC[s: IO.STREAM] RETURNS[ROPE] =
-- Terminates on reading a ":" or a CR; returns NIL in latter case.
BEGIN
lastBreak: CHAR;
r: ROPE← s.GetRope[NameBreak, NoBreak];
NoBreak: BreakProc = CHECKED {RETURN[KeepGoing]};
NameBreak: BreakProc = CHECKED {
lastBreak ← c;
IF c = ControlZ THEN {SkipThruCR[s]; RETURN[StopAndTossChar]}
ELSE IF c = '\\ OR c = CR OR c = ': THEN RETURN[StopAndTossChar]
ELSE RETURN[KeepGoing] };
IF r = NIL THEN r ← ""; -- kluge
IF r.Length[]=0 THEN
IF lastBreak=': THEN ERROR BadInput ELSE RETURN[NIL]
ELSE RETURN[r]
END;

SkipThruCR: SAFE PROC[ s: IO.STREAM ] = CHECKED
{ c: CHARACTER; WHILE (c ← s.GetChar[]) # CR DO ENDLOOP };

ReadString: PROC[s: IO.STREAM, nonNull: BOOLEANTRUE] RETURNS[ROPE] =
-- Terminates on reading a "\"; may return a null string if find immediately.
-- Null string generates error if nonNull=TRUE.
BEGIN
r: ROPE← s.GetRope[NameBreak, NoBreak];
NoBreak: BreakProc = CHECKED {RETURN[KeepGoing]};
NameBreak: BreakProc = CHECKED {
IF c='\\ THEN RETURN[StopAndTossChar]
ELSE RETURN[KeepGoing] };
IF r=NIL THEN r← ""; -- kluge, i don't know why GetRope returns NIL
IF r.Length[]=0 AND nonNull THEN { SkipThruCR[s]; ERROR BadInput } ELSE RETURN[r]
END; }.