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.

models.rb 8.0 KiB

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