...
 
Commits (31)
Welcome to the Spicey web application framework!
The Spicey Web Application Framework
====================================
To generate an application, follow the steps below.
1. Create a Curry program containing a constant of type `Database.ERD.ERD`
(the module `Database.ERD` is part of the package `cdbi`)
which describes your entity-relationship model
(see the file "examples/BlogERD.curry" as an example).
2. Change to the directory in which you want to create the project.
3. From there execute `spiceup` and supply the name of the term file,
e.g.,
2. Execute `spiceup` and supply the name of the Curry ERD program, e.g.,
spiceup .../BlogERD.curry
This generates the complete source code of the initial application
as a Curry package
(see the generated file README.txt for some explanations).
You can also provide a file name for the SQLite3 database in which
all data is stored, e.g.,
spiceup --db BlogData.db .../Blog.erdterm
spiceup --db BlogData.db .../BlogERD.curry
If the parameter "--db ..." is not provided, then the name of database
file is "<ERD>.db" where <ERD> is the name of the specified ER model.
Since this file name will be used in the _generated_ cgi programs,
a relative file name will be relative to the place where
the cgi programs are stored.
the cgi programs are stored. In order to avoid confusion due to
relative file names, it might be better to specify
an absolute path name for the database file.
This path could also be set in the definition of the constant
`sqliteDBFile` in the generated Curry program `Model/<ERD>.curry`.
3. Change into the generated directory containing all sources as a
Curry package, e.g., by `cd Blog`.
4. Compile the generated programs by `make compile`.
4. Install all required packages by `make install`.
5. Configure the Makefile (variable WEBSERVERDIR) and execute
5. Compile the generated programs by `make compile`.
6. Configure the Makefile (variable WEBSERVERDIR) and execute
`make deploy` to deploy the web application.
6. After the successful compilation, the application is executable
7. After the successful compilation, the application is executable
in a web browser by loading `<URL of web dir>/spicey.cgi`.
Note that the database is generated with the `cdbi` package.
Hence, one can also use embedded SQL statements when further developing
the Curry code. The syntax and use of such embedded SQL statements
is described in the Curry preprocessor.
......@@ -2,4 +2,7 @@ This directory contains some documention for the tool:
manual.tex:
A short description to be included in the main manual of the Curry system.
\ No newline at end of file
main.tex:
The manual as a stand-alone LaTeX file.
\documentclass[11pt,fleqn]{article}
\usepackage[T1]{fontenc}
\usepackage{latexsym}
\usepackage{url}
\usepackage{xspace}
\usepackage{graphicx}
\setlength{\textwidth}{16.5cm}
\setlength{\textheight}{23cm}
\renewcommand{\baselinestretch}{1.1}
\setlength{\topmargin}{-1cm}
\setlength{\oddsidemargin}{0cm}
\setlength{\evensidemargin}{0cm}
\setlength{\marginparwidth}{0.0cm}
\setlength{\marginparsep}{0.0cm}
\newlength{\figurewidth}
\setlength{\figurewidth}{\textwidth}
\addtolength{\figurewidth}{-0.4cm}
% font for program texts
\renewcommand{\tt}{\usefont{OT1}{cmtt}{m}{n}\selectfont}
\newcommand{\codefont}{\small\tt}
\usepackage{listings}
\lstset{aboveskip=1.5ex,
belowskip=1.5ex,
showstringspaces=false, % no special string space
mathescape=true,
flexiblecolumns=false,
xleftmargin=2ex,
basewidth=0.52em,
basicstyle=\small\ttfamily}
\lstset{literate={->}{{$\rightarrow{}\!\!\!$}}3
}
\lstnewenvironment{curry}{}{}
\lstnewenvironment{currynomath}{\lstset{mathescape=false}}{} % Curry w/o math
\newcommand{\listline}{\vrule width0pt depth1.75ex}
% program text in normal text
\newcommand{\code}[1]{\mbox{\codefont #1}}
% program text in normal text with apostrophs
\newcommand{\ccode}[1]{``\code{#1}''}
\newcommand{\pindex}[1]{\index{#1@{\tt #1}}} % program elements in index
\newcommand{\todo}[1]{\fbox{\sc To do: #1}}
\newcommand{\CYS}{Curry\xspace} % name of the Curry system described here
\newcommand{\cyshome}{\mbox{\textit{curryhome}}\xspace} % symbolic installation directory
\newcommand{\us}{\char95\xspace} % underscore
\begin{document}
\sloppy
\newcommand{\curryppdocs}{.}
\input{manual.tex}
% Bibliography
\begin{thebibliography}{10}
\bibitem{BrasselHanusMueller08PADL}
B.~Bra{\ss}el, M.~Hanus, and M.~M{\"u}ller.
\newblock High-level database programming in {Curry}.
\newblock In {\em Proc. of the Tenth International Symposium on Practical
Aspects of Declarative Languages (PADL'08)}, pages 316--332. Springer LNCS
4902, 2008.
\bibitem{HanusKoschnicke14TPLP}
M.~Hanus and S.~Koschnicke.
\newblock An {ER-based} framework for declarative web programming.
\newblock {\em Theory and Practice of Logic Programming}, 14(3):269--291, 2014.
\bibitem{HanusKrone17EPTCS}
M.~Hanus and J.~Krone.
\newblock A typeful integration of {SQL} into {Curry}.
\newblock In {\em Proceedings of the 24th International Workshop on Functional
and (Constraint) Logic Programming}, volume 234 of {\em Electronic
Proceedings in Theoretical Computer Science}, pages 104--119. Open Publishing
Association, 2017.
\end{thebibliography}
\end{document}
......@@ -15,8 +15,7 @@ inconsistent state of the database.
\subsection{Installation}
The actual implementation of Spicey is a package
managed by the Curry Package Manager CPM
(see also Section~\ref{sec-cpm}).
managed by the Curry Package Manager CPM.
Thus, to install the newest version of Spicey, use the following commands:
%
\begin{curry}
......@@ -29,7 +28,7 @@ the executable \code{spiceup} into the directory \code{\$HOME/.cpm/bin}.
Hence it is recommended to add this directory to your path
in order to execute Spicey as described below.
\subsection{Usage}
\subsection{Basic usage}
The idea of this tool, which is part of the distribution of \CYS,
is described in detail in \cite{HanusKoschnicke14TPLP}.
......@@ -39,13 +38,13 @@ in order to generate a web application.
First, one has to create a textual description of the
entity-relationship model
in a Curry program file as an (exported!) top-level operation type \code{ERD}
(w.r.t.\ the type definitions given in the system library
\code{Database.ERD})
(w.r.t.\ the type definitions defined in the module \code{Database.ERD}
of the package \code{cdbi})
and store it in some program file, e.g., \ccode{MyERD.curry}.
The directory \code{examples} in the package \code{spicey}\footnote{%
If you installed Spicey as described above,
the downloaded \code{spicey} package is located in the directory
\code{\$HOME/.cpm/bin_packages/spicey}.}
\code{\$HOME/.cpm/app\us{}packages/spicey}.}
contains two examples for such ERD program files:
\begin{description}
\item[\code{BlogERD.curry}:]
......@@ -56,17 +55,16 @@ This is an ER model for university lectures as
presented in the paper \cite{BrasselHanusMueller08PADL}.
\end{description}
%
Then change to the directory in which you want to create
the project sources.
Execute the command\pindex{spiceup}
Then you can generate the sources of your web application
by the command\pindex{spiceup}
\begin{curry}
spiceup .../MyERD.curry
> spiceup MyERD.curry
\end{curry}
with the path to the ERD program as a parameter
with the ERD program as a parameter.
You can also provide a file name for the SQLite3 database used
by the application generated by Spicey, e.g.,
\begin{curry}
spiceup --db MyData.db .../MyERD.curry
> spiceup --db MyData.db MyERD.curry
\end{curry}
If the parameter \ccode{--db DBFILE} is not provided,
then \code{DBDFILE} is set to the default name \ccode{$ERD$.db}
......@@ -76,20 +74,44 @@ a relative database file name will be relative to the place where
the web programs are stored.
In order to avoid such confusion, it might be better to specify
an absolute path name for the database file.
This path could also be set in the definition of the constant
\code{sqliteDBFile} in the generated Curry program
\code{Model/$ERD$.curry}.
After the generation of this project (see the generated file
\code{README.txt} for information about the generated project structure),
one can compile the generated programs by
Spicey generates the web application as a Curry package in a new
directory. Thus, change into this directory (e.g., \code{cd $ERD$})
and install all required packages by the command
\begin{curry}
make compile
> make install
\end{curry}
%
The generated file \code{README.txt} contains some information
about the generated project structure.
One can compile the generated programs by
\begin{curry}
> make compile
\end{curry}
In order to generate the executable web application,
configure the generated \code{Makefile}
by adapting the variable \code{WEBSERVERDIR} to the location
where the compiled cgi programs should be stored, and run
\begin{curry}
make deploy
> make deploy
\end{curry}
After the successful compilation and deployment of all files,
the application is executable
in a web browser by selecting the URL \code{<URL of web dir>/spicey.cgi}.
\subsection{Further remarks}
The application generated by Spicey is a schematic initial implementation.
It provides an appropriate basic programming structure but
it can be extended in various ways.
In particular, one can also use embedded SQL statements
(see \cite{HanusKrone17EPTCS} for details)
when further developing the Curry code, since the underlying database
access operations are generated with the \code{cdbi} package.
The syntax and use of such embedded SQL statements
is sketched in \cite{HanusKrone17EPTCS} and
described in the Curry preprocessor.
{
"name": "spicey",
"version": "1.1.0",
"version": "3.1.0",
"author": "Michael Hanus <mh@informatik.uni-kiel.de>",
"synopsis": "A web application framework for Curry",
"category": [ "Web", "Database" ],
"dependencies": {
"abstract-curry": ">= 1.0.0",
"ertools" : ">= 1.0.0"
"base" : ">= 1.0.0, < 2.0.0",
"abstract-curry": ">= 2.0.0",
"ertools" : ">= 2.0.0"
},
"compilerCompatibility": {
"pakcs": ">= 1.14.0, < 2.0.0",
"kics2": ">= 0.5.0, < 2.0.0"
"pakcs": ">= 2.0.0",
"kics2": ">= 2.0.0"
},
"configModule": "Spicey.PackageConfig",
"executable": {
......@@ -21,6 +22,10 @@
"src-dir": "examples",
"modules": [ "TestSpicey" ]
},
"documentation": {
"src-dir": "docs",
"main": "main.tex"
},
"source": {
"git": "https://git.ps.informatik.uni-kiel.de/curry-packages/spicey.git",
"tag": "$version"
......
--- Some global configurations for the Spicey application.
module Config.Spicey
where
--- Location of the directory containing private run-time data
--- such as session and authentication information.
spiceyDataDir :: String
spiceyDataDir = "data"
......@@ -5,18 +5,18 @@
--- a controller to start selected user processes.
--------------------------------------------------------------------------
module Controller.SpiceySystemController
module Controller.SpiceySystem
(loginController,processListController,historyController)
where
import ReadNumeric
import Config.UserProcesses
import System.Spicey
import System.Session
import Config.UserProcesses
import System.Processes
import View.SpiceySystemView
import System.Authentication
import View.SpiceySystem
import Controller.DefaultController
-----------------------------------------------------------------------------
......
......@@ -18,6 +18,15 @@ SRCDIR := $(CURDIR)/src
# The load path for the Spicey application:
export CURRYPATH := $(SRCDIR):$(SRCDIR)/Model
# Executable of CPNSD:
CPNSD := $(shell which curry-cpnsd)
# Executable of the CGI registry and submission form:
CURRYCGI := $(shell which curry-cgi)
# Executable of the makecgi:
MAKECGI := $(shell which curry-makecgi)
############################################################################
.PHONY: all
all:
@echo "make: deploy install compile load run clean?"
......@@ -27,31 +36,46 @@ all:
install:
$(CPM) install
# check presence of tools required for deployment and install them:
.PHONY: checkdeploy
checkdeploy:
@if [ ! -x "$(CPNSD)" ] ; then \
echo "Installing required executable 'curry-cpnsd'..." ; \
$(CPM) install cpns ; fi
@if [ ! -x "$(CURRYCGI)" ] ; then \
echo "Installing required executable 'curry-cgi'..." ; \
$(CPM) install html-cgi ; fi
@if [ ! -x "$(MAKECGI)" ] ; then \
echo "Installing required executable 'curry-makecgi'..." ; \
$(CPM) install html ; fi
# Compile the generated Spicey application:
.PHONY: compile
compile:
$(CPM) exec $(CURRYBIN)/curry $(CURRYOPTIONS) :load Main :quit
$(CURRYBIN)/curry $(CURRYOPTIONS) :load Main :quit
# Load the generated Spicey application into the Curry system so that
# one can evaluate some expressions:
.PHONY: load
load:
$(CPM) exec $(CURRYBIN)/curry $(CURRYOPTIONS) :load Main
$(CURRYBIN)/curry $(CURRYOPTIONS) :load Main
# Runs the generated Spicey application by evaluating the main expression.
# This might be useful to test only the initial web page without a web server
.PHONY: run
run:
$(CPM) exec $(CURRYBIN)/curry $(CURRYOPTIONS) :load Main :eval main :q
$(CURRYBIN)/curry $(CURRYOPTIONS) :load Main :eval main :q
# Deploy the generated Spicey application, i.e., install it in the
# web directory WEBSERVERDIR:
.PHONY: deploy
deploy:
deploy: checkdeploy
mkdir -p $(WEBSERVERDIR)
$(CPM) exec $(CURRYBIN)/curry makecgi -standalone -m main -o $(WEBSERVERDIR)/spicey.cgi Main.curry
$(CPM) exec $(MAKECGI) -standalone -m main -o $(WEBSERVERDIR)/spicey.cgi Main.curry
# copy other files (style sheets, images,...)
cp -r public/* $(WEBSERVERDIR)
mkdir -p $(WEBSERVERDIR)/data # create private data dir
cp -p data/htaccess $(WEBSERVERDIR)/data/.htaccess # and make it private
chmod -R go+rX $(WEBSERVERDIR)
# clean up generated the package directory
......
......@@ -26,13 +26,13 @@ The directory structure of this package as follows
src/Model/
This directory contains the implementation of the data model, i.e.,
it contains the Curry module <MODEL>.curry implementing the access
to the database which are generated from the ER description. If you
want to add more complex integrity constraints on update operations,
you should extend the Curry code in this module.
In addition to the Curry programs, this directory also contains
the term files of the original and transformed ER description
(files `<MODEL>_ERD.term` and `<MODEL>_ERDT.term`) and the
Curry file of the original ER description (file `<MODEL>_ERD.curry`).
to the database which are generated from the ER description.
In addition to the Curry program, this directory also contains
the Curry file of the original ER description (file `<MODEL>_ERD.curry`),
the term files of the transformed ER description (`<MODEL>_ERDT.term`),
and the info file `<MODEL>_SQLCode.info` which is used by
the Curry preprocessor when SQL queries are embedded in the source
code.
src/Controller/
This directory contains the implementation of the various
......
......@@ -13,11 +13,14 @@ module System.Session (
getSessionData, putSessionData, removeSessionData
) where
import HTML.Base
import Time
import FilePath ( (</>) )
import Global
import List
import Time
import HTML.Base
import Config.Spicey ( spiceyDataDir )
import System.Crypto
--- The life span in minutes to store data in sessions.
......@@ -32,11 +35,12 @@ sessionCookieName = "spiceySessionId"
--- This global value saves time and last session id.
lastId :: Global (Int, Int)
lastId = global (0, 0) (Persistent sessionCookieName)
lastId = global (0, 0) (Persistent (spiceyDataDir </> sessionCookieName))
--- The abstract type to represent session identifiers.
data SessionId = SessionId String
deriving Eq
getId :: SessionId -> String
getId (SessionId i) = i
......
......@@ -14,7 +14,11 @@ module System.SessionInfo (
getUserSessionInfo, updateUserSessionInfo
) where
import FilePath ( (</>) )
import Global
import Config.Spicey ( spiceyDataDir )
import System.Session
--------------------------------------------------------------------------
......@@ -39,7 +43,8 @@ setUserLoginOfSession login (SD _) = SD login
--------------------------------------------------------------------------
--- Definition of the session state to store the login name (as a string).
userSessionInfo :: Global (SessionStore UserSessionInfo)
userSessionInfo = global emptySessionStore (Persistent "userSessionInfo")
userSessionInfo =
global emptySessionStore (Persistent (spiceyDataDir </> "userSessionInfo"))
--- Gets the data of the current user session.
getUserSessionInfo :: IO UserSessionInfo
......
......@@ -17,7 +17,7 @@ module System.Spicey (
nextInProcessOr,
stringToHtml, maybeStringToHtml,
intToHtml,maybeIntToHtml, floatToHtml, maybeFloatToHtml,
boolToHtml, maybeBoolToHtml, calendarTimeToHtml, maybeCalendarTimeToHtml,
boolToHtml, maybeBoolToHtml, dateToHtml, maybeDateToHtml,
userDefinedToHtml, maybeUserDefinedToHtml,
spTable,
setPageMessage, getPageMessage,
......@@ -31,7 +31,7 @@ import ReadShowTerm(readsQTerm)
import System
import Time
import Database.KeyDatabaseSQLite
import Database.CDBI.Connection ( SQLResult )
import HTML.Base
import HTML.Styles.Bootstrap3
import WUI
......@@ -59,11 +59,11 @@ type ViewBlock = [HtmlExp]
type Controller = IO ViewBlock
--- Reads an entity for a given key and applies a controller to it.
applyControllerOn :: Maybe enkey -> (enkey -> Transaction en)
applyControllerOn :: Maybe enkey -> (enkey -> IO en)
-> (en -> Controller) -> Controller
applyControllerOn Nothing _ _ = displayError "Illegal URL"
applyControllerOn (Just userkey) getuser usercontroller =
runJustT (getuser userkey) >>= usercontroller
getuser userkey >>= usercontroller
nextController :: Controller -> _ -> IO HtmlForm
nextController controller _ = do
......@@ -99,11 +99,11 @@ confirmController question yescontroller nocontroller = do
--- transaction error is shown.
--- @param trans - the transaction to be executed
--- @param controller - the controller executed in case of success
transactionController :: (Transaction _) -> Controller -> Controller
transactionController :: IO (SQLResult _) -> Controller -> Controller
transactionController trans controller = do
transResult <- runT trans
either (\_ -> controller)
(\error -> displayError (showTError error))
transResult <- trans
either (\error -> displayError (show error))
(\_ -> controller)
transResult
--- If we are in a process, execute the next process depending on
......@@ -178,14 +178,16 @@ renderWuiForm wuispec initdata controller cancelcontroller title buttontag =
--- A WUI for manipulating CalendarTime entities.
--- It is based on a WUI for dates, i.e., the time is ignored.
wDateType :: WuiSpec CalendarTime
wDateType :: WuiSpec ClockTime
wDateType = transformWSpec (tuple2date,date2tuple) wDate
where
tuple2date :: (Int, Int, Int) -> CalendarTime
tuple2date (day, month, year) = CalendarTime year month day 0 0 0 0
tuple2date :: (Int, Int, Int) -> ClockTime
tuple2date (day, month, year) =
toClockTime (CalendarTime year month day 0 0 0 0)
date2tuple :: CalendarTime -> (Int, Int, Int)
date2tuple( CalendarTime year month day _ _ _ _) = (day, month, year)
date2tuple :: ClockTime -> (Int, Int, Int)
date2tuple ct = let CalendarTime year month day _ _ _ _ = toUTCTime ct
in (day, month, year)
--- A WUI for manipulating date entities.
wDate :: WuiSpec (Int, Int, Int)
......@@ -199,7 +201,7 @@ wBoolean :: WuiSpec Bool
wBoolean = wSelectBool "True" "False"
--- A WUI transformer to map WUIs into WUIs for corresponding Maybe types.
wUncheckMaybe :: a -> WuiSpec a -> WuiSpec (Maybe a)
wUncheckMaybe :: Eq a => a -> WuiSpec a -> WuiSpec (Maybe a)
wUncheckMaybe defval wspec =
wMaybe (transformWSpec (not,not) (wCheckBool [htxt "No value"]))
wspec
......@@ -246,13 +248,13 @@ spiceyFooter =
--- Transforms a view into an HTML form by adding the basic page layout.
getForm :: ViewBlock -> IO HtmlForm
getForm viewblock =
if viewblock == [HtmlText ""]
then return $ HtmlForm "forward to Spicey"
getForm viewblock = case viewblock of
[HtmlText ""] ->
return $ HtmlForm "forward to Spicey"
[formMetaInfo [("http-equiv","refresh"),
("content","1; url=spicey.cgi")]]
[par [htxt "You will be forwarded..."]]
else do
_ -> do
routemenu <- getRouteMenu
msg <- getPageMessage
login <- getSessionLogin
......@@ -332,17 +334,17 @@ boolToHtml b = textstyle "type_bool" (show b)
maybeBoolToHtml :: Maybe Bool -> HtmlExp
maybeBoolToHtml b = textstyle "type_bool" (maybe "" show b)
calendarTimeToHtml :: CalendarTime -> HtmlExp
calendarTimeToHtml ct = textstyle "type_calendartime" (toDayString ct)
dateToHtml :: ClockTime -> HtmlExp
dateToHtml ct = textstyle "type_calendartime" (toDayString (toUTCTime ct))
maybeCalendarTimeToHtml :: Maybe CalendarTime -> HtmlExp
maybeCalendarTimeToHtml ct =
textstyle "type_calendartime" (maybe "" toDayString ct)
maybeDateToHtml :: Maybe ClockTime -> HtmlExp
maybeDateToHtml ct =
textstyle "type_calendartime" (maybe "" (toDayString . toUTCTime) ct)
userDefinedToHtml :: _ -> HtmlExp
userDefinedToHtml :: Show a => a -> HtmlExp
userDefinedToHtml ud = textstyle "type_string" (show ud)
maybeUserDefinedToHtml :: Maybe a -> HtmlExp
maybeUserDefinedToHtml :: Show a => Maybe a -> HtmlExp
maybeUserDefinedToHtml ud = textstyle "type_string" (maybe "" show ud)
--------------------------------------------------------------------------
......
......@@ -5,7 +5,7 @@
--- and a view of a list of user processes.
--------------------------------------------------------------------------
module View.SpiceySystemView
module View.SpiceySystem
( loginView, processListView, historyView )
where
......
AuthType Basic
AuthName Spicey
AuthUserFile /dev/null
AuthGroupFile /dev/null
<Limit GET>
<IfVersion < 2.3>
# old access rules
order deny,allow
deny from all
satisfy any
#allow from 127.0.0.
</IfVersion>
<IfVersion >= 2.3>
# new access rules via authz_mod_core
Require all denied
#Require local
</IfVersion>
</Limit>
......@@ -5,13 +5,14 @@
"synopsis": "Web application 'XXXPKGNAMEXXX' generated by Spicey",
"category": [ "Web" ],
"dependencies": {
"keydb": ">= 1.0.0",
"html" : ">= 1.1.0",
"wui" : ">= 1.1.0"
"base" : ">= 1.0.0, < 2.0.0",
"cdbi" : ">= 2.0.0",
"html" : ">= 2.1.0",
"wui" : ">= 2.0.0"
},
"compilerCompatibility": {
"pakcs": ">= 1.14.0, < 2.0.0",
"kics2": ">= 0.5.0, < 2.0.0"
"pakcs": ">= 2.0.0",
"kics2": ">= 2.0.0"
},
"sourceDirs": [ "src", "src/Model" ]
}
This diff is collapsed.
......@@ -9,7 +9,7 @@ import Spicey.GenerationHelper
-- "main"-function
generateToHtml :: String -> [Entity] -> [Relationship] -> CurryProg
generateToHtml erdname allEntities relationships = CurryProg
generateToHtml erdname allEntities relationships = simpleCurryProg
(entitiesToHtmlModule erdname)
["WUI", "HTML.Base", "Time", spiceyModule, erdname] -- imports
[] -- typedecls
......@@ -37,7 +37,7 @@ type ToHtmlGenerator = String -> Entity -> [Relationship] -> [Entity] -> CFuncDe
toListView :: ToHtmlGenerator
toListView erdname (Entity entityName attrlist) _ _ =
cmtfunc
stCmtFunc
("The list view of a "++entityName++" entity in HTML format.\n"++
"This view is used in a row of a table of all entities.")
(thisModuleName erdname, (lowerFirst entityName)++"ToListView") 2 Public
......@@ -60,7 +60,7 @@ toListView erdname (Entity entityName attrlist) _ _ =
toShortView :: ToHtmlGenerator
toShortView erdname (Entity entityName attrlist) _ _ =
cmtfunc
stCmtFunc
("The short view of a "++entityName++" entity as a string.\n"++
"This view is used in menus and comments to refer to a "++entityName++" entity.")
(thisModuleName erdname, (lowerFirst entityName)++"ToShortView")
......@@ -92,7 +92,7 @@ toDetailsView erdname (Entity entityName attrlist) relationships allEntities =
eName = lowerFirst entityName
evar = (1,eName)
in
cmtfunc
stCmtFunc
("The detailed view of a "++entityName++" entity in HTML format.\n"++
if null (manyToOneEntities ++ manyToManyEntities) then "" else
"It also takes associated entities for every associated entity type.")
......@@ -163,11 +163,11 @@ labelList erdname (Entity entityName attrlist) relationships allEntities =
manyToManyEntities = manyToMany allEntities (Entity entityName attrlist)
manyToOneEntities = manyToOne (Entity entityName attrlist) relationships
in
cmtfunc
stCmtFunc
("The labels of a "++entityName++" entity, as used in HTML tables.")
(thisModuleName erdname, (lowerFirst entityName)++"LabelList") 2 Public
(
listType (listType (CTCons (html "HtmlExp") []))
listType (listType (baseType (html "HtmlExp")))
)
[simpleRule []
(list2ac (
......@@ -202,6 +202,6 @@ domainToString domain =
CharDom _ -> "char"
StringDom _ -> "string"
BoolDom _ -> "bool"
DateDom _ -> "calendarTime"
DateDom _ -> "date"
UserDefined _ _ -> "userDefined"
KeyDom _ -> "key"
\ No newline at end of file
......@@ -20,9 +20,9 @@ upperFirst [] = [] -- this case should not occur, but one never knows...
------------------------------------------------------------------------
--- Converts a string into a qualified name of the module
--- "Database.KeyDatabaseSQLite".
db :: String -> QName
db f = ("Database.KeyDatabaseSQLite", f)
--- "Database.CDBI.Connection".
dbconn :: String -> QName
dbconn f = ("Database.CDBI.Connection", f)
--- Converts a string into a qualified name of the module "HTML.Base".
html :: String -> QName
......@@ -170,7 +170,7 @@ viewFunctionName entityName viewFunction =
(viewModuleName entityName, viewFunction ++ entityName ++ "View")
viewBlockType :: CTypeExpr
viewBlockType = listType (CTCons (html "HtmlExp") [])
viewBlockType = listType (baseType (html "HtmlExp"))
attrType :: Attribute -> CTypeExpr
......@@ -181,7 +181,7 @@ attrType (Attribute _ t k False) =
(FloatDom _) -> ctvar "Float"
(StringDom _ ) -> ctvar "String"
(BoolDom _) -> ctvar "Bool"
(DateDom _) -> ctvar "CalendarTime"
(DateDom _) -> ctvar "ClockTime"
(UserDefined s _)-> ctvar s
(KeyDom _) -> ctvar "Key"
_ -> ctvar "Int"
......@@ -192,7 +192,7 @@ attrType (Attribute _ t k True) =
(FloatDom _) -> maybeType (ctvar "Float")
(StringDom _ ) -> ctvar "String"
(BoolDom _) -> maybeType (ctvar "Bool")
(DateDom _) -> maybeType (ctvar "CalendarTime")
(DateDom _) -> maybeType (ctvar "ClockTime")
(UserDefined s _)-> maybeType (ctvar s)
(KeyDom _) -> maybeType (ctvar "Key")
_ -> maybeType (ctvar "Int")
......@@ -217,8 +217,9 @@ attrDefaultValues defaultctime attrs = map defaultValue attrs
BoolDom (Just b) -> addJust (constF (pre (if b then "True" else "False")))
DateDom Nothing -> nothingOrDefault
DateDom (Just (CalendarTime y mo d h m s tz))
-> addJust (applyF ("Time", "CalendarTime")
(map (CLit . CIntc) [y,mo,d,h,m,s,tz]))
-> addJust (applyF ("Time", "toClockTime")
[applyF ("Time", "CalendarTime")
(map (CLit . CIntc) [y,mo,d,h,m,s,tz])])
UserDefined _ _ -> nothingOrDefault
KeyDom _ -> nothingOrDefault
_ -> error "GenerationHelper.attrDefaultValues: unknown domain for attribute"
......@@ -253,30 +254,22 @@ isStringDom dom = case dom of
StringDom _ -> True
_ -> False
hasCalendarTimeAttribute :: [Attribute] -> Bool
hasCalendarTimeAttribute = any isCalendarTime
hasDateAttribute :: [Attribute] -> Bool
hasDateAttribute = any isDate
where
isCalendarTime (Attribute _ domain _ _) = case domain of
isDate (Attribute _ domain _ _) = case domain of
DateDom _ -> True
_ -> False
combinator :: Int -> QName
combinator n =
case n of
0 -> error "GenerationHelper.combinator: empty attribute list"
1 -> error "GenerationHelper.combinator: no combinator for list of length 1"
2 -> (wui "wPair")
3 -> (wui "wTriple")
4 -> (wui "w4Tuple")
5 -> (wui "w5Tuple")
6 -> (wui "w6Tuple")
7 -> (wui "w7Tuple")
8 -> (wui "w8Tuple")
9 -> (wui "w9Tuple")
10 -> (wui "w10Tuple")
11 -> (wui "w11Tuple")
12 -> (wui "w12Tuple")
_ -> error "GenerationHelper.combinator: attribute list too long"
combinator n
| n==0 = error "GenerationHelper.combinator: empty attribute list"
| n==1
= error "GenerationHelper.combinator: no combinator for list of length 1"
| n>14 = error "GenerationHelper.combinator: attribute list too long"
| n==2 = (wui "wPair")
| n==3 = (wui "wTriple")
| otherwise = (wui $ "w" ++ show n ++ "Tuple")
-- Associate to each attribute of the argument list a WUI specification
-- as an abstract Curry program
......@@ -306,7 +299,8 @@ widgetFor domain null =
if null
then applyF (spiceyModule,"wUncheckMaybe")
[domainDefaultValue
(applyF ("Time", "CalendarTime")
(map (CLit . CIntc) [2016,1,1,0,0,0,0]))
(applyF ("Time", "toClockTime")
[applyF ("Time", "CalendarTime")
(map (CLit . CIntc) [2018,1,1,0,0,0,0])])
domain, e]
else e
......@@ -10,14 +10,14 @@ import Spicey.GenerationHelper
generateRoutesForERD :: ERD -> CurryProg
generateRoutesForERD (ERD _ entities _) =
let spiceySysCtrl = "Controller.SpiceySystemController" in
CurryProg
let spiceySysCtrl = "Controller.SpiceySystem" in
simpleCurryProg
mappingModuleName
([spiceyModule, "System.Routes", spiceySysCtrl, dataModuleName] ++
(map (\e -> controllerModuleName (entityName e)) entities)) -- imports
[] -- typedecls
[
cmtfunc
stCmtFunc
("Maps the controllers associated to URLs in module RoutesData\n"++
"into the actual controller operations.")
(mappingModuleName, "getController")
......@@ -51,18 +51,18 @@ branchesForEntity (Entity entityName _) =
"main" ++ controllerReference))
generateStartpointDataForERD :: ERD -> CurryProg
generateStartpointDataForERD (ERD _ entities _) = CurryProg
generateStartpointDataForERD (ERD _ entities _) = simpleCurryProg
dataModuleName
[authenticationModule] -- imports
[
CType (dataModuleName, "ControllerReference") Public []
([CCons (dataModuleName, "ProcessListController") Public [],
CCons (dataModuleName, "LoginController") Public []] ++
map controllerReferencesForEntity entities),
([simpleCCons (dataModuleName, "ProcessListController") Public [],
simpleCCons (dataModuleName, "LoginController") Public []] ++
map controllerReferencesForEntity entities) [],
urlMatchType,
routeType
] -- typedecls
[cmtfunc
[stCmtFunc
("This constant specifies the association of URLs to controllers.\n"++
"Controllers are identified here by constants of type\n"++
"ControllerReference. The actual mapping of these constants\n"++
......@@ -127,11 +127,11 @@ generateStartpointDataForERD (ERD _ entities _) = CurryProg
urlMatchType :: CTypeDecl
urlMatchType =
CType (dataModuleName, "UrlMatch") Public [] [
CCons (dataModuleName, "Exact") Public [stringType],
CCons (dataModuleName, "Prefix") Public [stringType,stringType],
CCons (dataModuleName, "Matcher") Public [stringType ~> boolType],
CCons (dataModuleName, "Always") Public []
]
simpleCCons (dataModuleName, "Exact") Public [stringType],
simpleCCons (dataModuleName, "Prefix") Public [stringType,stringType],
simpleCCons (dataModuleName, "Matcher") Public [stringType ~> boolType],
simpleCCons (dataModuleName, "Always") Public []
] []
routeMappingType :: CTypeExpr
routeMappingType = listType (baseType (dataModuleName,"Route"))
......@@ -145,4 +145,4 @@ generateStartpointDataForERD (ERD _ entities _) = CurryProg
controllerReferencesForEntity :: Entity -> CConsDecl
controllerReferencesForEntity (Entity entityName _) =
CCons (dataModuleName, entityName++"Controller") Public []
simpleCCons (dataModuleName, entityName++"Controller") Public []
......@@ -8,11 +8,12 @@ import AbstractCurry.Types
import AbstractCurry.Build
import AbstractCurry.Pretty hiding(showCProg)
import Database.ERD
import Directory
import FilePath ( (</>) )
import IO
import System(system)
import ERD2Curry ( erd2curryWithDBandERD )
import ERD2Curry ( erd2cdbiWithDBandERD )
import Database.ERD.Goodies
import Spicey.ControllerGeneration
......@@ -58,8 +59,6 @@ createControllers _ (ERD name entities relationship) path _ = do
putStrLn "Generating default controller authorization 'AuthorizedControllers.curry'..."
writeFile (path </> "DefaultController.curry")
(showCProg (generateDefaultController name entities))
writeFile (path </> "AuthorizedControllers.curry")
(showCProg (generateAuthorizations name entities))
where
erdt = transform (ERD name entities relationship)
......@@ -70,6 +69,12 @@ createControllers _ (ERD name entities relationship) path _ = do
(showCProg (generateControllersForEntity erdname allEntities
(Entity ename attrlist) relationships))
createAuthorizations :: String -> ERD -> String -> String -> IO ()
createAuthorizations _ (ERD name entities _) path _ = do
let targetfile = path </> "AuthorizedActions.curry"
putStrLn $ "Generating default action authorization '" ++ targetfile ++ "'..."
writeFile targetfile (showCProg (generateAuthorizations name entities))
createHtmlHelpers :: String -> ERD -> String -> String -> IO ()
createHtmlHelpers _ (ERD name entities relationship) path _ =
saveToHtml name (getEntities erdt) (getRelationships erdt)
......@@ -83,18 +88,17 @@ createHtmlHelpers _ (ERD name entities relationship) path _ =
hPutStr fileh (showCProg (generateToHtml erdname allEntities relationships))
hClose fileh
-- uses Curry's ertools for ERD to Curry transformation
-- Uses Curry's `ertools` for ERD to Curry transformation
createModels :: String -> ERD -> String -> String -> IO ()
createModels term_path erd path db_path = do
let dbfile = if null db_path then erdName erd ++ ".db"
let erdname = erdName erd
dbfile = if null db_path then erdname ++ ".db"
else db_path
erd2curryWithDBandERD dbfile term_path
let orgerdfile = erdName erd ++ "_ERD.term"
transerdfile = erdName erd ++ "_ERDT.term"
curryfile = erdName erd ++ ".curry"
system $ unwords ["mv", transerdfile, curryfile, "ERDGeneric.curry", path]
system $ unwords ["cp", term_path, path </> orgerdfile]
done
aterm_path <- getAbsolutePath term_path
curdir <- getCurrentDirectory
setCurrentDirectory path
erd2cdbiWithDBandERD dbfile term_path
setCurrentDirectory curdir
createRoutes :: String -> ERD -> String -> String -> IO ()
createRoutes _ erd path _ = do
......@@ -108,3 +112,43 @@ createRoutes _ erd path _ = do
hClose dmfileh
------------------------------------------------------------------------
-- Generate all default authorizations.
generateAuthorizations :: String -> [Entity] -> CurryProg
generateAuthorizations erdname entities = simpleCurryProg
enauthModName
[authorizationModule, sessionInfoModule, erdname] -- imports
[] -- typedecls
-- functions
(map operationAllowed entities)
[] -- opdecls
where
operationAllowed (Entity entityName _) =
stCmtFunc
("Checks whether the application of an operation to a "++entityName++"\n"++
"entity is allowed.")
(enauthModName, lowerFirst entityName ++ "OperationAllowed")
1
Public
(applyTC (authorizationModule,"AccessType") [baseType (erdname,entityName)]
~> baseType (sessionInfoModule,"UserSessionInfo")
~> ioType (baseType (authorizationModule,"AccessResult")))
[simpleRule [CPVar (1,"at"), CPVar (2,"_")]
(CCase CRigid (CVar (1,"at"))
[cBranch (CPComb (authorizationModule,"ListEntities") []) allowed,
cBranch (CPComb (authorizationModule,"NewEntity") []) allowed,
cBranch (CPComb (authorizationModule,"ShowEntity") [CPVar (3,"_")])
allowed,
cBranch (CPComb (authorizationModule,"DeleteEntity") [CPVar (3,"_")])
allowed,
cBranch (CPComb (authorizationModule,"UpdateEntity") [CPVar (3,"_")])
allowed])]
-- Expression implemented access allowed
allowed = applyF (pre "return") [constF (authorizationModule,"AccessGranted")]
-- Expression implemented access denied
--exprDenied = applyF (pre "return")
-- [applyF (authorizationModule,"AccessDenied")
-- [string2ac "Operation not allowed!"]]
------------------------------------------------------------------------
\ No newline at end of file
......@@ -2,25 +2,26 @@
module Spicey.SpiceUp where
import Database.ERD (ERD, readERDTermFile)
import Database.ERD.Goodies (erdName, storeERDFromProgram)
import Database.ERD ( ERD, readERDTermFile )
import Database.ERD.Goodies ( erdName, storeERDFromProgram )
import Directory
import Distribution
import FilePath ((</>))
import List (isSuffixOf, last)
import System (system, getArgs, exitWith)
import Distribution ( installDir )
import FilePath ( (</>), takeFileName )
import List ( isSuffixOf, last )
import System ( setEnviron, system, getArgs, exitWith )
import Spicey.PackageConfig (packagePath, packageVersion)
import Spicey.PackageConfig ( packagePath, packageVersion, packageLoadPath )
import Spicey.Scaffolding
systemBanner :: String
systemBanner =
let bannerText = "Spicey Web Framework (Version " ++ packageVersion ++
" of 11/10/17)"
" of 25/11/18)"
bannerLine = take (length bannerText) (repeat '-')
in bannerLine ++ "\n" ++ bannerText ++ "\n" ++ bannerLine
data FileMode = Exec | NoExec
deriving Eq
setFileMode :: FileMode -> String -> IO ()
setFileMode fmode filename =
......@@ -51,20 +52,25 @@ spiceyStructure pkgname =
ResourceFile NoExec "SessionInfo.curry",
ResourceFile NoExec "Authorization.curry",
ResourceFile NoExec "Authentication.curry",
ResourceFile NoExec "Processes.curry" ],
ResourceFile NoExec "Processes.curry",
GeneratedFromERD createAuthorizations ],
Directory "View" [
ResourceFile NoExec "SpiceySystemView.curry",
ResourceFile NoExec $ "View" </> "SpiceySystem.curry",
GeneratedFromERD createViews,
GeneratedFromERD createHtmlHelpers ],
Directory "Controller" [
ResourceFile NoExec "SpiceySystemController.curry",
ResourceFile NoExec $ "Controller" </> "SpiceySystem.curry",
GeneratedFromERD createControllers ],
Directory "Model" [
GeneratedFromERD createModels ],
Directory "Config" [
ResourceFile NoExec "UserProcesses.curry",
ResourceFile NoExec $ "Config" </> "Spicey.curry",
ResourceFile NoExec $ "Config" </> "UserProcesses.curry",
GeneratedFromERD createRoutes ]
],
Directory "data" [
ResourceFile NoExec $ "data" </> "htaccess"
],
Directory "public" [
ResourceFile NoExec "index.html",
ResourceFile NoExec "favicon.ico",
......@@ -109,13 +115,6 @@ replacePackageName pn (c:cs)
= pn ++ replacePackageName pn (drop 12 cs)
| otherwise = c : replacePackageName pn cs
copyFileLocal :: FileMode -> String -> String -> String -> IO ()
copyFileLocal fmode path resource_dir filename = do
let infile = resource_dir </> filename
let outfile = path </> filename
system $ "cp \"" ++ infile ++ "\" \"" ++ outfile ++ "\""
setFileMode fmode outfile
-- checks if given path exists (file or directory) and executes
-- given action if not
ifNotExistsDo :: String -> IO () -> IO ()
......@@ -131,11 +130,13 @@ createStructure :: String -> String -> ERD -> String -> String -> DirTree
-> IO ()
createStructure target_path resource_dir _ _ _
(ResourceFile fmode filename) = do
let full_path = target_path </> filename
ifNotExistsDo full_path $ do
putStrLn $ "Creating file '" ++ full_path ++ "'..."
copyFileLocal fmode target_path resource_dir filename
let infile = resource_dir </> filename
targetfile = target_path </> takeFileName filename
ifNotExistsDo targetfile $ do
putStrLn $ "Creating file '" ++ targetfile ++ "'..."
system $ "cp \"" ++ infile ++ "\" \"" ++ targetfile ++ "\""
setFileMode fmode targetfile
createStructure target_path resource_dir _ _ _
(ResourcePatchFile fmode filename f) = do
let full_path = target_path </> filename
......@@ -172,6 +173,8 @@ main = do
_ -> putStrLn ("Wrong arguments!\n") >> spiceupHelp 1
where
createStructureWith orgfile dbfile = do
-- set CURRYPATH in order to compile ERD model (which requires Database.ERD)
unless (null packageLoadPath) $ setEnviron "CURRYPATH" packageLoadPath
-- The directory containing the project generator:
let resourcedir = packagePath </> "resource_files"
exfile <- doesFileExist orgfile
......
......@@ -63,7 +63,8 @@ eRN i1 e1 e2 (ens,rels) r@(Relationship rname _)
(e:ens, r1:r2:rels)
eRJ :: Int -> Int -> Int -> String -> String -> ([Entity],[Relationship])
-> Relationship -> ([Entity],[Relationship])
-> Relationship
-> ([Entity],[Relationship])
eRJ i1 _ i3 e1 e2 (ens, rels) r@(Relationship rname _)
| i1==1 = (addFKey e1 e2 rname False (i3==1) ens ens, (r:rels)) --(1,1):(0,j)
| otherwise = if i3==1
......
......@@ -14,7 +14,7 @@ generateViewsForEntity erdname allEntities
(Entity ename attrlist) relationships =
let noKeyAttrs = filter (\a -> notKey a && notPKey a) attrlist
noPKeyAttrs = filter notPKey attrlist
in CurryProg
in simpleCurryProg
(viewModuleName ename)
[ "WUI", "HTML.Base", "Time", "Sort", bootstrapModule
, spiceyModule, sessionInfoModule
......@@ -44,16 +44,16 @@ wuiSpec erdname (Entity entityName attrlist) relationships allEntities =
manyToManyEntities = manyToMany allEntities (Entity entityName attrlist)
manyToOneEntities = manyToOne (Entity entityName attrlist) relationships
argumentCount = length attrlist + length manyToOneEntities
+ length manyToManyEntities
+ length manyToManyEntities
in
cmtfunc
stCmtFunc
("The WUI specification for the entity type "++entityName++".\n"++
if null (manyToOneEntities ++ manyToManyEntities)
then ""
else "It also includes fields for associated entities.")
(viewModuleName entityName, "w"++entityName) 2 Public
(foldr CFuncType
(CTCons ("WUI", "WuiSpec")
(applyTC ("WUI", "WuiSpec")
[entityInterface attrlist manyToOneEntities manyToManyEntities])
(map (\e -> listType (ctvar e))
(manyToOneEntities ++ manyToManyEntities))-- possible values
......@@ -65,13 +65,12 @@ wuiSpec erdname (Entity entityName attrlist) relationships allEntities =
head (attrWidgets attrlist)
else
applyF (combinator argumentCount)
(
(attrWidgets attrlist) ++
(map (\e -> applyF (wui "wSelect")
( attrWidgets attrlist ++
map (\e -> applyF (wui "wSelect")
[constF (erdname, lowerFirst e++"ToShortView"),
CVar (1, lowerFirst $ e ++ "List")])
manyToOneEntities) ++
(map (\e ->
manyToOneEntities ++
map (\e ->
applyF (wui "wMultiCheckSelect")
[CLambda [CPVar (1, lowerFirst e)]
(list2ac [
......@@ -80,19 +79,14 @@ wuiSpec erdname (Entity entityName attrlist) relationships allEntities =
[CVar (1, lowerFirst e)]
]]),
CVar (1, lowerFirst $ e ++ "List")
]) manyToManyEntities)
)
]) manyToManyEntities
)
),
applyF (spiceyModule, "renderLabels")
[constF (entitiesToHtmlModule erdname,
lowerFirst entityName++"LabelList")]
]
)]
where
getFirstAttributeName myEntityName =
gf (head (filter (\(Entity name _) -> name == myEntityName) allEntities))
gf (Entity _ (_:((Attribute name _ _ _):_))) = name
tuple2Entity :: ViewGenerator
......@@ -101,7 +95,7 @@ tuple2Entity erdname (Entity entityName attrlist) relationships allEntities =
manyToManyEntities = manyToMany allEntities (Entity entityName attrlist)
manyToOneEntities = manyToOne (Entity entityName attrlist) relationships
in
cmtfunc
stCmtFunc
("Transformation from data of a WUI form to entity type "++entityName++".")
(viewModuleName entityName, "tuple2"++entityName) 2 Public
(
......@@ -152,7 +146,7 @@ entity2Tuple erdname (Entity entityName attrlist) relationships allEntities =
manyToManyEntities = manyToMany allEntities (Entity entityName attrlist)
manyToOneEntities = manyToOne (Entity entityName attrlist) relationships
in
cmtfunc
stCmtFunc
("Transformation from entity type "++entityName++" to a tuple\n"++
"which can be used in WUI specifications.")
(viewModuleName entityName, (lowerFirst entityName)++"2Tuple") 2 Public
......@@ -200,13 +194,13 @@ wuiType _ (Entity entityName attrlist) relationships allEntities =
manyToManyEntities = manyToMany allEntities (Entity entityName attrlist)
manyToOneEntities = manyToOne (Entity entityName attrlist) relationships
in
cmtfunc
stCmtFunc
("WUI Type for editing or creating "++entityName++" entities.\n"++
"Includes fields for associated entities.")
(viewModuleName entityName, "w"++entityName++"Type") 2 Public
(
foldr CFuncType
(CTCons ("WUI", "WuiSpec") [
(applyTC ("WUI", "WuiSpec") [
if null manyToManyEntities
then ctvar entityName
else
......@@ -361,7 +355,7 @@ blankView _ (Entity entityName attrlist) relationships allEntities =
let
manyToManyEntities = manyToMany allEntities (Entity entityName attrlist)
manyToOneEntities = manyToOne (Entity entityName attrlist) relationships
withCTime = hasCalendarTimeAttribute attrlist
withCTime = hasDateAttribute attrlist
infovar = (0, "sinfo")
in
viewFunction
......@@ -371,7 +365,7 @@ blankView _ (Entity entityName attrlist) relationships allEntities =
( -- function type
userSessionInfoType ~>
foldr CFuncType viewBlockType (
(if withCTime then [baseType ("Time","CalendarTime")] else []) ++
(if withCTime then [baseType ("Time","ClockTime")] else []) ++
(map (\e -> listType (ctvar e))
(manyToOneEntities ++ manyToManyEntities)) ++ -- possible values
[entityInterface attrlist manyToOneEntities manyToManyEntities
......@@ -401,9 +395,11 @@ blankView _ (Entity entityName attrlist) relationships allEntities =
)]
-- Generate function to compare to entities in lexicographic order.
-- To avoid useless component comparisons, only the first five non-key
-- attributes are used for the comparison.
leqEntity :: ViewGenerator
leqEntity erdname (Entity entityName attrlist) _ _ =
cmtfunc
stCmtFunc
("Compares two "++entityName++" entities. This order is used in the list view.")
(viewModuleName entityName, "leq" ++ entityName) 2 Private
-- function type
......@@ -415,10 +411,10 @@ leqEntity erdname (Entity entityName attrlist) _ _ =
(applyF (pre "<=")
[tupleExpr (map (\ (Attribute a _ _ _) ->
applyF (erdname,ename++a) [CVar e1])
(filter notKey attrlist)),
(take 5 (filter notKey attrlist))),
tupleExpr (map (\ (Attribute a _ _ _) ->
applyF (erdname,ename++a) [CVar e2])
(filter notKey attrlist))
(take 5 (filter notKey attrlist)))
])]
......@@ -510,7 +506,7 @@ listView erdname (Entity entityName attrlist) _ _ =
]
]
)
[CLocalFunc (cfunc
[CLocalFunc (stFunc
(viewModuleName entityName, "list"++entityName) 2 Private
(ctvar entityName ~> listType viewBlockType)
[simpleRule [CPVar envar]
......@@ -556,8 +552,8 @@ listView erdname (Entity entityName attrlist) _ _ =
viewFunction :: String -> String -> String -> Int -> CTypeExpr -> [CRule]
-> CFuncDecl
viewFunction description entityName viewType arity functionType rules =
cmtfunc description (viewFunctionName entityName viewType) arity
Public functionType rules
stCmtFunc description (viewFunctionName entityName viewType) arity
Public functionType rules
entityInterface :: [Attribute] -> [String] -> [String] -> CTypeExpr
entityInterface attrlist manyToOne manyToMany =
......