;---------- Contrato "NBDC-SONAE" Fev.96 --------------------------------------- ; Copyright INESC / SONAE, 1996 ; Autor: jno ;------------------------------------------------------------------------------- TYPE ; atomic Id = STR; Key = STR; At = STR; Val = STR; ClId = STR; Db = Id -> X; X = Ent | Rel; Ent :: F: Key -> Tuple; Tuple = At -> Val; Rel :: R: XTuple-set; XTuple :: K: FKTuple A: Tuple; FKTuple = Id -> Key; ; temporal stuff TDb = Id -> TX; TX = TEnt | TRel; TEnt :: F: Key -> TTuple; TTuple = Dat -> Tuple; TRel :: R: TXTuple-set; TXTuple :: T: Dat K: (Id -> Key) A: (At -> Val); ; temporal and atemporal stuff XTX = Ent | Rel | TEnt | TRel; SONAE :: BDC: TDb D: Db C: (ClId -> Cliente) T: Dat; Cliente :: LD: Dat B: Db; ENDTYPE ;------- but~oes ----------------------------------------------- vv() = sh("vi x.cam"); v() = vi("x.cam"); ;------- ac,~oes ----------------------------------------------- FUNC HELP():SYM RETURN dumpTupSet({ [ "Comando"->"HELP", "Descricao" -> "Funcionalidade" ], [ "Comando"->"INIT", "Descricao"->"Arranque" ], [ "Comando"->"BDCSCHEMA", "Descricao" -> "Esquema da BDC" ], [ "Comando"->"BDCSETDATE", "P1" -> "Dat", "Descricao" -> "Actualiza data" ], [ "Comando"->"BDCSCHEMA", "Descricao"->"Esquema da BDC" ], [ "Comando"->"BDCADDENT", "P1"->"Id", "P2"->"Key", "P3"->"Dat", "P4"->"Tuple", "Descricao"->"Acrescenta entidade `a BDC" ], [ "Comando"->"BDCADDREL", "P1"->"Id", "P2"->"Dat", "P3"->"Id->Key", "P4"->"Tuple", "Descricao"->"Acrescenta relacionamento `a BDC" ], [ "Comando"->"BDCRULES", "Descricao"->"*** experiemental ***" ], [ "Comando"->"BDCDELENT", "P1"->"Id", "P2"->"Key", "P3"->"Dat", "Descricao"->"*** experiemental ***" ], [ "Comando"->"BDCHIST", "P1"->"Id", "Descricao"->"Historico de" ], [ "Comando"->"BDCSNAP", "P1"->"Id", "P2"->"Dat", "Descricao"->"'Snapshot' na BDC de" ], [ "Comando"->"DUMP", "P1"->"STR", "Descricao"->"'Dump' da BDC ou Cliente" ], [ "Comando"->"CLISTAT", "Descricao"->"Estado dos Clientes" ], [ "Comando"->"CLIBACKLOG", "P1"->"ClId", "Descricao"->"Desfazamento de Cliente" ], [ "Comando"->"CLIUPDATE", "P1"->"ClId", "Descricao"->"Difusao para Cliente" ], [ "Comando"->"CLISNAP", "P2"->"Id", "P1"->"ClId", "Descricao"->"Consulta de E/R em Cliente" ], [ ] }); FUNC CLISTAT():SYM RETURN let (cf=C(sonae), r={ [ "Cliente" -> i, "Ultima Difusao" -> Dat2str(LD(cf[i])) ] | i <- dom(cf) }) in dumpTupSet(r U { [ "Data actual" -> Dat2str(T(sonae)) ]}); FUNC BDCRULES():SYM RETURN dumpTupSet({ [ "Operacao" -> "ACTIVAARTIGO", "Parametro" -> "a", "Ocorre" -> ">=1", "FK" -> "#ARTIGO", "Rel" -> "GAMA LOJA" ], [ "Operacao" -> "ACTIVAARTIGO", "Parametro" -> "a", "Ocorre" -> ">=1", "FK" -> "#ARTIGO", "Rel" -> "UNIDADE FORNECIMENTO" ], [ "Operacao" -> "ELIMINAARTIGO", "Parametro" -> "a", "Ocorre" -> "0", "FK" -> "#ARTIGO", "Rel" -> "GAMA LOJA" ], [ "Operacao" -> "ELIMINAARTIGO", "Parametro" -> "a", "Ocorre" -> "0", "FK" -> "#ARTIGO", "Rel" -> "UNIDADE FORNECIMENTO" ] }); FUNC BDCSCHEMA():SYM RETURN let (nbdc=BDC(sonae), re= { XTXschema(i,nbdc[i]) | i <- dom(nbdc): is-TEnt(nbdc[i])}, rr= { XTXschema(i,nbdc[i]) | i <- dom(nbdc): is-TRel(nbdc[i])}) in do(dumpTupSet(re),dumpTupSet(rr)); FUNC BDCSETDATE(d:Dat):SYM RETURN let (nbdc=BDC(sonae), db=D(sonae), cs=C(sonae), t=T(sonae)) in if ltDat(d,t) then error("","N~ao se pode modificar o passado") else sonae <- SONAE(nbdc,db,cs,d); FUNC CLIUPDATE(i:ClId):SYM RETURN let (nbdc=BDC(sonae), db=D(sonae), cs=C(sonae), t=T(sonae)) in if ~(i in dom(cs)) then error(i,"Cliente desconhecido") else let (c=cs[i], ld=LD(c), bd=B(c), f= TDbInterval(nbdc,ld,t)) in if f==[] then warning(i,"Cliente est'a actualizado") else let (nbd= DbPlus(bd,f), ncs= cs + [ i -> Cliente(t,nbd) ]) in sonae <- SONAE(nbdc,db,ncs,t); FUNC CLIBACKLOG(i:ClId):SYM RETURN let (nbdc=BDC(sonae), db=D(sonae), cs=C(sonae), t=T(sonae)) in if ~(i in dom(cs)) then error(i,"Cliente desconhecido") else let (c=cs[i], ld=LD(c), f= TDbInterval(nbdc,ld,t)) in if f==[] then warning(i,"Cliente est'a actualizado") else let( l= < ^ relBrowse(XTX2TupleSet(i,f[i])) | i <- dom(f)>) in foreach(x,l,stdDump(x)); FUNC DUMP(o:STR):SYM RETURN let (f= if o=="BDC" then BDC(sonae) else if o in dom(C(sonae)) then B(C(sonae)[o]) else [], l= < ^ relBrowse(XTX2TupleSet(i,f[i])) | i <- dom(f)>) in if f==[] then error(o,"Cliente desconhecido ou vazio") else foreach(x,l,stdDump(x)); FUNC BDCHIST(i:Id):SYM RETURN let (nbdc=BDC(sonae)) in if ~(i in dom(nbdc)) then error(i,"Entidade/relacao desconhecida") else dumpTupSet(XTX2TupleSet(i,nbdc[i])); FUNC BDCSNAP(i:Id,d:Dat):SYM RETURN let (nbdc=BDC(sonae)) in if ~(i in dom(nbdc)) then error(i,"Entidade/rela,c~ao desconhecida") else dumpTupSet(XTX2TupleSet(i,TX2Xd(nbdc[i],d))); FUNC CLISNAP(c:ClId,i:Id):SYM RETURN let (nbdc=BDC(sonae), cs=C(sonae)) in if ~(c in dom(cs)) then error(c,"Cliente desconhecido") else let (cl=cs[c], db=B(cl)) in if ~(i in dom(db)) then error(i,"Entidade/rela,c~ao desconhecida") else dumpTupSet(XTX2TupleSet(i,db[i])); FUNC BDCADDENT(e:Id,k:Key,d:Dat,tu:Tuple):SYM RETURN let (nbdc=BDC(sonae), db=D(sonae), cs=C(sonae), t=T(sonae), te=if ~(e in dom(nbdc)) then [] else F(nbdc[e]), tt=if k in dom(te) then te[k] else [], nte= te + [ k -> tt + [ d -> tu ] ], nnbdc= nbdc + [ e -> TEnt(nte) ] ) in sonae <- SONAE(nnbdc,db,cs,t); FUNC BDCDELENT(e:Id,k:Key,d:Dat):SYM RETURN let (nbdc=BDC(sonae), db=D(sonae), cs=C(sonae), t=T(sonae), te=if ~(e in dom(nbdc)) then [] else F(nbdc[e]), tt=if k in dom(te) then te[k] else [], nte= te + [ k -> tt + [ d -> ["Morte" -> "*" ] ] ], nnbdc= nbdc + [ e -> TEnt(nte) ] ) in sonae <- SONAE(nnbdc,db,cs,t); FUNC BDCADDREL(r:Id,d:Dat,k:(Id->Key),a:Tuple):SYM PRE (let (nbdc=BDC(sonae), b= if r in dom(nbdc) then let (kk=K(choice(R(nbdc[r])))) in dom(k)==dom(kk) else subset(dom(k),{i | i <- dom(nbdc): is-TEnt(nbdc[i])})) in if ~b then false else forall({TEntExists(k[i],nbdc[i],d) | i <- dom(k) }) ) -> error(r,"Relacionamento inconsistente") RETURN let (nbdc=BDC(sonae), db=D(sonae), cs=C(sonae), t=T(sonae), tr=if ~(r in dom(nbdc)) then {} else R(nbdc[r]), ntr= tr U { TXTuple(d,k,a) }, nnbdc= nbdc + [ r -> TRel(ntr) ] ) in sonae <- SONAE(nnbdc,db,cs,t); FUNC INIT():SYM RETURN do( sonae <- SONAE( [], [], [ x -> Cliente(Dat(90,1,1),[]) | x <- {"C1","C2","C3"} ],Dat(96,3,1)), BDCADDENT("UNIDADE","2x3",Dat(95,2,26), [ "Nome" -> "Grupo 2 x 3 unidades" ]), BDCADDENT("UNIDADE","3x4",Dat(95,2,26), [ "Nome" -> "Caixa 3 x 4 unidades" ]), BDCADDENT("LOJA","L1",Dat(95,2,26), [ "Nome" -> "Modelo", "Endereco" -> "Braga" ]), BDCADDENT("LOJA","L2",Dat(94,2,26), [ "Nome" -> "Pingo Doce", "Endereco" -> "Porto" ]), BDCADDENT("ARTIGO","2000023",Dat(92,1,1), [ "Descricao" -> "Pessego Ramirez em lata", "IVA"->"16" ]), BDCADDENT("ARTIGO","2000023",Dat(93,1,1), [ "Descricao" -> "Pessego Ramirez em lata", "IVA"->"17" ]), BDCADDENT("ARTIGO","2000023",Dat(94,1,1), [ "Descricao" -> "Pessego Ramirez","IVA"->"17" ]), BDCADDENT("ARTIGO","2000023",Dat(96,12,1), [ "Descricao" -> "Pessego Ramirez em calda", "IVA"->"17" ]), BDCADDENT("ARTIGO","2000024",Dat(96,2,12), [ "Descricao" -> "Atum Bom-Petisco", "IVA"->"17" ]), BDCADDENT("FORNECEDOR","XYZ Ltd",Dat(96,2,14), [ "Razao Social" -> "Nao sei" ]), BDCADDENT("FORNECEDOR","XXX&Cia", Dat(96,2,26), [ "Razao Social" -> "?" ]), BDCADDREL("GAMA LOJA",Dat(96,2,21), [ "LOJA" -> "L1", "ARTIGO" -> "2000023" ],["Obs."->"ok"] ), BDCADDREL("GAMA LOJA",Dat(96,2,12), [ "LOJA" -> "L2", "ARTIGO" -> "2000023" ],[] ), BDCADDREL("UNIDADE FORNECIMENTO",Dat(98,1,1), [ "FORNECEDOR" -> "XYZ Ltd", "ARTIGO" -> "2000024", "UNIDADE" -> "3x4" ],["Preco"->"$"] ), BDCADDREL("UNIDADE FORNECIMENTO",Dat(98,2,12), [ "FORNECEDOR" -> "XYZ Ltd", "ARTIGO" -> "2000023", "UNIDADE" -> "2x3" ],["Preco"->"$"] ), BDCADDREL("GAMA LOJA",Dat(96,2,17), [ "LOJA" -> "L1", "ARTIGO" -> "2000024" ],[] ), CLIUPDATE("C1"), CLIUPDATE("C2"), CLIUPDATE("C3"), dumpTupSet({["Projecto" -> "NBDC/SONAE", "Versao" -> "1.0", "Obs." -> "'Valid time' apenas", "Arranque"->"OK", "Data Corrente" -> Dat2str(T(sonae))]}) ); FUNC XTXschema(i:Id,x:XTX):Tuple RETURN if is-Ent(x) then let (y=F(x)) in [ "Entidade"-> i ] + [ a -> "A" | a <- atributos(ran(y)) ] else if is-Rel(x) then let (j=strcat("#",i), r=R(x), kr = { K(xt) | xt <- r }, fks = { strcat("#",i) | i <- dom(choice(kr)) }, X = atributos({ A(xt) | xt <- r }) ) in [ "Relacao"-> i ] + [ j -> "FK" | j <- fks ] + [ a -> "A" | a <- X ] else if is-TRel(x) then let (r=R(x), nr= { XTuple(K(t),A(t)) | t <- r }) in XTXschema(i,Rel(nr)) else let (f=F(x), nf=[ k -> PLUS(ran(f[k])) | k <- dom(f) ]) in XTXschema(i,Ent(nf)); FUNC TEntExists(k:Key,e:TEnt,d:Dat):BOOL ;PRE k in dom(F(e)) RETURN ; let (xxx=princ("\nTEntExists k=",k)) in let (tt=F(e)[k], m=DatMIN(dom(tt))) in leqDat(m,d); FUNC TX2Xdaux(f:TEnt,k:Key,d:Dat):Tuple RETURN let (tt=f[k], ntt=[ t -> tt[t] | t <- dom(tt): leqDat(t,d) ], t=DatMAX(dom(ntt))) in ntt[t]; FUNC TX2Xd(tx:TX,d:Dat):X RETURN if is-TRel(tx) then let (r=R(tx)) in Rel({ XTuple(K(t),A(t)) | t <- r : leqDat(T(t),d) }) else let (f=F(tx), ff = [ k -> TX2Xdaux(f,k,d) | k <- dom(f) ]) in Ent([ k -> ff[k] | k <- dom(ff) : ff[k]!=[] ]); ;nb: lets em ffs por compreensao dumpTupSet(s) = stdDump(relBrowse(s)); FUNC relBrowse(r: Tuple-set): STR-list RETURN if r=={} then < "No records found" > else let (A=atributos(r), x=[ a -> 2.+MAX({strlen(v) | v <- {a} U valores(a,r)}) | a <- A ], L= < a | a <- A >, hline= Strcat(< strcat("+",strfill("-",x[a])) | a <- L >^<"+\n">) ;,xxx=princ("strlen=",strlen(hline),"\n") ) in < hline, Strcat(< strcat("|",strcenter(a,x[a])) | a <- L >^<"|\n">), hline > ^ < Strcat(< strcat("|",strcenter(if a in dom(t) then t[a] else "",x[a])) | a <- L >^<"|\n">) | t <- r > ^ < hline >; FUNC EntPlus(e1:Ent,e2:Ent):Ent RETURN let (f1=F(e1),f2=F(e2)) in Ent(f1+f2); FUNC RelPlus(e1:Rel,e2:Rel):Rel RETURN let (r1=R(e1),r2=R(e2)) in Rel(r1 U r2); FUNC DbPlus(db1:Db,db2:Db):Db RETURN let (I=dom(db1)*dom(db2) ) in (db1 \ I) + (db2 \ I) + [ i -> EntPlus(db1[i],db2[i]) | i <- I: is-Ent(db1[i]) ] + [ i -> RelPlus(db1[i],db2[i]) | i <- I: is-Rel(db1[i]) ]; FUNC TDbInterval(tdb:TDb,d1:Dat,d2:Dat):Db ; PRE d1 <= d2 RETURN ; nb: ver isto if d1==d2 then [] else let (f= [ i -> TXInterval(tdb[i],d1,d2) | i <- dom(tdb) ]) in [ i -> f[i] | i <- dom(f): let (x=f[i]) in if is-Rel(x) then R(x)!={} else F(x)!=[] ]; FUNC TXInterval(tx:TX,d1:Dat,d2:Dat):X RETURN ;let (xxx=princ("\nTXInterval=",d1,d2)) in if is-TRel(tx) then let (r=R(tx)) in Rel({ XTuple(K(t),A(t)) | t <- r : leqDat(T(t),d2) && gtDat(T(t),d1) }) else let (f=F(tx), ff = [ k -> TX2Xdd(f,k,d1,d2) | k <- dom(f) ]) in Ent([ k -> ff[k] | k <- dom(ff) : ff[k]!=[] ]); ;nb: simplificar! FUNC TX2Xdd(f:TEnt,k:Key,d1:Dat,d2:Dat):Tuple RETURN let (tt=f[k], ntt=[ t -> tt[t] | t <- dom(tt): leqDat(t,d2) && gtDat(t,d1) ], t=DatMAX(dom(ntt))) in ntt[t]; FUNC TDb2Db(tdb:TDb):Db RETURN [ i -> TX2X(tdb[i]) | i <- dom(tdb) ]; FUNC TX2X(tx:TX):X RETURN if is-TRel(tx) then let (r=R(tx)) in Rel({ XTuple(K(t),A(t)) | t <- r }) else let (f=F(tx), ff = [ k -> TTuple2Tuple(f[k]) | k <- dom(f) ]) in Ent(ff); FUNC TTuple2Tuple(tt:TTuple):Tuple RETURN let (m=DatMAX(dom(tt))) in tt[m]; FUNC TDb2TupSet(tdb:TDb):Tuple-set RETURN UNION({ let (tx=tdb[i]) in if is-TRel(tx) then TRel2TupSet(tx) else TEnt2TupSet(i,tx) | i <- dom(tdb) }); FUNC TDbBackLog(tbd:TDb,d1:Dat,d2:Dat):TDb RETURN error("!","not yet"); FUNC Ent2TupSet(i:Id,x:Ent):Tuple-set RETURN let (j=strcat("#",i), f=F(x)) in { [ j -> k ] + f[k] | k <- dom(f) }; FUNC TRel2TupSet(x:TRel):Tuple-set RETURN { TXTuple2Tuple(xt) | xt <- R(x) }; FUNC Rel2TupSet(x:Rel):Tuple-set RETURN { let (fk=K(y), fa=A(y)) in jj(fk) + fa | y <- R(x) }; FUNC XTX2TupleSet(i:Id,x:XTX):Tuple-set RETURN if is-Ent(x) then Ent2TupSet(i,x) else if is-Rel(x) then Rel2TupSet(x) else if is-TRel(x) then { TXTuple2Tuple(xt) | xt <- R(x) } else TEnt2TupSet(i,x); FUNC TEnt2TupSet(i:Id,x:TEnt):Tuple-set RETURN let (j=strcat("#",i), f=F(x)) in UNION({{ [ j -> k, "Data Vigor" -> Dat2str(d) ] + (f[k])[d] | d <- dom(f[k]) } | k <- dom(f) }); ;nb: por isto possivel? ; in { [ j -> k, "Data Vigor" -> Dat2str(d) ] + (f[k])[d] ; | k <- dom(f), d <- dom(f[k]) }; FUNC Browse(i:ClId,j:Id):SYM RETURN let (dbs=B(sonae)) in if ~(i in dom(dbs)) then error(i,"base de dados desconhecida") else let (db=dbs[i]) in if ~(j in dom(db)) then error(j,"tabela desconhecida") else dumpTupSet(XTX2TupleSet(j,db[j])); FUNC TXTuple2Tuple(t:TXTuple):Tuple RETURN [ "Data Vigor" -> Dat2str(T(t)) ] + jj(K(t)) + A(t); FUNC jj(fk:FF):FF ;RETURN let (r= { < strcat("#",k), fk[k] > | k <- dom(fk) }) ; in [ p1(t) -> p2(t) | t <- r ]; RETURN if fk==[] then [] else let(k=choice(dom(fk)), kk= strcat("#",k)) in [ kk -> fk[k] ] + jj(fk \ {k}); FUNC jno2(ff:FF):FF ;RETURN [ p2(k) -> ff[k] | k <- dom(ff) ] RETURN if ff==[] then [] else let(k=choice(dom(ff)), nk=p2(k)) in [ nk -> fk[k] ] + jno2(ff \ {k}); FUNC error(s:STR,m:STR):SYM RETURNS dumpTupSet({["Mensagem"->"Erro","Id" -> s, "Obs." -> m]}); FUNC warning(s:STR,m:STR):SYM RETURNS dumpTupSet({["Mensagem"->"Aviso","Id" -> s, "Obs." -> m]}); ;------- STR extra functionality ---------------------------------------------- ; Strcat : STR-list --> STR-list Strcat(l) = if l==<> then "" else strcat(head(l),Strcat(tail(l))); stdDump(l) = do(foreach(s,l,do(princ(s))),""); FUNC strcenter(s:STR,l:INT):STR ; pre: l >= strlen(s) RETURN if l==strlen(s) then s else let (x=l.-strlen(s),m=x./2,r=rem(x,2),n=m.+r) in strcat(strfill(" ",m),s,strfill(" ",n)); FUNC strleft(s:STR,l:INT):STR ; pre: l >= strlen(s) RETURN if l==strlen(s) then s else strcat(strleft(s,l.-1)," "); FUNC strfill(s:STR,l:INT):STR ;if l==0 then "" else strcat(s,strfill(s,l.-1)); RETURN do(x<-"", n<-l, while((n>0),do(x<-strcat(s,x),n<-n.-1)), x); ;------- BOOL extra functionality ---------------------------------------------- forall(B)= subset(B,{true}); ;------- INT extra functionality ---------------------------------------------- FUNC MAX(s:INT-set):INT RETURN MAXloop(s,0); FUNC MAXloop(s:INT-set,m:INT):INT RETURN if (s=={}) then m else let (x=choice(s)) in MAXloop(s-{x}, max(x,m)); ;------- funcoes polimorficas primitivas ----------------------- PLUS(s) = if s=={} then [] else plus-orio([],s); ; valores: A x (A->B)-set --> B-set valores(a,r) = { t[a] | t <- r : a in dom(t) }; ; atributos: (A->B)-set --> A-set atributos(r) = UNION({ dom(t) | t <- r }); ;---------- Dat Functionality -------------------------------------------------- TYPE Dat :: Y: INT M: INT D: INT; ENDTYPE leqDat(d,e) = d==e || ltDat(d,e); gtDat(d,e) = ltDat(e,d); ltDat(d,e) = if (Y(d)Y(e)) then 'false else if (M(d)M(e)) then 'false else (D(d) 9) then "/" else "/0", itoa(m), if (d > 9) then "/" else "/0", itoa(d)); FUNC DatMAX(s:Dat-set):Dat RETURN DatMAXloop(s,Dat(0,0,0)); FUNC DatMAXloop(s:Dat-set,m:Dat):Dat RETURN if (s=={}) then m else let (x=choice(s)) in DatMAXloop(s-{x}, if ltDat(x,m) then m else x); FUNC DatMIN(s:Dat-set):Dat RETURN DatMINloop(s,Dat(9999,1,1)); FUNC DatMINloop(s:Dat-set,m:Dat):Dat RETURN if (s=={}) then m else let (x=choice(s)) in DatMINloop(s-{x}, if ltDat(x,m) then x else m); INIT(); BDCSETDATE(Dat(96,3,2)); CLISTAT(); BDCHIST("LOJA"); BDCADDENT("LOJA","L1",Dat(96,3,2),["Nome"->"Pingo Doce"]); BDCHIST("LOJA"); CLIBACKLOG("C1");