adamc@915: con rawMeta = fn t :: Type => adamc@915: {New : transaction t, adamc@915: Inj : sql_injectable t} adamc@915: adamc@944: con colMeta' = fn (row :: {Type}) (input :: Type) (filter :: Type) => adamc@915: {Header : string, adamc@944: Project : $row -> transaction input, adamc@944: Update : $row -> input -> transaction ($row), adamc@944: Display : input -> xbody, adamc@944: Edit : input -> xbody, adamc@944: Validate : input -> signal bool, adamc@944: CreateFilter : transaction filter, adamc@944: DisplayFilter : filter -> xbody, adamc@961: Filter : filter -> $row -> signal bool, adamc@961: Sort : option ($row -> $row -> bool)} adamc@915: adamc@944: con colMeta = fn (row :: {Type}) (global_input_filter :: (Type * Type * Type)) => adamc@944: {Initialize : transaction global_input_filter.1, adamc@944: Handlers : global_input_filter.1 -> colMeta' row global_input_filter.2 global_input_filter.3} adamc@915: adamc@935: con aggregateMeta = fn (row :: {Type}) (acc :: Type) => adamc@935: {Initial : acc, adamc@935: Step : $row -> acc -> acc, adamc@935: Display : acc -> xbody} adamc@935: adamc@915: structure Direct : sig adamc@944: con metaBase = fn actual_input_filter :: (Type * Type * Type) => adamc@944: {Display : actual_input_filter.2 -> xbody, adamc@944: Edit : actual_input_filter.2 -> xbody, adamc@944: Initialize : actual_input_filter.1 -> transaction actual_input_filter.2, adamc@944: Parse : actual_input_filter.2 -> signal (option actual_input_filter.1), adamc@944: CreateFilter : transaction actual_input_filter.3, adamc@944: DisplayFilter : actual_input_filter.3 -> xbody, adamc@961: Filter : actual_input_filter.3 -> actual_input_filter.1 -> signal bool, adamc@961: Sort : actual_input_filter.1 -> actual_input_filter.1 -> bool} adamc@930: adamc@944: datatype metaBoth actual input filter = adamc@944: NonNull of metaBase (actual, input, filter) * metaBase (option actual, input, filter) adamc@944: | Nullable of metaBase (actual, input, filter) adamc@930: adamc@944: con meta = fn global_actual_input_filter :: (Type * Type * Type * Type) => adamc@944: {Initialize : transaction global_actual_input_filter.1, adamc@944: Handlers : global_actual_input_filter.1 adamc@944: -> metaBoth global_actual_input_filter.2 global_actual_input_filter.3 adamc@944: global_actual_input_filter.4} adamc@915: adamc@944: con editableState :: (Type * Type * Type * Type) -> (Type * Type * Type) adamc@944: val editable : ts ::: (Type * Type * Type * Type) -> rest ::: {Type} adamc@915: -> nm :: Name -> [[nm] ~ rest] => string -> meta ts adamc@915: -> colMeta ([nm = ts.2] ++ rest) adamc@915: (editableState ts) adamc@915: adamc@944: con readOnlyState :: (Type * Type * Type * Type) -> (Type * Type * Type) adamc@944: val readOnly : ts ::: (Type * Type * Type * Type) -> rest ::: {Type} adamc@915: -> nm :: Name -> [[nm] ~ rest] => string -> meta ts adamc@915: -> colMeta ([nm = ts.2] ++ rest) adamc@915: (readOnlyState ts) adamc@915: adamc@944: val nullable : global ::: Type -> actual ::: Type -> input ::: Type -> filter ::: Type adamc@944: -> meta (global, actual, input, filter) adamc@944: -> meta (global, option actual, input, filter) adamc@930: adamc@915: type intGlobal adamc@915: type intInput adamc@944: type intFilter adamc@944: val int : meta (intGlobal, int, intInput, intFilter) adamc@915: adamc@915: type stringGlobal adamc@915: type stringInput adamc@944: type stringFilter adamc@944: val string : meta (stringGlobal, string, stringInput, stringFilter) adamc@915: adamc@915: type boolGlobal adamc@915: type boolInput adamc@944: type boolFilter adamc@944: val bool : meta (boolGlobal, bool, boolInput, boolFilter) adamc@915: adamc@915: functor Foreign (M : sig adamc@915: con row :: {Type} adamc@915: con t :: Type adamc@915: val show_t : show t adamc@915: val read_t : read t adamc@915: val eq_t : eq t adamc@961: val ord_t : ord t adamc@915: val inj_t : sql_injectable t adamc@915: con nm :: Name adamc@915: constraint [nm] ~ row adamc@915: table tab : ([nm = t] ++ row) adamc@915: val render : $([nm = t] ++ row) -> string adamc@915: end) : sig adamc@944: type global adamc@944: type input adamc@944: type filter adamc@944: val meta : meta (global, M.t, input, filter) adamc@915: end adamc@915: end adamc@915: adamc@944: con computedState :: (Type * Type * Type) adamc@915: val computed : row ::: {Type} -> t ::: Type -> show t adamc@915: -> string -> ($row -> t) -> colMeta row computedState adamc@915: val computedHtml : row ::: {Type} -> string -> ($row -> xbody) -> colMeta row computedState adamc@915: adamc@915: functor Make(M : sig adamc@915: con key :: {Type} adamc@915: con row :: {Type} adamc@915: constraint key ~ row adamc@915: table tab : (key ++ row) adamc@915: adamc@915: val raw : $(map rawMeta (key ++ row)) adamc@915: adamc@944: con cols :: {(Type * Type * Type)} adamc@915: val cols : $(map (colMeta (key ++ row)) cols) adamc@915: adamc@915: val keyFolder : folder key adamc@915: val rowFolder : folder row adamc@915: val colsFolder : folder cols adamc@935: adamc@935: con aggregates :: {Type} adamc@935: val aggregates : $(map (aggregateMeta (key ++ row)) aggregates) adamc@937: val aggFolder : folder aggregates adamc@964: adamc@964: val pageLength : option int adamc@915: end) : sig adamc@915: type grid adamc@915: adamc@915: val grid : transaction grid adamc@915: val sync : grid -> transaction unit adamc@915: val render : grid -> xbody adamc@940: adamc@940: val showSelection : grid -> source bool adamc@940: val selection : grid -> signal (list ($(M.key ++ M.row))) adamc@915: end