Election results in the London Borough of Sutton.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

289 lines
9.1 KiB

  1. require 'data_mapper'
  2. class Poll
  3. include DataMapper::Resource
  4. property :district_id, Integer, :key => true
  5. property :election_id, Integer, :key => true
  6. property :electorate, Integer # The number of people eligible to vote in this district in this election
  7. property :ballot_papers_issued, Integer # The number of ballot papers issued (includes spoiled ballots)
  8. property :seats, Integer, :required => true # The number of seats to be elected in this district in this election
  9. def turnout_percent
  10. @ballot_papers_issued.to_f / @electorate.to_f * 100.0
  11. end
  12. belongs_to :election
  13. belongs_to :district
  14. end
  15. class PollingStation
  16. include DataMapper::Resource
  17. property :id, String, :key => true, :length => 2 # e.g. "KA"
  18. property :name, String, :length => 255#, :required => true
  19. property :address, String, :length => 255#, :required => true
  20. property :postcode, String#, :required => true
  21. property :easting, Float, :required => true
  22. property :northing, Float, :required => true
  23. property :lat, Float, :required => true
  24. property :lng, Float, :required => true
  25. has n, :postcodes
  26. end
  27. class Postcode
  28. include DataMapper::Resource
  29. # Postcode natural key, uppercase with space, eg. "SM1 1EA"
  30. # Column names derived from Ordnance Survey CodePoint Open
  31. property :postcode, String, :key => true
  32. property :positional_quality_indicator, Integer
  33. property :eastings, Integer, :required => true
  34. property :northings, Integer, :required => true
  35. property :country_code, String, :required => true
  36. property :nhs_regional_ha_code, String, :required => true
  37. property :nhs_ha_code, String, :required => true
  38. property :admin_county_code, String # NULL within Greater London
  39. property :admin_district_code, String, :required => true # e.g. London Borough of Sutton
  40. property :admin_ward_code, String, :required => true # e.g. Sutton Central
  41. property :lat, Float, :required => true
  42. property :lng, Float, :required => true
  43. property :ward_id, Integer, :required => true # Sutton Council
  44. property :constituency_id, Integer, :required => false # UK Parliament
  45. property :polling_station_id, String, :length => 2
  46. belongs_to :district, :child_key => [:ward_id]
  47. belongs_to :polling_station
  48. def self.finder(postcode)
  49. postcode = postcode.strip.upcase
  50. if o = self.get(postcode)
  51. return o
  52. end
  53. result = Pat.get(postcode)
  54. unless result.code == 404
  55. # cache API result
  56. self.create(
  57. :postcode => postcode,
  58. :lat => result['geo']['lat'],
  59. :lng => result['geo']['lng'],
  60. :district_name => result['administrative']['district']['title'],
  61. :district_code => result['administrative']['district']['uri'].match(/.+\/(.+)$/)[1],
  62. :ward_name => result['administrative']['ward']['title'],
  63. :ward_code => result['administrative']['ward']['uri'].match(/.+\/(.+)$/)[1]
  64. )
  65. else
  66. # invalid postcode
  67. nil
  68. end
  69. end
  70. end
  71. class Candidate
  72. include DataMapper::Resource
  73. property :id, Serial
  74. property :forenames, String, :required => true
  75. property :surname, String, :required => true, :index => true
  76. property :sex, String
  77. has n, :candidacies
  78. def short_name
  79. @forenames.split(' ')[0] + ' ' + @surname
  80. end
  81. def name
  82. @forenames + ' ' + @surname
  83. end
  84. end
  85. class DeletedCandidate
  86. include DataMapper::Resource
  87. property :old_candidate_id, Integer, :key => true # ID of candidate that has been merged/deleted
  88. property :candidate_id, Integer, :required => true # ID of candidate that has been kept
  89. end
  90. class Candidacy
  91. include DataMapper::Resource
  92. property :id, Serial
  93. property :election_id, Integer, :required => true
  94. property :candidate_id, Integer, :required => true
  95. property :party_id, Integer
  96. property :district_id, Integer, :required => true
  97. property :votes, Integer
  98. property :address, String, :length => 200
  99. property :postcode, String
  100. property :position, Integer # Position of this candidate in this district. (1..n)
  101. property :seats, Integer # Number of seats won by this candidacy (0 or 1)
  102. property :labcoop, Boolean, :default => false # Candidacy is for joint Labour/Co-op party
  103. belongs_to :election
  104. belongs_to :candidate
  105. belongs_to :party
  106. belongs_to :district
  107. end
  108. class Campaign
  109. include DataMapper::Resource
  110. property :party_id, Integer, :key => true
  111. property :election_id, Integer, :key => true
  112. property :party_url, String, :length => 255
  113. property :manifesto_html_url, String, :length => 255
  114. property :manifesto_pdf_url, String, :length => 255
  115. belongs_to :party
  116. belongs_to :election
  117. end
  118. class Election
  119. include DataMapper::Resource
  120. property :id, Serial
  121. property :body_id, Integer, :required => true
  122. property :d, Date, :required => true, :index => true
  123. property :reason, String, :length => 255
  124. property :kind, String, :length => 255
  125. has n, :candidacies
  126. has n, :polls
  127. belongs_to :body
  128. has n, :campaigns
  129. def self.past
  130. self.all(:d.lt => Time.now.to_s, :order => [ :d.desc ])
  131. end
  132. def self.future
  133. self.all(:d.gte => Time.now.to_s, :order => [ :d.desc ])
  134. end
  135. # electorate and ballot_papers_issued assume there's a Poll object for every district in this election
  136. def electorate
  137. Poll.sum(:electorate, :election => self)
  138. end
  139. def ballot_papers_issued
  140. Poll.sum(:ballot_papers_issued, :election => self)
  141. end
  142. end
  143. class District
  144. include DataMapper::Resource
  145. property :id, Serial
  146. property :body_id, Integer, :required => true
  147. property :name, String, :length => 255, :required => true
  148. property :slug, String
  149. property :seats, Integer
  150. property :ons_district_code, String
  151. belongs_to :body
  152. has n, :postcodes, :child_key => [:ward_id]
  153. has n, :polls
  154. def self.slugify(name)
  155. name.gsub(/[^\w\s-]/, '').gsub(/\s+/, '-').downcase
  156. end
  157. end
  158. class Body
  159. include DataMapper::Resource
  160. property :id, Serial
  161. property :name, String, :length => 255, :required => true
  162. property :district_name, String, :length => 255, :required => true # singular
  163. property :districts_name, String, :length => 255, :required => true # plural
  164. property :slug, String, :length => 255
  165. has n, :elections
  166. has n, :districts
  167. end
  168. class Party
  169. include DataMapper::Resource
  170. property :id, Serial
  171. property :name, String, :required => true
  172. property :colour, String
  173. has n, :candidacies
  174. has n, :campaigns
  175. end
  176. # These models are now redundant
  177. class Ward
  178. include DataMapper::Resource
  179. property :id, Serial
  180. property :slug, String, :required => true
  181. property :ons_id, String, :required => true
  182. property :name, String, :required => true
  183. property :constituency_id, Integer, :required => true
  184. has n, :councilcandidates, :order => ['surname']
  185. belongs_to :constituency
  186. def self.slugify(name)
  187. name.gsub(/[^\w\s-]/, '').gsub(/\s+/, '-').downcase
  188. end
  189. end
  190. class Councilcandidate
  191. include DataMapper::Resource
  192. property :id, Serial
  193. property :ward_id, Integer, :required => true
  194. property :party_id, Integer, :required => true
  195. property :forenames, String, :required => true
  196. property :surname, String, :required => true
  197. property :address, String, :length => 200
  198. property :postcode, String, :required => true
  199. property :votes_2010, Integer
  200. belongs_to :party
  201. belongs_to :ward
  202. end
  203. class Parliamentcandidate
  204. include DataMapper::Resource
  205. property :id, Serial
  206. property :constituency_id, Integer, :required => true
  207. property :party_id, Integer, :required => true
  208. property :forenames, String, :required => true
  209. property :surname, String, :required => true
  210. property :address, String, :length => 200
  211. property :postcode, String
  212. property :votes_2010, Integer
  213. property :votes_2005, Integer
  214. property :percent_2005, Float
  215. belongs_to :party
  216. belongs_to :constituency
  217. end
  218. class Constituency
  219. include DataMapper::Resource
  220. property :id, Serial
  221. property :name, String, :required => true
  222. has n, :wards, :order => ['name']
  223. has n, :parliamentcandidates, :order => ['surname']
  224. end
  225. DataMapper.setup(:default, ENV['DATABASE_URL'] || "postgres://postgres@localhost:5432/suttonelections")
  226. DataMapper.auto_upgrade!