The init-db! function in schema now creates the database correctly.

This commit is contained in:
simon 2016-10-13 16:23:12 +01:00
parent 70aaf92002
commit 3864a3851f
2 changed files with 135 additions and 108 deletions

View file

@ -57,3 +57,7 @@ as above; in the other, run
Copyright © 2016 Simon Brooke for the Radical Independence Campaign. Copyright © 2016 Simon Brooke for the Radical Independence Campaign.
Licensed under the GNU General Public License, version 2.0 or (at your option) any later version. Licensed under the GNU General Public License, version 2.0 or (at your option) any later version.
**NOTE THAT** files which are directly created by the Luminus template do not currently have a GPL header
at the top; files which are new in this project or which have been substantially modified for this project
do have a GPL header at the top.

View file

@ -27,6 +27,12 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Note that this is the (old) Korma way of doing things;
;;; it may not play well with migrations, nor with the HugSQL way of doing things recommended
;;; in Web Development with Clojure, Second Ed. So this may be temporary 'get us started' code,
;;; which later gets thrown away.
(defn create-districts-table! (defn create-districts-table!
"Create a table to hold the electoral districts in which electors are registered. "Create a table to hold the electoral districts in which electors are registered.
Note that, as this app is being developed for the independence referendum in which Note that, as this app is being developed for the independence referendum in which
@ -38,14 +44,14 @@
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:districts :districts
[;; it may be necessary to have a serial abstract primary key but I suspect ;; it may be necessary to have a serial abstract primary key but I suspect
;; polling districts already have numbers assigned by the Electoral Commission and ;; polling districts already have numbers assigned by the Electoral Commission and
;; it would be sensible to use those. TODO: check. ;; it would be sensible to use those. TODO: check.
[:id "integer not null primary key"] [:id "integer not null primary key"]
[:name "varchar(64) not null"] [:name "varchar(64) not null"]
;; TODO: it would make sense to hold polygon data for polling districts so we can reflect ;; TODO: it would make sense to hold polygon data for polling districts so we can reflect
;; them on the map, but I haven't thought through how to do that yet. ;; them on the map, but I haven't thought through how to do that yet.
]))) )))
(kc/defentity district (kc/defentity district
@ -62,18 +68,18 @@
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:addresses :addresses
[[:id "serial not null primary key"] [:id "serial not null primary key"]
;; we do NOT want to hold multiple address records for the same household. When we receive ;; we do NOT want to hold multiple address records for the same household. When we receive
;; the electoral roll data the addresses are likely to be text fields inlined in the elector ;; the electoral roll data the addresses are likely to be text fields inlined in the elector
;; record; in digesting the roll data we need to split these out and resolve them against existing ;; record; in digesting the roll data we need to split these out and resolve them against existing
;; addresses in the table, creating a new address record only if there's no match. ;; addresses in the table, creating a new address record only if there's no match.
[:address "varchar(256) not null unique"] [:address "varchar(256) not null unique"]
[:postcode "varchar(16)"] [:postcode "varchar(16)"]
[:phone "varchar(16)"] [:phone "varchar(16)"]
;; the electoral district within which this address exists ;; the electoral district within which this address exists
[:district_id "integer references districts(id)"] [:district_id "integer references districts(id)"]
[:latitude :real] [:latitude :real]
[:longitude :real]]))) [:longitude :real])))
(kc/defentity address (kc/defentity address
@ -84,16 +90,16 @@
(kc/has-one district)) (kc/has-one district))
(defn create-authority-table! (defn create-authorities-table!
"Create a table to hold the oauth authorities against which we with authenticate canvassers." "Create a table to hold the oauth authorities against which we with authenticate canvassers."
[] []
(sql/db-do-commands (sql/db-do-commands
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:authority :authorities
[[:id "varchar(32) not null primary key"] [:id "varchar(32) not null primary key"]
;; more stuff here when I understand more ;; more stuff here when I understand more
]))) )))
(kc/defentity authority (kc/defentity authority
@ -110,15 +116,15 @@
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:electors :electors
[;; id should be the roll number on the electoral roll, I think, but only if this is unique ;; id should be the roll number on the electoral roll, I think, but only if this is unique
;; across Scotland. Otherwise we need a separate id field. TODO: check. ;; across Scotland. Otherwise we need a separate id field. TODO: check.
[:id "integer primary key"] [:id "integer primary key"]
[:name "varchar(64) not null"] [:name "varchar(64) not null"]
[:address_id "integer not null references addresses(id)" ] [:address_id "integer not null references addresses(id)" ]
[:phone "varchar(16)"] [:phone "varchar(16)"]
;; we'll probably only capture email data on electors if they request a followup ;; we'll probably only capture email data on electors if they request a followup
;; on a particular issue by email. ;; on a particular issue by email.
[:email "varchar(128)"]]))) [:email "varchar(128)"])))
(kc/defentity elector (kc/defentity elector
@ -136,21 +142,21 @@
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:canvassers :canvassers
[;; id is the kc/kc/entity-fields. ;; id is the username the canvasser logs in as.
[:id "varchar(32) not null primary key"] [:id "varchar(32) not null primary key"]
[:fullname "varchar(64) not null"] [:fullname "varchar(64) not null"]
;; most canvassers will be electors, we should link them: ;; most canvassers will be electors, we should link them:
[:elector_id "integer references electors(id) on delete no action"] [:elector_id "integer references electors(id) on delete no action"]
;; but some canvassers may not be electors, so we need contact details separately: ;; but some canvassers may not be electors, so we need contact details separately:
[:address_id "integer not null references addresses(id)" ] [:address_id "integer not null references addresses(id)" ]
[:phone "varchar(16)"] [:phone "varchar(16)"]
[:email "varchar(128)"] [:email "varchar(128)"]
;; with which authority do we authenticate this canvasser? I do not want to hold even ;; with which authority do we authenticate this canvasser? I do not want to hold even
;; encrypted passwords locally ;; encrypted passwords locally
[:authority_id "varchar(32) not null references authority(id) on delete no action"] [:authority_id "varchar(32) not null references authorities(id) on delete no action"]
;; true if the canvasser is authorised to use the app; else false. This allows us to ;; true if the canvasser is authorised to use the app; else false. This allows us to
;; block canvassers we suspect of misbehaving. ;; block canvassers we suspect of misbehaving.
[:authorised :boolean]]))) [:authorised :boolean])))
(kc/defentity canvasser (kc/defentity canvasser
@ -163,17 +169,17 @@
(kc/has-one authority)) (kc/has-one authority))
(defn create-visit-table! (defn create-visits-table!
"Create a table to record visits by canvassers to addresses (including virtual visits by telephone)." "Create a table to record visits by canvassers to addresses (including virtual visits by telephone)."
[] []
(sql/db-do-commands (sql/db-do-commands
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:visits :visits
[[:id "serial not null primary key"] [:id "serial not null primary key"]
[:address_id "integer not null references address(id)"] [:address_id "integer not null references addresses(id)"]
[:canvasser_id "varchar(32) references canvassers(id) not null"] [:canvasser_id "varchar(32) references canvassers(id) not null"]
[:date "timestamp with timezone not null default now()"]]))) [:date "timestamp with time zone not null default now()"])))
(kc/defentity visit (kc/defentity visit
@ -185,20 +191,20 @@
(kc/has-one canvasser)) (kc/has-one canvasser))
(defn create-option-table! (defn create-options-table!
"Create a table to record options in the vote. This app is being created for the Independence "Create a table to record options in the vote. This app is being created for the Independence
referendum, which will have just two options, 'Yes' and 'No', but it might later be adapted referendum, which will have just two options, 'Yes' and 'No', but it might later be adapted
for more general political canvassing." for more general political canvassing."
[] []
(sql/db-do-commands (sql/db-do-commands
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:options :options
[;; id is also the text of the option; e.g. 'Yes', 'No'. ;; id is also the text of the option; e.g. 'Yes', 'No'.
[:id "varchar(32) not null primary key"] [:id "varchar(32) not null primary key"]
;; To do elections you probably need party and candidate and stuff here, but ;; To do elections you probably need party and candidate and stuff here, but
;; for the referendum it's unnecessary. ;; for the referendum it's unnecessary.
]))) )))
(kc/defentity option (kc/defentity option
@ -210,15 +216,15 @@
(defn create-option-district-table! (defn create-option-district-table!
"Create a table to link options to the districts in which they are relevant. This is extremely "Create a table to link options to the districts in which they are relevant. This is extremely
simple for the referendum: both options are relevant to all districts. This table is essentially simple for the referendum: both options are relevant to all districts. This table is essentially
'for later expansion'." 'for later expansion'."
[] []
(sql/db-do-commands (sql/db-do-commands
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:optionsdistricts :optionsdistricts
[[:option_id"varchar(32) not null references options(option)"] [:option_id"varchar(32) not null references options(option)"]
[:district_id "integer not null references districts(id)"]]))) [:district_id "integer not null references districts(id)"])))
;; I think we don't need an entity for optionsdistricts, because it's just a link table. ;; I think we don't need an entity for optionsdistricts, because it's just a link table.
@ -232,12 +238,12 @@
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:opinions :opinions
[[:id "serial primary key"] [:id "serial primary key"]
;; the elector who gave this opinion ;; the elector who gave this opinion
[:elector_id "integer not null references electors(id)"] [:elector_id "integer not null references electors(id)"]
;; the option the elector said they were planning to vote for ;; the option the elector said they were planning to vote for
[:option_id "varchar(32) not null references options(option)"] [:option_id "varchar(32) not null references options(option)"]
[:visit_id "integer not null references visits(id)"]]))) [:visit_id "integer not null references visits(id)"])))
(kc/defentity opinion (kc/defentity opinion
@ -259,10 +265,10 @@
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:issues :issues
[;; short name of this issue, e.g. 'currency', 'defence', 'pensions' ;; short name of this issue, e.g. 'currency', 'defence', 'pensions'
[:id "varchar(32) not null primary key"] [:id "varchar(32) not null primary key"]
;; URL of some brief material the canvasser can use on the doorstap ;; URL of some brief material the canvasser can use on the doorstap
[:url "varchar(256)"]]))) [:url "varchar(256)"])))
(kc/defentity issue (kc/defentity issue
@ -272,20 +278,20 @@
(kc/entity-fields :id :url)) (kc/entity-fields :id :url))
(defn create-followup-method-table! (defn create-followup-methods-table!
"Create a table to hold reference data on followup methods." "Create a table to hold reference data on followup methods."
[] []
(sql/db-do-commands (sql/db-do-commands
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:followupmethod :followupmethods
[[;; the method, e.g. 'telephone', 'email', 'post' [;; the method, e.g. 'telephone', 'email', 'post'
:id "varchar(32) not null primary key"]]))) :id "varchar(32) not null primary key"])))
(kc/defentity followup-method (kc/defentity followup-method
(kc/pk :id) (kc/pk :id)
(kc/table :followupmethod) (kc/table :followupmethods)
(kc/database yyydb/*db*) (kc/database yyydb/*db*)
(kc/entity-fields :id)) (kc/entity-fields :id))
@ -298,12 +304,12 @@
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:issueexpertise :issueexpertise
[;; the expert canvasser ;; the expert canvasser
[:canvasser-id "varchar(32) not null references canvasser(id)"] [:canvasser_id "varchar(32) not null references canvassers(id)"]
;; the issue they have expertise in ;; the issue they have expertise in
[:issue_id "varchar(32) not null references issues(issue)"] [:issue_id "varchar(32) not null references issues(id)"]
;; the method by which this expert can respond to electors on this issue ;; the method by which this expert can respond to electors on this issue
[:method_id "varchar 32 not null references followupmethod(method)"]]))) [:method_id "varchar(32) not null references followupmethods(id)"])))
(kc/defentity issue-expertise (kc/defentity issue-expertise
@ -315,25 +321,25 @@
(kc/has-one followup-method)) (kc/has-one followup-method))
(defn create-followup-request-table! (defn create-followup-requests-table!
"Create a table to record requests for followup contacts on particular issues." "Create a table to record requests for followup contacts on particular issues."
[] []
(sql/db-do-commands (sql/db-do-commands
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:followuprequest :followuprequests
[[:id "serial primary key"] [:id "serial primary key"]
[:elector_id "integer not null references electors(id)"] [:elector_id "integer not null references electors(id)"]
[:visit_id "integer not null references visits(id)"] [:visit_id "integer not null references visits(id)"]
[:issue_id "varchar(32) not null references issues(issue)"] [:issue_id "varchar(32) not null references issues(id)"]
;; We probably need a followupmethod (telephone, email, postal) and, for telephone, ;; We probably need a followupmethod (telephone, email, postal) and, for telephone,
;; convenient times but I haven't thought through how to represent this or how ;; convenient times but I haven't thought through how to represent this or how
;; the user interface will work. ;; the user interface will work.
[:method_id "varchar(32) not null references followupmethod(method)"]]))) [:method_id "varchar(32) not null references followupmethods(id)"])))
(kc/defentity followup-request (kc/defentity followup-request
(kc/table :followuprequest) (kc/table :followuprequests)
(kc/database yyydb/*db*) (kc/database yyydb/*db*)
(kc/entity-fields :id) (kc/entity-fields :id)
(kc/has-one elector) (kc/has-one elector)
@ -342,7 +348,7 @@
(kc/has-one followup-method)) (kc/has-one followup-method))
(defn create-followup-action-table! (defn create-followup-actions-table!
"Create a table to record actions on followup requests. Record in this table are almost "Create a table to record actions on followup requests. Record in this table are almost
certainly created through a desktop-style interface rather than through te app, so it's certainly created through a desktop-style interface rather than through te app, so it's
reasonable that there should be narrative fields." reasonable that there should be narrative fields."
@ -350,19 +356,36 @@
(sql/db-do-commands (sql/db-do-commands
yyydb/*db* yyydb/*db*
(sql/create-table-ddl (sql/create-table-ddl
:followupaction :followupactions
[[:id "serial primary key"] [:id "serial primary key"]
[:request_id "integer not null references followuprequest(id)"] [:request_id "integer not null references followuprequests(id)"]
[:actor "varchar(32) not null references canvassers(id)"] [:actor "varchar(32) not null references canvassers(id)"]
[:date "timestamp with timezone not null default now()"] [:date "timestamp with time zone not null default now()"]
[:notes "text"] [:notes "text"]
;; true if this action closes the request ;; true if this action closes the request
[:closed :boolean]]))) [:closed :boolean])))
(kc/defentity followup-action (kc/defentity followup-action
(kc/table :followupaction) (kc/table :followupactions)
(kc/database yyydb/*db*) (kc/database yyydb/*db*)
(kc/entity-fields :id :notes :date :closed) (kc/entity-fields :id :notes :date :closed)
(kc/has-one followup-request) (kc/has-one followup-request)
(kc/has-one canvasser {:fk :actor})) (kc/has-one canvasser {:fk :actor}))
(defn init-db! []
"Initialised the whole database."
(create-districts-table!)
(create-addresses-table!)
(create-authorities-table!)
(create-electors-table!)
(create-canvassers-table!)
(create-visits-table!)
(create-options-table!)
(create-issues-table!)
(create-followup-methods-table!)
(create-issue-expertise-table!)
(create-followup-requests-table!)
(create-followup-actions-table!)
)