Plans for stricter record semantics in R8
Luc Taesch
ltaesch@REDACTED
Sun Oct 15 21:09:54 CEST 2000
> Bjorn Gustavsson wrote:
> >
> > In R8, we preliminary plan to stricten the test for valid records
>
> Great. Are there any plans of inserting generic functions on records as
> well (or implementing O'Keef's suggestion from 1998)?
>
i would not mind a link ?
> Due to their
> implementation, it is today impossible to write generic code using
> different record types. There are however many cases where different
> records can be treated equally as they share some common denominators.
>
> Generic code of this kind is today handled by using the tuple
> representation of records. (Do as I say, don't do as I do is what I end
> up preaching....) And the code is static anyhow, as every time you add a
> new record, you have to recompile the file with the generic stuff (or go
> through a call back module which makes the code yucky and hard to
> follow).
>
> Functions (BIFs) could include
>
> get_record(RecordType) -> #RecordType{}
> get_record_name(Record) -> RecordType
> get_record_fields(RecordName) -> [FieldName1,...]
> lookup_record_field(Record, FieldName1) -> Element
>
here are the corresponding functions in attached files
Function : prototype/2
%% Purpose : create One Empty record of type Table, according to Schema
%%---------------------------------------
%%---------------------------------------
%% Function : info/2
%% Purpose : entity | relations for a Record
%% Arg: entity| relation, Record, grmSchema
%%---------------------------------------
grm_mnesia:field_value(Record,Field)->
%%---------------------------------------
grm_mnesia:retrieve(Table,Key) when atom(Key)
%%---------------------------------------
Function :grm_mnesia: retrieve/3
%% Purpose : retrieve the records referenced by a given record
%% Arg: Relation, Record | [Record], Schema
in the attached grm_mnesia, files, ull find the corresponding functions.
(still work in progress).
they suppose your database is defined in a grm schema like
schema()->
[
{entity,
[description,indexing,responsabilities,services,suppliers,states,invariant,component,precondition,postcondition,predicate,menu,commands,queries,dialog]},
{relation,
[{component,composition,states},
{states,reference,description},
{component,reference,description},
{component,composition,commands},
{component,composition,queries},
% {features,reference,description},
% {features,composition,commands},
% {features,composition,queries},
with manipulation functions in grm_schema
supported_relationships()->
[attribute,dependency,reference,composition].
also an example kit_schema, and the kit_lib in case of dependencies.
this is work in progress, and need a lot of restructuring ( a few things
are in grm_schema/mnesia now, but need some to be moved out.)
(GRM stands for generic relationship management, i believe, (kilov work
on formal semantics, an iso standard now. (kilov worked in RM_ODP may be
known by you, telecom guys. i can search links if interested)
i was surprised how little overhead i found (maybe 10-20%, i was
expecting 100-200, compared to "compiled coded" records. (well , i dont
have soft real time requirement)
btw, there is a few utilitaries that create db schema, or records
headers based on the schema
%% Purpose : give the records definition (.hrl)
%% Arg: headers,Schema
%% Return : -record (tablename,[fieldsname]), string-ified.
%%---------------------------------------
info(headers,S)->
%%---------------------------------------
%% Function : info/2
%% Purpose : give the table definition (like mnesia:save_to_text would)
%% Arg: table,Schema
%% Return : {table, [{tablename,[fieldsname]}]}
%%---------------------------------------
info(tables,S)->
got some more things, if interested.
> Just in time for xmas?? :-)
>
> Regards,
>
--
First, they ignore you.
Then, they laugh at you.
Then, they fight you.
Then, you win.
--- Gandhi.
Working code is what matter, not your market capitalization.
--Kurt granroth
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20001015/9a99bcad/attachment.htm>
-------------- next part --------------
%% ``The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved via the world wide web at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% The Initial Developer of the Original Code is luc abom.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%% $Id: grm_schema.erl,v 1.7 2000/10/13 16:59:29 luc Exp $
%%
-module(grm_schema).
-author('luc@REDACTED').
-compile([export_all]).
-export([new/1,
add/3,
fetch/2,fetch/3,
composition/2,dependency/2,reference/2,
supported_relationships/0]).
%%---------------------------------------
%% Function : new/1
%% Purpose : create a new grm schema
%% Arg: schema
%% Return : empty schema
%%---------------------------------------
new(schema)->schema([],[])
.
%%---------------------------------------
%% Function : add/3
%% Purpose : add a new entity to the schema
%% Arg: entity, Entity= atom(),Schema
%% Return : updated schema
%%---------------------------------------
add(entity,E, S)->
false= exist(entity,E,S), %%precondition: uniqueness
schema(
combine_item( E,fetch(entity,S)),
fetch(relation,S));
%%---------------------------------------
%% Function : add/4
%% Purpose : add a new relation to the schema
%% Arg: relation, FromEntity= atom(),{relation, ToEntity},Schema
%% Return : updated schema
%%---------------------------------------
add(relation, Relation, S) ->
is_add_able(relation,Relation,S), %% precondition : valid relation
schema(
fetch(entity,S),
combine_item(Relation,fetch(relation,S))).
%%---------------------------------------
%% Function : fetch/2
%% Purpose : fetch entities or relationsfrom the schema
%% Arg: entity,Schema, or relation, Schema
%% Return : list of entities {entity,[atoms()]}, or { relation, {entity,relation,[entities]
%%---------------------------------------
fetch(entity,[{entity,E},{relation,R}])->
% {value,{entity,K}}=lists:keysearch(entity,1,S),
E
;
fetch(relation,[{entity,E},{relation,R}]) ->
lists:keysort(2,R).
%%---------------------------------------
%% Function : fetch/3
%% Purpose : fetch relation (resp .specific relation) entity from the schema
%% Arg: relation | supportedRelations(), FromEntity= atom(),{relation, ToEntity},Schema
%% Return : [{{From,Rel,To}}] (=filtered schema)
%%---------------------------------------
fetch(relation,From,S) ->
R=fetch(relation,S),
K=lists:filter(fun({FromX,Rel,To})->
case FromX of
From->true;
_ ->false
end end
,R)
%{value,K}=lists:keysearch(From,1,R),
, K;
fetch(Relation,From,S)->
fetch(relation,From,Relation,S).
%% not exported
fetch(relation,From,Rel,S) ->
R=fetch(relation,S),
K=lists:filter(fun({FromX,RelX,To})->
case {FromX,RelX} of
{From,Rel}->true;
_ ->false
end
end
,R)
%{value,K}=lists:keysearch(From,1,R),
, K.
%%------------------------------------------
%% internals
%%----------------------------------------
%%---------------------------------------
%% Function : schema/2
%% Purpose : build a schema structure
%% Arg: EntityList= [atom()],relationList [relations()]}
%% Return : [{entity, EntityList},{relation,relationList}]
%%---------------------------------------
schema(EntityList,RelationList)->
[{entity,EntityList},{relation,RelationList}].
relation(From,RelationType,To)->
{From,RelationType,To}.
composition(From,To)->
relation(From,composition,To).
reference(From,To)->
relation(From,reference,To).
dependency(From,To)->
relation(From,dependency,To).
attribute(From,To)->
relation(From,attribute,To).
%%---------------------------------------
%% Function : is_valid/3
%% Purpose : check a relationship or an entity
%% Arg: Relationship,Schema
%% Return : true if both entity exists in the schema, the relation is supported, and doesnt exists already (unique)
%%---------------------------------------
is_add_able(relation,{From,RelationType,To},Schema)->
case {
lists:member(RelationType,supported_relationships()),
exist(entity,From,Schema),
exist(entity,To,Schema),
exist(relation,RelationType,Schema)
} of
{true,true,true,false}->
true;
_ ->
false
end.
%%---------------------------------------
%% Function : exist/3
%% Purpose : check the existence of an entity or a relationship in the schema
%% Arg: Entity= atom(),Schema
%% Return : true | false
%%---------------------------------------
exist(entity,Entity,Schema)->
lists:member(Entity,fetch(entity,Schema));
exist(relation,Entity,Schema)->
lists:member(Entity,fetch(relation,Schema)).
%%---------------------------------------
%% Function : /3
%% Purpose : check the existence of an entity or a relationship in the schema
%% Arg: Entity= atom(),Schema
%% Return : true | false
%%---------------------------------------
supported_relationships()->
% [composition,dependency,reference,attribute].
[attribute,dependency,reference,composition].
%%---------------------------------------
%% Function : info/2
%% Purpose : check the schema definition
%% Arg: schema,Schema
%% Return : ok or wrong >reason
%%---------------------------------------
%% a schema is ok if
%% any relations relates existing entities
%% relations are among the supported ones.
append_true(true,Res)->Res;
append_true(Acc,true) ->Acc;
append_true(Acc,Res) ->[Res | Acc ].
is_valid(relation,{From,RelationType,To},Schema)->
lists:foldl(
fun({Fun,ErrMess},Acc)->
Res=case Fun() of
true->true;
_ -> { ErrMess,{From,RelationType,To}}
end,
append_true(Acc,Res)
end
,true,
[{fun()-> lists:member(RelationType,supported_relationships()) end,"relationship not supported"},
{fun() ->exist(entity,From,Schema) end,"wrong source entity"},
{fun()->exist(entity,To,Schema) end,"wrong target entity"}
% {fun()-> exist(relation,RelationType,Schema) end,"relation already exists"}
]
);
is_valid(attribute,{From,RelationType,To},Schema)->
lists:foldl(
fun({Fun,ErrMess},Acc)->
Res= case Fun() of
true->true;
_ -> { ErrMess,{From,RelationType,To}}
end,
append_true(Acc,Res)
end
,true,
[{fun()->case RelationType of attribute->true;_->false end end,"wrong keyword:attribute expected"},
{fun() ->exist(entity,From,Schema) end,"wrong source entity"},
{fun()->not exist(entity,To,Schema) end," entity exists with attribute name"}
]
).
info(schema,Schema)->
lists:foldl(fun(R={From,RelationType,To},Acc)->
Res =case RelationType of
attribute -> is_valid(attribute,R,Schema);
_->
is_valid(relation,R,Schema)
end,
append_true(Res,Acc)
end,
true,
fetch(relation,Schema));
%%---------------------------------------
%% Function : info/2
%% Purpose : give the table definition (like mnesia:save_to_text would)
%% Arg: table,Schema
%% Return : {table, [{tablename,[fieldsname]}]}
%%---------------------------------------
info(tables,S)->
{tables,lists:map(
fun(E)->
{E, [key |lists:map( fun({From,Rel,To})->
To
end, fetch(relation,E,S))]
}
end
, fetch(entity,S))
} ;
%% Purpose : give the records definition (.hrl)
%% Arg: headers,Schema
%% Return : -record (tablename,[fieldsname]), string-ified.
%%---------------------------------------
info(headers,S)->
{tables,T}=info(tables,S),
lists:map(
fun({Name,ListofFiels})->
["-record(",
atom_to_list(Name),",",
io_lib:format("~p",[list_to_tuple(ListofFiels)]),").\n"] end
,T).
dump_to_recordfile(File) ->
dump_to_recordfile(mnesia_lib:is_running(), file:open(File, write)).
dump_to_recordfile(yes, {ok, F}) ->
file:write(F,list_to_binary("-module(testdata_auto).\n"
"-compile([export_all]).\n"
"-import(kit_db,[store/1]).\n"
"-include(\"kit_schema.hrl\").\n"
"test_data()->\n")),
Tabs = lists:delete(schema, mnesia_lib:local_active_tables()),
lists:foreach(fun(T) -> dump_tab(F, T) end, Tabs),
file:write(F,list_to_binary("ok.\n")
),
file:close(F);
dump_to_recordfile(_,_) -> error.
dump_tab(F, T) ->
W = mnesia_lib:val({T, wild_pattern}),
{atomic,All} = mnesia:transaction(fun() -> mnesia:match_object(W) end),
R=lists:map(fun(Term) -> format_record(Term)end, All),
file:write(F,list_to_binary(R))
.
format_record(R)->
[T| FieldValue]=tuple_to_list(R),
FieldName= mnesia_lib:val({T, attributes}),
NameAndValue=lmerge(FieldName,FieldValue),
["ok=store(",$#,atom_to_list(T),${,
[fr_elem(hd(NameAndValue))|fr_tail(tl(NameAndValue))],
$},$),$,,$\n ].
fr_elem({Name,Value})-> [io_lib:format("~p",[Name])," = ",io_lib:format("~p",[Value])].
% [ioN,$=,V].
fr_tail([])->
"";
fr_tail([H|T]) ->[[$,,fr_elem(H)] | fr_tail(T)]
.
lmerge(L1,L2)->
lists:reverse(lmerge(L1,L2,[])).
lmerge([],_,A)->A;
lmerge(_,[],A)->A;
lmerge([H1|L1],[H2|L2],Acc)->
lmerge(L1,L2, [{H1,H2}|Acc] ).
%%---------------------------------------utils
combine_item(L1, []) ->
[L1];
combine_item(L1, L2) ->
[L1]++L2.
-------------- next part --------------
%% ``The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved via the world wide web at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% The Initial Developer of the Original Code is luc abom.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%% $Id: grm_mnesia.erl,v 1.11 2000/10/11 16:28:06 luc Exp $
%%
-module(grm_mnesia).
-author('luc@REDACTED').
-compile([export_all]).
-export([info/2,info/3]).
-include("kit_server.hrl").
-import(grm_schema,[fetch/3]).
%-import(kit_lib,[heading/1]).
-import(kit_lib_format,[for_all_sections/2]).
-include("mnesia_test_lib.hrl").
%%---------------------------------------
%% Function : info/2
%% Purpose : entity | relations for a Record
%% Arg: entity| relation, Record, grmSchema
%% Return : entity(), relations
%%---------------------------------------
info(entity, Record)-> element(1,Record).
info(relation, Record, Schema) ->
fetch(relation,info(entity,Record),Schema).
%%---------------------------------------
%% Function : retrieve/3
%% Purpose : retrieve the records referenced by a given record
%% Arg: Relation, Record | [Record], Schema
%% Return : empty schema
%%---------------------------------------
retrieve(Relation,Records,Schema) when list(Records)->
lists:flatten(
lists:map( fun(OneRecord)-> retrieve(Relation,OneRecord,Schema) end
,Records));
retrieve(Relation,Record,Schema)->
Relations= fetch(Relation,info(entity,Record),Schema),
lists:flatten(
lists:map( fun({_From,_Relation,To})->
Key=field_value(Record,To),
Res =retrieve_ft(To,Key,Record)
end,
Relations))
.
%%---------------------------------------
%% Function : retrieve_ft/3
%% Purpose : retrieve the records in a table, fault tolerant manner
%% Arg: Table,Keys ,FatherRecord (just for error message)
%% Return : Record | [Record]
%%---------------------------------------
retrieve_ft(Table, Keys,Record) when list(Keys)->
R=lists:map(fun(X)->retrieve_ft(Table,X,Record) end, Keys),
K=lists:flatten(R),
K
;
retrieve_ft(Table,Keys,Record) when atom(Keys)->
case Res =retrieve(Table,Keys) of
not_found ->
kit_lib:info_report(?MODULE,
[
{retrieve_ft,"key pointing wrong: ignoring\n"},
{pointing_to,Table},{key_to,Keys},
{record,Record}]),
[]; %fault tolerant, may be parametrable
R -> [R]
end.
%%---------------------------------------
%% Function : retrieve/2
%% Purpose : retrieve the records in a table
%% Arg: Table,Keys
%% Return : Record | [Record]
%%---------------------------------------
retrieve(Any, Keys) when list(Keys)->
case catch list_to_atom(Keys) of
{'EXIT',_} ->
lists:map(fun(X)->retrieve(Any,X) end, Keys);
K -> retrieve(Any,K)
end;
%%not exported
retrieve(Table,Key) when atom(Key)->
F = fun() ->
mnesia:read({Table,Key})
end,
case mnesia:transaction(F) of
{atomic,[T]} -> T;
Msg->
kit_lib:info_report(?MODULE,
[
{retrieve_2,"record not found\n"},
{table,Table},{key,Key},
{message,Msg}]),
not_found
end.
%%return the #Record.Field
field_value(Record,Field)->
R= field_rank(
info(entity,Record),Field),
element(R,Record).
%%Return the Rank from Field in Table
field_rank(Table, Field)->
T2= mnesia:table_info(Table,attributes),
find_rank(Field,T2).
%%count th rank from X in L, +1 (for the record name)
find_rank(X,L)->
find_rank(X,L,2).
find_rank(_,[],N)->not_found;
find_rank(X,[X|T],N)->
N;
find_rank(X,[_|T],N) ->find_rank(X,T,N+1).
%%---------------------------------------
%% Function : prototype/2
%% Purpose : create One Empty record of type Table, according to Schema
%% Arg: Table,Schema
%% Return : Record | [Record]
%%---------------------------------------
prototype(Table, Schema)->
list_to_tuple( [Table,new_key(Table) |
lists:map(fun(_)->
[] end,
fetch(relation,Table,Schema))]).
%%---------------------------------------
%% Function : new_key/1
%% Purpose : create a new key
%% Arg: Table
%% Return : Record | [Record]
%%---------------------------------------
%generate a new key refering to a table
new_key(Table) when atom(Table)->
{{Y,M,D},{H,Mi,S}}= erlang:universaltime(),
%random:seed(),Rand=random:uniform(999),
{_,_,Rand}=now(),
K=io_lib:format("~w~p~p~p~p~p~p",[Y,M,D,H,Mi,S,Rand]),
list_to_atom(lists:append([atom_to_list(Table) |K])).
%%---------------------------------------
%% Function : add_link/2
%% Arg : Son, Father
%% Purpose: add the Son Record as a link into the Father (not in the db)
%% Return : FatherRecord
%%---------------------------------------
add_link(Son,Father)->
SonName=info(entity,Son),
Key=element(2,Son),
SonRank=field_rank( info(entity,Father),SonName),
CurrentValue=element(SonRank,Father),
NewSource=setelement(SonRank,Father, [Key | CurrentValue ] ).
%%---------------------------------------
%% Function : new_structure/2
%% Purpose : create a strucuture of new (empty) records, according to Schema
%% Arg: Table,Schema
%% Return : {Record, [AssociatedRecord]
%%---------------------------------------
new(Table, Schema)->
new(Table, Schema,[]).
new(Table, Schema,Acc2)->
{NewRec, AssociatedRecords}
= lists:mapfoldl(fun({From,RelationType,To},Acc)->
new_element(RelationType,{To,Acc},Schema)
end,
[],fetch(relation,Table,Schema)),
NK=new_key(Table),
NR=list_to_tuple([Table,NK|NewRec]),
{NR,[NR|lists:append([AssociatedRecords,Acc2])]}.
new_element(attribute,{Relation,AccListe},Schema)->
{default(Relation), AccListe};
new_element(dependency,{Relation,AccListe},Schema) ->
{default(Relation),AccListe};
new_element(reference,{To,AccListe},Schema) ->
{NewRecord,AccListe2}=new(To,Schema,AccListe),
{key(NewRecord), AccListe2};
new_element(composition,{To,AccListe},Schema) ->
{NewRecord,AccListe2}=new(To,Schema,AccListe),
{key(NewRecord), AccListe2}.
default(Relation)->atom_to_list(Relation).
key(R)->[element(2,R)].
%%% context related functions, to be cleaned
context(append_to_heirs,Record, Context)->
?log("Record: ~p Context : ~p",[Record,Context]),
Newheirs= [[Record] | context(heirs,Context)],
REsult= Context#context{
heirs=Newheirs}.
context(new,Mode)->
#context{heirs=[], mode=Mode};
context(relation,Context)->
Context#context.relation;
context(mode,Context)->
Context#context.mode;
context(funNext,Context)->
Context#context.funNext;
context(heirs,Context)->
father(Context#context.heirs);
context(context,Context)->Context;
context(Badarg,Context)->?log("badard:~p~n",[Badarg]).
%%---------------------------------------
%% Function : father/1
%% Purpose : the father of the curernt element in a context
%% Arg: [Record], = context
%% Return : Record
%%---------------------------------------
father([])->[];
father(Context) when list(Context)->
father(hd(Context));
father(Context)->
Context.
%%initialise the navigation and thecontext
navigate(Build,Record,S,Context)->
NewContext=Context#context{schema=S,
funBuild=Build,
allrelation= grm_schema:supported_relationships()},
next(Record,[[{composition,Record}]],NewContext).
%%navigate the record
nav_it(Record,Context)->
AllRec =
instance_per_relation(
Record,Context#context.allrelation,Context#context.schema),
I3=fsg(AllRec,Context#context.schema) , %filter, sort , group
next(Record,I3,Context). %go on
next(Record,ListofDuplets,Context)-> %prepare next iteration
NewContext1 =Context#context{
heirs= [[Record] | Context#context.heirs]},
NewContext=NewContext1#context{
funNext = fun(R1)-> nav_it(R1,NewContext1) end},
Build=NewContext#context.funBuild,
Build(section,ListofDuplets,NewContext).
instance_per_relation(Record,Relations,S)->%retrieve instances per relation, and build duplets
lists:flatten(
lists:foldl(
fun(Rel,Acc)->
Rec=lists:map(
fun(OneRec)->
{Rel,OneRec} end,
retrieve(Rel,Record,S)),
[Rec | Acc]
end,[],Relations)).
fsg(ListofDuplets,Schema)->
%Fiter, Sort, and groups duplets of {relation, records}
I1=grm_filter(ListofDuplets),
I2=grm_sort(I1,Schema),
I3= group_relation_and_records(I2),
%, io:format("Allrec ~p~n Sorted:noG ~p~n I3:G ~p~n",[ListofDuplets,I2,I3]),
I3
.
grm_filter(Allrec)->
Allrec.
grm_sort(AllRec,Schema)->%sort relation first, then records
OrderList=grm_schema:fetch(entity,Schema),
F= fun(A,B)->
{RelA,RecA}=A,
{RelB,RecB}=B,
case RelA of
RelB-> compare_stuff(element(1,RecA) , element(1,RecB),OrderList);
_->% we ressort on ordering the relationships
compare_relationships(RelA,RelB)
end
end,
lists:sort(F,AllRec).
%%---------------------------------------
%% Function : compare_relationships/2
%% Purpose : define an ordered relation on GRM relationships
%% Arg: R1,R2 = supportedrelationships()
%% Return : true if R1 >R2
%%---------------------------------------
compare_relationships(R1,R2)->
OrderList=[attribute,reference,composition,dependency],
compare_stuff(R1,R2,OrderList).
compare_stuff(R1,R2, OrderList)->
RankR1=find_rank(R1,OrderList),
RankR2=find_rank(R2,OrderList),
RankR1<RankR2.
%%---------------------------------------
%% Function : group/1
%% Purpose : the grouped list , ie [a,a,a,b,b]->[[a,a,a],[b,b]]
%% Arg: [sortedRecords], fun to compare equality of records
%% Return : [[groupedRecord],..]
%%---------------------------------------
group_with_key(L,Key)->
{ResList,LastCurrent}=lists:foldl(
fun(Rec,Acc)->{GroupList,CurrentGroup}=Acc,
case CurrentGroup of
[]->{GroupList,[Rec]};
H ->
CurrentRecordName = Key(hd(H)),
case Key(Rec) of
CurrentRecordName -> %same as current
{GroupList,[Rec | H ]};
_ -> %other record, new sublist
{[H| GroupList ],[Rec]}
end
end
end
, {[],[]},L),
lists:reverse([LastCurrent|ResList])
.
group_records(L)->
F= fun(X)->
element(1,X) end,
group_with_key(L,F).
group_relation_and_records([])->[];
group_relation_and_records(L)->
%assuming L =[{rel,Record}]
F= fun(X)->{_Rel,Rec}=X,
element(1,Rec) end,
group_with_key(L,F).
-------------- next part --------------
%% ``The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved via the world wide web at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% The Initial Developer of the Original Code is luc abom.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%% $Id: kit_lib_format.erl,v 1.8 2000/10/11 16:28:06 luc Exp $
%%
-module(kit_lib_format).
-author('luc@REDACTED').
-compile([export_all]).
-include("mnesia_test_lib.hrl").
-include("kit_server.hrl").
-include("kit_schema.hrl").
-import(grm_mnesia,[info/2,info/3,context/2]).
-import(kit_lib,[forge_link/1, heading/1,father/1]).
%-export([new/1,
% add/3,
% fetch/2,fetch/3,
% composition/2,dependency/2,reference/2,
% supported_relationships/0]).
%%---------------------------------------
%% Function : grm_browse/3
%% Purpose : browse a grm schema, from a record
%% Arg: relation, the record to browse, grm_schema, the Fun to naivigate the schema, the context of the current element
%% Return : a formatting tree
%%---------------------------------------
grm_browse(Rel,[],Context) ->
kit_lib:info_report(?MODULE,[
{grm_browse_3,"received empty record: ignoring"},
{relation,Rel},
{context,Context}]),
[];
%%following are relation related relates
grm_browse(reference,Record,Context)->
build_format(desc,Record, Context);
grm_browse(composition,Record,Context)->
Next=context(funNext,Context),
Next(Record);
grm_browse(dependency,Record,Context) ->[];
grm_browse(attribute,Record,Context) ->[];
%%following are section related
grm_browse(section,Record,Context) ->
for_all_sections(Record,Context)
.
for_all_sections(Records,Context)->
lists:flatmap(fun(RecordSection)->
{Rel,Rec}=hd(RecordSection),
case Rel of
composition ->
[{section, [{heading, heading(Rec)}],
lists:append(
[buttons_for_leafs(Rec,Context),
for_all_records(RecordSection,Context)]) }];
reference ->for_all_records(RecordSection,Context)
end
end, Records)
.
%% Build all the Records
for_all_records(Records,Context)->
Build=Context#context.funBuild,
lists:flatmap(fun(Arg)->{Rel,Rec}=Arg,
Build(Rel,Rec,Context)
end, Records)
.
buttons_for_leafs(Record,Context)->
case context(mode,Context) of
edit ->
Relations=info(relation,Record,Context#context.schema),
Re=lists:map( fun({From,Rel,To})->To end, Relations),
R=io_lib:format("~p~p",[Re,Relations]),
% io:format("R:~p~n",[R]),
[{input,
[{type,"submit"},{name,name_for_submit("add",Record,Context)},{value,"+"}],
[]},
selector(Re,name_for_submit("select",Record,Context))];
_->[]
end
.
%%% format related functions
build_format(desc,Record, Context)->
case context(mode, Context) of
browse->
desc_to_para2(Record,kit_lib:forge_link(context(heirs,Context)));
edit -> desc_to_input(Record);
link-> link_to_para(Record);
_Donk ->?log("shit mode :~p~n",[_Donk])
end
.
%desc(Type, L,Link) when list(L) ->
% lists:flatten(lists:map(fun(X)->desc(Type,X,Link) end, L));
%desc(list, A,Link) when record(A,states) ->
% desc_to_para(A#states.description,forge_link(A));
%desc(list, A,Link) when record(A,features) ->
% desc_to_para(A#features.description,forge_link(A));
desc(list, A,Link) ->
desc_to_para(A,Link).
desc_to_para(C) when record(C,description)->
[{link,
[{linkend,"testlink"}],
C#description.name},
{'P', C#description.definition}].
desc_to_para(C,Link) when record(C,description)
-> [{link,
[{linkend,Link}],
C#description.name},
{'P', C#description.definition}].
desc_to_para2(C,Link) when record(C,description)
-> [{'P',[
{link,
[{linkend,Link}],
C#description.name},
{data, ":"},
{data,C#description.definition}]}].
desc_to_glossentry(C,Link) when record(C,description)
-> [{glossentry,
[{glossterm,
[{link,[{linkend,Link}],C#description.name}]},
{glossdef, C#description.definition}]
}].
desc_to_input(C) when record(C,description)->
[{'P',[input_field("name",C#description.key,C#description.name),
input_textarea("definition",C#description.key,C#description.definition)
]}].
link_to_para( A) when record(A,menu) ->
[{'P',link_to_para(A#menu.text,A#menu.link)}].
link_to_para(Text, Link) ->
[{link,[{linkend,Link},{target,"main"}], Text}].
%%%%%%%%%%%%%%%%%%%%
%% utils
input_field(Name,Key,Value)->
{input,[{type,"text"},
{name,name_with_key(Name,Key)},
{value,Value}],
""}.
input_textarea(Name,Key,Value)->
{textarea,[{name,name_with_key(Name,Key)},
{row,4},{column,70}],
Value}.
selector(List,Name)->
%create a list of option from a list of atoms
{select,[{name,Name}],
lists:map(fun(O)->{option,atom_to_list(O)} end, List)
}.
name_with_key(Name, Key) when atom(Key) ->
%produce a NAME+_+KEY value, as string, to be used in field name identifier in forms
Name++"_"++atom_to_list(Key).
name_for_submit(Action,Record,Context)->
%%produce a name with the action_Table++Key
Action++"_"++name_with_record(Record).
name_with_record(Record)->
%%produce Table++Key
atom_to_list(element(1,Record)) ++ atom_to_list(element(2,Record)).
-------------- next part --------------
-module(kit_schema).
-compile(export_all).
schema()->
[{entity,
[description,indexing,responsabilities,services,suppliers,states,invariant,component,precondition,postcondition,predicate,menu,commands,queries,dialog]},
{relation,[{component,composition,states},
{states,reference,description},
{component,reference,description},
{component,composition,commands},
{component,composition,queries},
% {features,reference,description},
% {features,composition,commands},
% {features,composition,queries},
{description, attribute,name},
{description, attribute,definition},
{menu,attribute,text},
{menu,attribute,link},
{menu,attribute,order},
{states,composition,precondition},
{states,composition,postcondition},
{precondition,reference,description},
{postcondition,reference,description},
{postcondition,composition,predicate},
{precondition,composition,predicate},
{predicate,reference,description},
{commands,reference,description},
{queries, reference,description},
{queries,composition,precondition},
{commands,composition,precondition},
{commands,composition,postcondition},
{invariant,reference,description},
{invariant,composition,predicate},
{indexing,reference,description},
{component,composition,indexing},
{responsabilities,reference,description},
{component,composition,responsabilities},
{suppliers,reference,description},
{component,composition,suppliers},
{services,reference,description},
{component,composition,services},
{dialog,reference,description},
{component,composition,dialog}
]}] .
update_header()->
true =grm_schema:info(schema,schema()),%precondition
F=
grm_schema:info(headers,schema()),
write_file("../inc/kit_schema.hrl",lists:flatten(F)).
write_file(Fname,Tree)->
Pname = Fname, %"./kit.sgml",
case file:write_file(Pname, list_to_binary(Tree)) of
ok ->
io:format(": written file: ~p~n",
[Pname]);
{error,Reason} ->
io:format("writing mail failed, reason: ~p~n",
[?MODULE,?LINE,Reason])
end.
More information about the erlang-questions
mailing list