diff --git a/app/models/achievement.rb b/app/models/achievement.rb index b3b0d99..4d32ffc 100644 --- a/app/models/achievement.rb +++ b/app/models/achievement.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class Achievement < ActiveRecord::Base + +class Achievement < ApplicationRecord include PgSearchCommon has_many :user_achievements pg_search_common_scope against: :award diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..635c883 --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true + + def self.copy_csv(sql) + Enumerator.new do |y| + conn = ActiveRecord::Base.connection.raw_connection + conn.copy_data "COPY (#{sql}) TO STDOUT WITH CSV HEADER DELIMITER ';'" do + while row = conn.get_copy_data + y << row + end + end + end + end +end diff --git a/app/models/genome_gov_paper.rb b/app/models/genome_gov_paper.rb index 7c5c40b..32b5bc4 100644 --- a/app/models/genome_gov_paper.rb +++ b/app/models/genome_gov_paper.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class GenomeGovPaper < ActiveRecord::Base + +class GenomeGovPaper < ApplicationRecord include PgSearchCommon has_many :snp_references, as: :paper diff --git a/app/models/genotype.rb b/app/models/genotype.rb index d72a5bb..ebde198 100644 --- a/app/models/genotype.rb +++ b/app/models/genotype.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true + require 'fileutils' -class Genotype < ActiveRecord::Base +class Genotype < ApplicationRecord belongs_to :user has_many :user_snps, dependent: :delete_all validates_presence_of :user @@ -20,7 +21,7 @@ class Genotype < ActiveRecord::Base end def fs_filename - "#{user.id}.#{filetype}.#{id}" + "#{user_id}.#{filetype}.#{id}" end Paperclip.interpolates :fs_filename do |attachment, style| diff --git a/app/models/homepage.rb b/app/models/homepage.rb index b293202..48c54f6 100644 --- a/app/models/homepage.rb +++ b/app/models/homepage.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class Homepage < ActiveRecord::Base + +class Homepage < ApplicationRecord belongs_to :user after_save :destroy_if_blank diff --git a/app/models/mendeley_paper.rb b/app/models/mendeley_paper.rb index 13cabd5..b2b4dae 100644 --- a/app/models/mendeley_paper.rb +++ b/app/models/mendeley_paper.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class MendeleyPaper < ActiveRecord::Base + +class MendeleyPaper < ApplicationRecord include PgSearchCommon has_many :snp_references, as: :paper diff --git a/app/models/message.rb b/app/models/message.rb index b8bce8e..bdcf78a 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class Message < ActiveRecord::Base + +class Message < ApplicationRecord attr_encrypted :body, key: ENV.fetch('USER_DATA_SECRET_KEY') attr_encrypted :subject, key: ENV.fetch('USER_DATA_SECRET_KEY') diff --git a/app/models/open_humans_profile.rb b/app/models/open_humans_profile.rb index 44e8c0c..5eb4cda 100644 --- a/app/models/open_humans_profile.rb +++ b/app/models/open_humans_profile.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -class OpenHumansProfile < ActiveRecord::Base +class OpenHumansProfile < ApplicationRecord belongs_to :user end diff --git a/app/models/pgp_annotation.rb b/app/models/pgp_annotation.rb index cd1a621..c7fb5b4 100644 --- a/app/models/pgp_annotation.rb +++ b/app/models/pgp_annotation.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class PgpAnnotation < ActiveRecord::Base + +class PgpAnnotation < ApplicationRecord include PgSearchCommon belongs_to :snp diff --git a/app/models/phenotype.rb b/app/models/phenotype.rb index ffbec70..536454d 100644 --- a/app/models/phenotype.rb +++ b/app/models/phenotype.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class Phenotype < ActiveRecord::Base + +class Phenotype < ApplicationRecord include PgSearchCommon has_many :user_phenotypes, dependent: :destroy diff --git a/app/models/phenotype_comment.rb b/app/models/phenotype_comment.rb index 96a483d..1d450c8 100644 --- a/app/models/phenotype_comment.rb +++ b/app/models/phenotype_comment.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class PhenotypeComment < ActiveRecord::Base + +class PhenotypeComment < ApplicationRecord include PgSearchCommon belongs_to :phenotype diff --git a/app/models/phenotype_set.rb b/app/models/phenotype_set.rb index b1a964f..db1e1ac 100644 --- a/app/models/phenotype_set.rb +++ b/app/models/phenotype_set.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class PhenotypeSet < ActiveRecord::Base + +class PhenotypeSet < ApplicationRecord include PgSearchCommon has_and_belongs_to_many :phenotypes diff --git a/app/models/picture_phenotype.rb b/app/models/picture_phenotype.rb index 6a49cb4..a6d5f21 100644 --- a/app/models/picture_phenotype.rb +++ b/app/models/picture_phenotype.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class PicturePhenotype < ActiveRecord::Base + +class PicturePhenotype < ApplicationRecord include PgSearchCommon has_many :user_picture_phenotypes, dependent: :destroy diff --git a/app/models/picture_phenotype_comment.rb b/app/models/picture_phenotype_comment.rb index 518f99f..501cec2 100644 --- a/app/models/picture_phenotype_comment.rb +++ b/app/models/picture_phenotype_comment.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class PicturePhenotypeComment < ActiveRecord::Base + +class PicturePhenotypeComment < ApplicationRecord include PgSearchCommon belongs_to :picture_phenotype diff --git a/app/models/plos_paper.rb b/app/models/plos_paper.rb index 29527c8..6775347 100644 --- a/app/models/plos_paper.rb +++ b/app/models/plos_paper.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class PlosPaper < ActiveRecord::Base + +class PlosPaper < ApplicationRecord include PgSearchCommon has_many :snp_references, as: :paper diff --git a/app/models/search_result.rb b/app/models/search_result.rb index 27d00dc..61bfb3e 100644 --- a/app/models/search_result.rb +++ b/app/models/search_result.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true -class SearchResult < ActiveRecord::Base + +class SearchResult < ApplicationRecord end diff --git a/app/models/snp.rb b/app/models/snp.rb index 987db22..963e9bd 100644 --- a/app/models/snp.rb +++ b/app/models/snp.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class Snp < ActiveRecord::Base + +class Snp < ApplicationRecord include PgSearchCommon has_many :user_snps, foreign_key: :snp_name, primary_key: :name diff --git a/app/models/snp_comment.rb b/app/models/snp_comment.rb index 6f9c2e1..df8fc4e 100644 --- a/app/models/snp_comment.rb +++ b/app/models/snp_comment.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class SnpComment < ActiveRecord::Base + +class SnpComment < ApplicationRecord include PgSearchCommon belongs_to :snp diff --git a/app/models/snp_reference.rb b/app/models/snp_reference.rb index 8f8ad9e..6184e25 100644 --- a/app/models/snp_reference.rb +++ b/app/models/snp_reference.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class SnpReference < ActiveRecord::Base + +class SnpReference < ApplicationRecord self.primary_keys = :snp_id, :paper_id, :paper_type belongs_to :snp belongs_to :paper, polymorphic: true diff --git a/app/models/snpedia_paper.rb b/app/models/snpedia_paper.rb index 46edd33..f80c37a 100644 --- a/app/models/snpedia_paper.rb +++ b/app/models/snpedia_paper.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class SnpediaPaper < ActiveRecord::Base + +class SnpediaPaper < ApplicationRecord include PgSearchCommon has_many :snp_references, as: :paper diff --git a/app/models/user.rb b/app/models/user.rb index 001d762..515e56e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class User < ActiveRecord::Base + +class User < ApplicationRecord include PgSearchCommon has_attached_file :avatar, diff --git a/app/models/user_achievement.rb b/app/models/user_achievement.rb index 84c6472..ddd3fbc 100644 --- a/app/models/user_achievement.rb +++ b/app/models/user_achievement.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class UserAchievement < ActiveRecord::Base + +class UserAchievement < ApplicationRecord belongs_to :achievement belongs_to :user end diff --git a/app/models/user_phenotype.rb b/app/models/user_phenotype.rb index c4e8ddb..cb85da7 100644 --- a/app/models/user_phenotype.rb +++ b/app/models/user_phenotype.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class UserPhenotype < ActiveRecord::Base + +class UserPhenotype < ApplicationRecord include PgSearchCommon belongs_to :phenotype diff --git a/app/models/user_picture_phenotype.rb b/app/models/user_picture_phenotype.rb index 94898a3..333eaa8 100644 --- a/app/models/user_picture_phenotype.rb +++ b/app/models/user_picture_phenotype.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class UserPicturePhenotype < ActiveRecord::Base + +class UserPicturePhenotype < ApplicationRecord include PgSearchCommon belongs_to :picture_phenotype diff --git a/app/models/user_session.rb b/app/models/user_session.rb index f3c524b..68da1be 100644 --- a/app/models/user_session.rb +++ b/app/models/user_session.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + class UserSession < Authlogic::Session::Base after_persisting :raven_set_user_context after_destroy :raven_clear_user_context diff --git a/app/models/user_snp.rb b/app/models/user_snp.rb index f8454da..728a6c0 100644 --- a/app/models/user_snp.rb +++ b/app/models/user_snp.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true -class UserSnp < ActiveRecord::Base + +class UserSnp < ApplicationRecord self.primary_keys = [:genotype_id, :snp_name] belongs_to :snp, foreign_key: :snp_name, primary_key: :name, counter_cache: true has_one :user, through: :genotype diff --git a/app/services/data_zipper_service.rb b/app/services/data_zipper_service.rb new file mode 100644 index 0000000..3b08a74 --- /dev/null +++ b/app/services/data_zipper_service.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +require 'zip' +require_relative 'data_zipper_service/generate_user_phenotype_csv' +require_relative 'data_zipper_service/zip_user_picture_phenotypes' + +class DataZipperService + CSV_OPTIONS = { col_sep: ';' }.freeze + PUBLIC_PATH = '/data/zip/opensnp_datadump.current.zip' + DEFAULT_OUTPUT_DIR = Rails.root.join('public', 'data', 'zip').freeze + + attr_reader :time, :time_str, :zip_public_path, :zip_tmp_path, :tmp_dir, + :link_path, :output_dir, :logger + + def initialize(output_dir: DEFAULT_OUTPUT_DIR, logger: Logger.new(STDOUT)) + @output_dir = output_dir + @time = Time.now.utc + @time_str = time.strftime('%Y%m%d%H%M') + @tmp_dir = Rails.root.join('tmp', "opensnp_datadump.#{time_str}") + zip_file_name = "opensnp_datadump.#{time_str}.zip" + @zip_public_path = @output_dir.join(zip_file_name) + @zip_tmp_path = Rails.root.join('tmp', zip_file_name) + @link_path = @output_dir.join('opensnp_datadump.current.zip') + @logger = logger + end + + def call + # only create a new file if in the current minute none has been created yet + if Dir.exist?(tmp_dir) + logger.error("Directory #{tmp_dir} already exists. Exiting...") + return false + end + + begin + logger.info("Creating temp dir: #{tmp_dir}") + Dir.mkdir(tmp_dir) + logger.info("Creating zipfile: #{zip_tmp_path}") + Zip::File.open(zip_tmp_path, Zip::File::CREATE) do |zipfile| + zip_user_phenotypes(zipfile) + zip_user_picture_phenotypes(zipfile) + zip_readme(zipfile) + zip_genotype_files(zipfile) + end + + # move from local storage to network storage + logger.info("Copying #{zip_tmp_path} to #{zip_public_path}") + FileUtils.cp(zip_tmp_path, zip_public_path) + logger.info("Deleting #{zip_tmp_path}") + FileUtils.rm(zip_tmp_path) + logger.info("Creating symlink #{link_path} to #{zip_public_path}") + FileUtils.ln_sf(zip_public_path, link_path) + + # everything went OK, now delete old zips + delete_old_zips + ensure + logger.info("Deleting #{tmp_dir}") + FileUtils.rm_rf(tmp_dir) + end + end + + def self.public_path + PUBLIC_PATH + end + + private + + # Create a CSV with a row for each genotype, with user data and phenotypes as + # columns. + def zip_user_phenotypes(zipfile) + logger.info('Zipping user phenotypes') + zipfile.get_output_stream("phenotypes_#{time_str}.csv") do |f| + GenerateUserPhenotypeCsv.new.call.each do |row| + f.write(row) + end + end + end + + # make a CSV describing all of them - which filename is for which user's phenotype + def zip_user_picture_phenotypes(zipfile) + logger.info('Zipping user picture phenotypes') + ZipUserPicturePhenotypes.new(zipfile, tmp_dir, time_str).call + end + + def zip_readme(zipfile) + logger.info('Zipping readme') + # make a README containing time of zip - this way, users can compare with page-status + # and see how old the data is + zipfile.get_output_stream('readme.txt') do |f| + f.write( + I18n.t( + 'zipfulldata.readme', + time: time.ctime, + phenotype_count: Phenotype.count, + genotype_count: Genotype.count, + picture_count: PicturePhenotype.count + ) + ) + end + end + + def zip_genotype_files(zipfile) + logger.info('Zipping genotype files') + ZipGenotypeFiles.new(zipfile).call + end + + def delete_old_zips + forbidden_files = [link_path, zip_public_path].map(&:to_s) + Dir[output_dir.join('opensnp_datadump.*.zip')].each do |f| + next if forbidden_files.include?(f) + logger.info("Deleting #{f}") + File.delete(f) + end + end +end diff --git a/app/services/data_zipper_service/generate_user_phenotype_csv.rb b/app/services/data_zipper_service/generate_user_phenotype_csv.rb new file mode 100644 index 0000000..001f57e --- /dev/null +++ b/app/services/data_zipper_service/generate_user_phenotype_csv.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +class DataZipperService + class GenerateUserPhenotypeCsv + def call + # Build a pivot table with characteristics and user genotype IDs as dimensions and + # variations as values. + # + # PostgreSQL docs: https://www.postgresql.org/docs/9.6/tablefunc.html#AEN145056 + ApplicationRecord.copy_csv(<<-SQL) + SELECT + user_id, + fs_filename AS genotype_filename, + user_yob AS date_of_birth, + user_sex AS chrom_sex, + oh_user_name AS openhumans_name, + #{characteristics_headers} + FROM CROSSTAB( + 'SELECT genotypes.id, -- unique key, must be first + genotypes.user_id, + genotypes.user_id || ''.'' || genotypes.filetype || ''.'' || genotypes.id, + users.yearofbirth, + users.sex, + COALESCE(open_humans_profiles.open_humans_user_id, ''-''), + phenotypes.characteristic, -- column headers, must be second to last + user_phenotypes.variation -- values, must be last + FROM genotypes + JOIN users ON users.id = genotypes.user_id + LEFT JOIN user_phenotypes ON user_phenotypes.user_id = genotypes.user_id + LEFT JOIN phenotypes ON phenotypes.id = user_phenotypes.phenotype_id + LEFT JOIN open_humans_profiles ON open_humans_profiles.user_id = users.id + ORDER BY genotypes.id, phenotypes.id', + '#{phenotypes.to_sql}' + ) AS ct_variations( + genotype_id integer, + user_id integer, + fs_filename text, + user_yob text, + user_sex text, + oh_user_name text, + #{characteristics_types} + ) + ORDER BY user_id, genotype_id + SQL + end + + private + + def phenotypes + @phenotypes ||= Phenotype.select(:characteristic).order(:id) + end + + def characteristics_headers + characteristics.map do |c| + header = c.gsub('"', '""') + "COALESCE(\"#{header}\", '-') AS \"#{header}\"" + end.join(', ') + end + + def characteristics_types + characteristics.map { |c| "\"#{c.gsub('"', '""')}\" text" }.join(', ') + end + + def characteristics + @characteristics ||= phenotypes.pluck(:characteristic) + end + end +end diff --git a/app/services/data_zipper_service/zip_genotype_files.rb b/app/services/data_zipper_service/zip_genotype_files.rb new file mode 100644 index 0000000..8e4fde2 --- /dev/null +++ b/app/services/data_zipper_service/zip_genotype_files.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class DataZipperService + class ZipGenotypeFiles + def initialize(zipfile) + @zipfile = zipfile + end + + attr_reader :zipfile + + def call + Genotype.includes(:user).find_each do |genotype| + next unless File.exist?(genotype.genotype.path) + + user = genotype.user + yob = user.yearofbirth == 'rather not say' ? 'unknown' : user.yearofbirth + sex = user.sex == 'rather not say' ? 'unknown' : user.sex + + zipfile.add( + "user#{genotype.user_id}_file#{genotype.id}_yearofbirth_#{yob}_" \ + "sex_#{sex}.#{genotype.filetype}.txt", + genotype.genotype.path + ) + end + end + end +end diff --git a/app/services/data_zipper_service/zip_user_picture_phenotypes.rb b/app/services/data_zipper_service/zip_user_picture_phenotypes.rb new file mode 100644 index 0000000..8804b01 --- /dev/null +++ b/app/services/data_zipper_service/zip_user_picture_phenotypes.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'csv' + +class DataZipperService + class ZipUserPicturePhenotypes + CSV_BASE_HEADER = %w(user_id date_of_birth chrom_sex).freeze + + def initialize(zipfile, tmp_dir, time_str) + @zipfile = zipfile + @tmp_dir = tmp_dir + @time_str = time_str + end + + attr_reader :zipfile, :tmp_dir, :time_str + + def call + picture_phenotypes = PicturePhenotype.order(:id) + csv_head = CSV_BASE_HEADER + picture_phenotypes.pluck(:characteristic) + picture_zip = Zip::File.open( + tmp_dir.join("opensnp_picturedump.#{time_str}.zip"), + Zip::File::CREATE + ) + + user_picture_phenotypes_csv = CSV.generate(CSV_OPTIONS) do |csv| + csv << csv_head + + User + .order(:id) + .includes(:user_picture_phenotypes) + .find_each do |user| + csv << build_user_picture_phenotype_row(user, picture_phenotypes, picture_zip) + end + end + + picture_zip.close + + zipfile.get_output_stream("picture_phenotypes_#{time_str}.csv") do |f| + f.write(user_picture_phenotypes_csv) + end + zipfile.add("picture_phenotypes_#{time_str}_all_pics.zip", picture_zip.name) + end + + def build_user_picture_phenotype_row(user, picture_phenotypes, picture_zip) + user_picture_phenotypes = user + .user_picture_phenotypes + .index_by(&:picture_phenotype_id) + + [ + user.id, + user.yearofbirth, + user.sex + ] + picture_phenotypes.map do |picture_phenotype| + user_picture_phenotype = user_picture_phenotypes[picture_phenotype.id] + if user_picture_phenotype && user_picture_phenotype.phenotype_picture.present? + extension = user_picture_phenotype + .phenotype_picture + .content_type + .split('/') + .last + extension = 'jpg' if extension == 'jpeg' + file_name = "#{user_picture_phenotype.id}.#{extension}" + picture_zip.add(file_name, user_picture_phenotype.phenotype_picture.path) + file_name + else + '-' + end + end + end + end +end diff --git a/app/views/genotypes/index.html.erb b/app/views/genotypes/index.html.erb index c3abf69..4561a13 100644 --- a/app/views/genotypes/index.html.erb +++ b/app/views/genotypes/index.html.erb @@ -12,7 +12,7 @@
Includes all genotyping files, a CSV with all phenotypes of those users, and all picture phenotypes. A preprocessed dump of 5,000 datasets from February 2020 exists on GenomePrep
diff --git a/app/views/snps/index.html.erb b/app/views/snps/index.html.erb index 86a8a73..e5493d1 100644 --- a/app/views/snps/index.html.erb +++ b/app/views/snps/index.html.erb @@ -4,7 +4,7 @@Includes annotation for all SNPs from all sources
diff --git a/app/workers/data_zipper_worker.rb b/app/workers/data_zipper_worker.rb new file mode 100644 index 0000000..bee435d --- /dev/null +++ b/app/workers/data_zipper_worker.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class DataZipperWorker + include Sidekiq::Worker + sidekiq_options queue: :zipfulldata, retry: 0, unique: true, dead: false + # can't do retry => false. + # Note with retry disabled, Sidekiq will not track or save any error data for the worker's jobs. + # dead => false means don't send dead job to the dead queue, we don't care about that + + def perform + DataZipperService.new(logger: logger).call + end +end diff --git a/app/workers/zipfulldata.rb b/app/workers/zipfulldata.rb deleted file mode 100644 index c92f6e1..0000000 --- a/app/workers/zipfulldata.rb +++ /dev/null @@ -1,227 +0,0 @@ - -# frozen_string_literal: true -require 'csv' -require 'zip' - - -class Zipfulldata - include Sidekiq::Worker - sidekiq_options queue: :zipfulldata, retry: 0, unique: true, dead: false - # can't do retry => false. - # Note with retry disabled, Sidekiq will not track or save any error data for the worker's jobs. - # dead => false means don't send dead job to the dead queue, we don't care about that - - attr_reader :time, :time_str, :csv_options, :dump_file_name, :zip_public_path, - :zip_fs_path, :tmp_dir, :link_path - - def perform - logger.info('job started') - run - logger.info('job done') - end - - def initialize - @time = Time.now.utc - @time_str = time.strftime("%Y%m%d%H%M") - @csv_options = { col_sep: ';' } - @dump_file_name = "opensnp_datadump.#{time_str}" - @zip_public_path = "public/data/zip/#{dump_file_name}.zip" - @zip_fs_path = "/tmp/#{dump_file_name}.zip" - @tmp_dir = "#{Rails.root}/tmp/#{dump_file_name}" - @link_path = Rails.root.join('public/data/zip/opensnp_datadump.current.zip') - end - - def run - genotypes = Genotype.includes(user: :user_phenotypes) - logger.info("Got #{genotypes.length} genotypes") - - # only create a new file if in the current minute none has been created yet - if Dir.exists?(tmp_dir) - logger.info("Directory #{tmp_dir} already exists. Exiting...") - return false - end - - begin - logger.info("Making tmpdir #{tmp_dir}") - Dir.mkdir(tmp_dir) - logger.info("Starting zipfile #{zip_fs_path}") - Zip::File.open(zip_fs_path, Zip::File::CREATE) do |zipfile| - create_user_csv(genotypes, zipfile) - list_of_pics = create_picture_phenotype_csv(zipfile) - create_picture_zip(list_of_pics, zipfile) - create_readme(zipfile) - zip_genotype_files(genotypes, zipfile) - end - # move from local storage to network storage - FileUtils.cp(@zip_fs_path, Rails.root.join("public/data/zip/#{dump_file_name}.zip")) - FileUtils.rm(@zip_fs_path) - logger.info('created zip-file') - - FileUtils.ln_sf( - Rails.root.join("public/data/zip/#{dump_file_name}.zip"), - link_path) - - # everything went OK, now delete old zips - delete_old_zips - - ensure - FileUtils.rm_rf(tmp_dir) - end - true - end - - def create_user_csv(genotypes, zipfile) - phenotypes = Phenotype.all - csv_file_name = "#{tmp_dir}/dump#{time_str}.csv" - csv_head = %w(user_id genotype_filename date_of_birth chrom_sex openhumans_name) - csv_head.concat(phenotypes.map(&:characteristic)) - - CSV.open(csv_file_name, "w", csv_options) do |csv| - csv << csv_head - - # create lines in csv-file for each user who has uploaded his data - genotypes.each do |genotype| - user = genotype.user - oh_name = user.open_humans_profile&.open_humans_user_id || '-' - row = [user.id, genotype.fs_filename, user.yearofbirth, user.sex, oh_name] - - phenotypes.each do |phenotype| - if up = user.user_phenotypes.where(phenotype_id: phenotype.id).first - row << up.variation - else - row << "-" - end - end - csv << row - end - end - logger.info('created user csv') - zipfile.add("phenotypes_#{time_str}.csv", csv_file_name) - end - - # make a CSV describing all of them - which filename is for which user's phenotype - def create_picture_phenotype_csv(zipfile) - file_name = "#{tmp_dir}/picture_dump#{time_str}.csv" - logger.info("Writing picture-CSV to #{file_name}") - - list_of_pics = [] # need this for the zip-file-later - - picture_phenotypes = PicturePhenotype.all - csv_head = %w(user_id date_of_birth chrom_sex) - csv_head.concat(picture_phenotypes.map(&:characteristic)) - - CSV.open(file_name, "w", csv_options) do |csv| - - csv << csv_head - - # create lines in csv-file for each user who has uploaded his data - - User.includes(:user_picture_phenotypes).order(:id).each do |u| - logger.info("Looking at user #{u.id}") - row = [u.id, u.yearofbirth, u.sex] - picture_phenotypes.each do |pp| - - # copy the picture with name to +user_id+_+pic_phenotype_id+.png - # logger.info("Looking for this picture #{pp.id}") - picture = pp.user_picture_phenotypes.where(user_id: u.id).first - # does this user have this pic? - if picture.present? && picture.phenotype_picture.present? - picture_path = picture.phenotype_picture.path - basename = picture_path.split("/")[-1] - filetype = basename.split(".")[-1] - logger.info("FOUND file #{picture_path}, basename is #{basename}") - - list_of_pics << picture - row << "#{picture.id}.#{filetype}" - else - row << '-' - end - end - logger.info('Putting a line into CSV') - csv << row - end - end - logger.info('created picture handle csv-file') - zipfile.add("picture_phenotypes_#{time_str}.csv", file_name) - list_of_pics - end - - def create_picture_zip(list_of_pics, zipfile) - pic_zipname = "/data/zip/opensnp_picturedump."+time_str+".zip" - Zip::File.open("#{Rails.root}/public/#{pic_zipname}", Zip::File::CREATE) do |z| - list_of_pics.each do |tmp| - begin - file_name = tmp.phenotype_picture.path - basename = file_name.split("/")[-1] - filetype = basename.split(".")[-1] - logger.info("Adding file to zip named #{tmp.id.to_s + "." + filetype}") - z.add(tmp.id.to_s+"."+filetype, file_name) - logger.info("Added #{tmp.id.to_s + "." + filetype}") - rescue => e - logger.info("create_picture_zip: #{e.class}: #{e.message}") - end - end - end - zipfile.add("picture_phenotypes_#{time_str}_all_pics.zip", - "#{Rails.root}/public/#{pic_zipname}") - logger.info('created picture zip file') - end - - def create_readme(zipfile) - # make a README containing time of zip - this way, users can compare with page-status - # and see how old the data is - phenotype_count = Phenotype.count - genotype_count = Genotype.count - picture_count = PicturePhenotype.count - File.open("#{tmp_dir}/dump#{time_str}.txt", "w") do |readme| - readme.puts(<<-TXT) -This archive was generated on #{time.ctime} UTC. It contains #{phenotype_count} phenotypes, #{genotype_count} genotypes and #{picture_count} picture phenotypes. - -Thanks for using openSNP! -TXT - end - zipfile.add("readme.txt", "#{tmp_dir}/dump#{time_str}.txt") - end - - def zip_genotype_files(genotypes, zipfile) - genotypes.each do |gen_file| - yob = gen_file.user.yearofbirth - sex = gen_file.user.sex - to_zip_file = "#{Rails.root}/public/data/#{gen_file.fs_filename}" - - if yob == "rather not say" - yob = "unknown" - end - if sex == "rather not say" - sex = "unknown" - end - - zipfile.add("user#{gen_file.user_id}_file#{gen_file.id}_yearofbirth_#{yob}_sex_#{sex}.#{gen_file.filetype}.txt", - to_zip_file) unless !File.exist? to_zip_file - end - end - - def delete_old_zips - forbidden_files = [link_path, - Rails.root.join('data', 'annotation.zip').to_s, - Rails.root.join('public', 'data', 'zip', "#{dump_file_name}.zip").to_s] - Dir[Rails.root.join('public/data/zip/*.zip')].each do |f| - if (not forbidden_files.include? f) and (File.ftype(f) == "file") - File.delete(f) - end - end - end - - def self.public_path - '/data/zip/opensnp_datadump.current.zip' - end - - def self.gb_size - file = Rails.root.join('public', self.public_path) - if File.file? file - "(Size: #{(File.size(file).to_f / (2**30)).round(2)})" - else - "" - end - end -end diff --git a/config/locales/en.yml b/config/locales/en.yml index 250291b..e1ba9eb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -10,3 +10,8 @@ en: attributes: phenotype: taken: 'has already been entered.' + zipfulldata: + readme: | + This archive was generated on %{time} UTC. It contains %{phenotype_count} phenotypes, %{genotype_count} genotypes and %{picture_count} picture phenotypes. + + Thanks for using openSNP! diff --git a/db/development_seeds.rb b/db/development_seeds.rb index 2ee2b57..33fb9f7 100644 --- a/db/development_seeds.rb +++ b/db/development_seeds.rb @@ -34,5 +34,5 @@ PROPERTIES = %w{ }.freeze 100.times do - Phenotype.create! characteristic: "#{BODY_PARTS.sample} #{PROPERTIES.sample}" + Phenotype.find_or_create_by(characteristic: "#{BODY_PARTS.sample} #{PROPERTIES.sample}") end diff --git a/db/structure.sql b/db/structure.sql index 5ed7cd3..a7aed5d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1,1843 +1,1844 @@ --- --- PostgreSQL database dump --- - --- Dumped from database version 9.5.13 --- Dumped by pg_dump version 9.5.12 - -SET statement_timeout = 0; -SET lock_timeout = 0; -SET client_encoding = 'UTF8'; -SET standard_conforming_strings = on; -SET check_function_bodies = false; -SET client_min_messages = warning; -SET row_security = off; - --- --- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: - --- - -CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; - - --- --- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: - --- - -COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; - - --- --- Name: hstore; Type: EXTENSION; Schema: -; Owner: - --- - -CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public; - - --- --- Name: EXTENSION hstore; Type: COMMENT; Schema: -; Owner: - --- - -COMMENT ON EXTENSION hstore IS 'data type for storing sets of (key, value) pairs'; - - --- --- Name: pg_stat_statements; Type: EXTENSION; Schema: -; Owner: - --- - -CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA public; - - --- --- Name: EXTENSION pg_stat_statements; Type: COMMENT; Schema: -; Owner: - --- - -COMMENT ON EXTENSION pg_stat_statements IS 'track execution statistics of all SQL statements executed'; - - --- --- Name: find_bad_row(text); Type: FUNCTION; Schema: public; Owner: - --- - -CREATE FUNCTION public.find_bad_row(tablename text) RETURNS tid - LANGUAGE plpgsql - AS $_$ -DECLARE -result tid; -curs REFCURSOR; -row1 RECORD; -row2 RECORD; -tabName TEXT; -count BIGINT := 0; -BEGIN -SELECT reverse(split_part(reverse($1), '.', 1)) INTO tabName; -OPEN curs FOR EXECUTE 'SELECT ctid FROM ' || tableName; -count := 1; -FETCH curs INTO row1; -WHILE row1.ctid IS NOT NULL LOOP -result = row1.ctid; -count := count + 1; -FETCH curs INTO row1; -EXECUTE 'SELECT (each(hstore(' || tabName || '))).* FROM ' -|| tableName || ' WHERE ctid = $1' INTO row2 -USING row1.ctid; -IF count % 100000 = 0 THEN -RAISE NOTICE 'rows processed: %', count; -END IF; -END LOOP; -CLOSE curs; -RETURN row1.ctid; -EXCEPTION -WHEN OTHERS THEN -RAISE NOTICE 'LAST CTID: %', result; -RAISE NOTICE '%: %', SQLSTATE, SQLERRM; -RETURN result; -END -$_$; - - --- --- Name: upsert_user_snps(integer); Type: FUNCTION; Schema: public; Owner: - --- - -CREATE FUNCTION public.upsert_user_snps(current_genotype_id integer) RETURNS void - LANGUAGE plpgsql - AS $$ - DECLARE - temp_table_name VARCHAR := CONCAT('user_snps_temp_', current_genotype_id::varchar); - query VARCHAR := FORMAT('SELECT snp_name, local_genotype from %s', temp_table_name); - temp_record RECORD; - BEGIN - FOR temp_record IN EXECUTE(query) LOOP - BEGIN - INSERT INTO user_snps (snp_name, genotype_id, local_genotype) - VALUES (temp_record.snp_name, - current_genotype_id, - temp_record.local_genotype); - EXCEPTION WHEN unique_violation THEN - UPDATE user_snps - SET local_genotype = temp_record.local_genotype - WHERE snp_name = temp_record.snp_name - AND user_snps.genotype_id = current_genotype_id; - END; - END LOOP; - END; - $$; - - -SET default_tablespace = ''; - -SET default_with_oids = false; - --- --- Name: achievements; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.achievements ( - id integer NOT NULL, - award text, - short_name character varying(255), - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: achievements_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.achievements_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: achievements_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.achievements_id_seq OWNED BY public.achievements.id; - - --- --- Name: active_admin_comments; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.active_admin_comments ( - id integer NOT NULL, - resource_id character varying(255) NOT NULL, - resource_type character varying(255) NOT NULL, - author_id integer, - author_type character varying(255), - body text, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, - namespace character varying(255) -); - - --- --- Name: active_admin_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.active_admin_comments_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: active_admin_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.active_admin_comments_id_seq OWNED BY public.active_admin_comments.id; - - --- --- Name: admin_users; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.admin_users ( - id integer NOT NULL, - email character varying(255) DEFAULT ''::character varying NOT NULL, - encrypted_password character varying(255) DEFAULT ''::character varying NOT NULL, - reset_password_token character varying(255), - reset_password_sent_at timestamp without time zone, - remember_created_at timestamp without time zone, - sign_in_count integer DEFAULT 0, - current_sign_in_at timestamp without time zone, - last_sign_in_at timestamp without time zone, - current_sign_in_ip character varying(255), - last_sign_in_ip character varying(255), - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL -); - - --- --- Name: admin_users_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.admin_users_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: admin_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.admin_users_id_seq OWNED BY public.admin_users.id; - - --- --- Name: file_links; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.file_links ( - id integer NOT NULL, - description text, - url text, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: file_links_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.file_links_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: file_links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.file_links_id_seq OWNED BY public.file_links.id; - - --- --- Name: friendly_id_slugs; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.friendly_id_slugs ( - id integer NOT NULL, - slug character varying(255) NOT NULL, - sluggable_id integer NOT NULL, - sluggable_type character varying(40), - created_at timestamp without time zone -); - - --- --- Name: friendly_id_slugs_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.friendly_id_slugs_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: friendly_id_slugs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.friendly_id_slugs_id_seq OWNED BY public.friendly_id_slugs.id; - - --- --- Name: genome_gov_papers; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.genome_gov_papers ( - id integer NOT NULL, - first_author text, - title text, - pubmed_link text, - pub_date text, - journal text, - trait text, - pvalue double precision, - pvalue_description text, - confidence_interval text, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: genome_gov_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.genome_gov_papers_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: genome_gov_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.genome_gov_papers_id_seq OWNED BY public.genome_gov_papers.id; - - --- --- Name: genotypes; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.genotypes ( - id integer NOT NULL, - filetype character varying(255) DEFAULT '23andme'::character varying, - user_id integer NOT NULL, - created_at timestamp without time zone, - updated_at timestamp without time zone, - md5sum character varying(255), - genotype_file_name character varying(255), - genotype_content_type character varying(255), - genotype_file_size integer, - genotype_updated_at timestamp without time zone -); - - --- --- Name: genotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.genotypes_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: genotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.genotypes_id_seq OWNED BY public.genotypes.id; - - --- --- Name: homepages; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.homepages ( - id integer NOT NULL, - url text, - description text, - created_at timestamp without time zone, - updated_at timestamp without time zone, - user_id integer -); - - --- --- Name: homepages_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.homepages_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: homepages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.homepages_id_seq OWNED BY public.homepages.id; - - --- --- Name: mendeley_papers; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.mendeley_papers ( - id integer NOT NULL, - first_author text, - title text, - mendeley_url text, - doi text, - pub_year integer, - uuid character varying(255), - open_access boolean, - reader integer, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: mendeley_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.mendeley_papers_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: mendeley_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.mendeley_papers_id_seq OWNED BY public.mendeley_papers.id; - - --- --- Name: messages; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.messages ( - id integer NOT NULL, - subject text, - user_id integer, - body text, - sent boolean, - user_has_seen boolean, - from_id integer, - to_id integer, - created_at timestamp without time zone, - updated_at timestamp without time zone, - encrypted_body text, - encrypted_body_iv character varying, - encrypted_subject text, - encrypted_subject_iv character varying -); - - --- --- Name: messages_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.messages_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: messages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.messages_id_seq OWNED BY public.messages.id; - - --- --- Name: open_humans_profiles; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.open_humans_profiles ( - id integer NOT NULL, - open_humans_user_id character varying, - project_member_id character varying, - user_id integer, - access_token character varying, - refresh_token character varying, - expires_in timestamp without time zone, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: open_humans_profiles_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.open_humans_profiles_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: open_humans_profiles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.open_humans_profiles_id_seq OWNED BY public.open_humans_profiles.id; - - --- --- Name: pgp_annotations; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.pgp_annotations ( - id integer NOT NULL, - gene text, - qualified_impact text, - inheritance text, - summary text, - trait text, - created_at timestamp without time zone, - updated_at timestamp without time zone, - snp_id integer -); - - --- --- Name: pgp_annotations_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.pgp_annotations_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: pgp_annotations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.pgp_annotations_id_seq OWNED BY public.pgp_annotations.id; - - --- --- Name: phenotype_comments; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.phenotype_comments ( - id integer NOT NULL, - comment_text text, - subject text, - user_id integer, - phenotype_id integer, - reply_to_id integer, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: phenotype_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.phenotype_comments_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: phenotype_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.phenotype_comments_id_seq OWNED BY public.phenotype_comments.id; - - --- --- Name: phenotype_sets; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.phenotype_sets ( - id integer NOT NULL, - user_id integer, - title character varying(255), - description text, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: phenotype_sets_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.phenotype_sets_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: phenotype_sets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.phenotype_sets_id_seq OWNED BY public.phenotype_sets.id; - - --- --- Name: phenotype_sets_phenotypes; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.phenotype_sets_phenotypes ( - phenotype_set_id integer, - phenotype_id integer -); - - --- --- Name: phenotypes; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.phenotypes ( - id integer NOT NULL, - characteristic character varying(255), - known_phenotypes text, - created_at timestamp without time zone, - updated_at timestamp without time zone, - description text -); - - --- --- Name: phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.phenotypes_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.phenotypes_id_seq OWNED BY public.phenotypes.id; - - --- --- Name: picture_phenotype_comments; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.picture_phenotype_comments ( - id integer NOT NULL, - comment_text text, - subject text, - user_id integer, - picture_phenotype_id integer, - reply_to_id integer, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: picture_phenotype_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.picture_phenotype_comments_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: picture_phenotype_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.picture_phenotype_comments_id_seq OWNED BY public.picture_phenotype_comments.id; - - --- --- Name: picture_phenotypes; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.picture_phenotypes ( - id integer NOT NULL, - characteristic character varying(255), - description text, - number_of_users integer DEFAULT 0, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: picture_phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.picture_phenotypes_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: picture_phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.picture_phenotypes_id_seq OWNED BY public.picture_phenotypes.id; - - --- --- Name: plos_papers; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.plos_papers ( - id integer NOT NULL, - first_author text, - title text, - doi text, - pub_date timestamp without time zone, - created_at timestamp without time zone, - updated_at timestamp without time zone, - reader integer -); - - --- --- Name: plos_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.plos_papers_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: plos_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.plos_papers_id_seq OWNED BY public.plos_papers.id; - - --- --- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.schema_migrations ( - version character varying(255) NOT NULL -); - - --- --- Name: snp_comments; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.snp_comments ( - id integer NOT NULL, - comment_text text, - subject text, - user_id integer, - snp_id integer, - created_at timestamp without time zone, - updated_at timestamp without time zone, - reply_to_id integer -); - - --- --- Name: snp_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.snp_comments_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: snp_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.snp_comments_id_seq OWNED BY public.snp_comments.id; - - --- --- Name: snp_references; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.snp_references ( - snp_id integer, - paper_id integer, - paper_type character varying(255) -); - - --- --- Name: snp_references_backup; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.snp_references_backup ( - snp_id integer NOT NULL, - paper_id integer NOT NULL, - paper_type character varying(255) NOT NULL -); - - --- --- Name: snpedia_papers; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.snpedia_papers ( - id integer NOT NULL, - url character varying(255), - summary text, - created_at timestamp without time zone, - updated_at timestamp without time zone, - revision integer DEFAULT 0 -); - - --- --- Name: snpedia_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.snpedia_papers_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: snpedia_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.snpedia_papers_id_seq OWNED BY public.snpedia_papers.id; - - --- --- Name: snps; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.snps ( - id integer NOT NULL, - name character varying(255), - "position" character varying(255), - chromosome character varying(255), - genotype_frequency character varying(255) DEFAULT '--- {} -'::character varying, - allele_frequency character varying(255) DEFAULT '--- -A: 0 -T: 0 -G: 0 -C: 0 -'::character varying, - ranking integer DEFAULT 0, - number_of_users integer DEFAULT 0, - mendeley_updated timestamp without time zone DEFAULT '2011-08-24 03:44:32.459467'::timestamp without time zone, - plos_updated timestamp without time zone DEFAULT '2011-08-24 03:44:32.459582'::timestamp without time zone, - snpedia_updated timestamp without time zone DEFAULT '2011-08-24 03:44:32.459627'::timestamp without time zone, - created_at timestamp without time zone, - updated_at timestamp without time zone, - user_snps_count integer -) -WITH (autovacuum_enabled='false', toast.autovacuum_enabled='false'); - - --- --- Name: snps_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.snps_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: snps_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.snps_id_seq OWNED BY public.snps.id; - - --- --- Name: user_achievements; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.user_achievements ( - id integer NOT NULL, - user_id integer, - achievement_id integer, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: user_achievements_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.user_achievements_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: user_achievements_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.user_achievements_id_seq OWNED BY public.user_achievements.id; - - --- --- Name: user_phenotypes; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.user_phenotypes ( - id integer NOT NULL, - user_id integer, - phenotype_id integer, - variation character varying(255), - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: user_phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.user_phenotypes_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: user_phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.user_phenotypes_id_seq OWNED BY public.user_phenotypes.id; - - --- --- Name: user_picture_phenotypes; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.user_picture_phenotypes ( - id integer NOT NULL, - user_id integer, - picture_phenotype_id integer, - variation character varying(255), - phenotype_picture_file_name character varying(255), - phenotype_picture_content_type character varying(255), - phenotype_picture_file_size integer, - phenotype_picture_updated_at timestamp without time zone, - created_at timestamp without time zone, - updated_at timestamp without time zone -); - - --- --- Name: user_picture_phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.user_picture_phenotypes_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: user_picture_phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.user_picture_phenotypes_id_seq OWNED BY public.user_picture_phenotypes.id; - - --- --- Name: user_snps; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.user_snps ( - snp_name character varying(32) NOT NULL, - genotype_id integer NOT NULL, - local_genotype bpchar -) -WITH (autovacuum_enabled='false', toast.autovacuum_enabled='false'); - - --- --- Name: users; Type: TABLE; Schema: public; Owner: - --- - -CREATE TABLE public.users ( - id integer NOT NULL, - name character varying(255), - email character varying(255), - password_salt character varying(255), - crypted_password character varying(255), - persistence_token character varying(255), - perishable_token character varying(255), - has_sequence boolean DEFAULT false, - sequence_link character varying(255), - description text, - finished_snp_parsing boolean DEFAULT false, - phenotype_creation_counter integer DEFAULT 0, - created_at timestamp without time zone, - updated_at timestamp without time zone, - avatar_file_name character varying(255), - avatar_content_type character varying(255), - avatar_file_size integer, - avatar_updated_at timestamp without time zone, - help_one boolean DEFAULT false, - help_two boolean DEFAULT false, - help_three boolean DEFAULT false, - sex character varying(255) DEFAULT 'rather not say'::character varying, - yearofbirth character varying(255) DEFAULT 'rather not say'::character varying, - message_on_message boolean DEFAULT true, - message_on_snp_comment_reply boolean DEFAULT true, - message_on_phenotype_comment_reply boolean DEFAULT true, - message_on_newsletter boolean DEFAULT true, - message_on_new_phenotype boolean DEFAULT false, - admin boolean DEFAULT false NOT NULL -); - - --- --- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: - --- - -CREATE SEQUENCE public.users_id_seq - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - --- --- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - --- - -ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.achievements ALTER COLUMN id SET DEFAULT nextval('public.achievements_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.active_admin_comments ALTER COLUMN id SET DEFAULT nextval('public.active_admin_comments_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.admin_users ALTER COLUMN id SET DEFAULT nextval('public.admin_users_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.file_links ALTER COLUMN id SET DEFAULT nextval('public.file_links_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.friendly_id_slugs ALTER COLUMN id SET DEFAULT nextval('public.friendly_id_slugs_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.genome_gov_papers ALTER COLUMN id SET DEFAULT nextval('public.genome_gov_papers_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.genotypes ALTER COLUMN id SET DEFAULT nextval('public.genotypes_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.homepages ALTER COLUMN id SET DEFAULT nextval('public.homepages_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.mendeley_papers ALTER COLUMN id SET DEFAULT nextval('public.mendeley_papers_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.messages ALTER COLUMN id SET DEFAULT nextval('public.messages_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.open_humans_profiles ALTER COLUMN id SET DEFAULT nextval('public.open_humans_profiles_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.pgp_annotations ALTER COLUMN id SET DEFAULT nextval('public.pgp_annotations_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.phenotype_comments ALTER COLUMN id SET DEFAULT nextval('public.phenotype_comments_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.phenotype_sets ALTER COLUMN id SET DEFAULT nextval('public.phenotype_sets_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.phenotypes ALTER COLUMN id SET DEFAULT nextval('public.phenotypes_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.picture_phenotype_comments ALTER COLUMN id SET DEFAULT nextval('public.picture_phenotype_comments_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.picture_phenotypes ALTER COLUMN id SET DEFAULT nextval('public.picture_phenotypes_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.plos_papers ALTER COLUMN id SET DEFAULT nextval('public.plos_papers_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.snp_comments ALTER COLUMN id SET DEFAULT nextval('public.snp_comments_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.snpedia_papers ALTER COLUMN id SET DEFAULT nextval('public.snpedia_papers_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.snps ALTER COLUMN id SET DEFAULT nextval('public.snps_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_achievements ALTER COLUMN id SET DEFAULT nextval('public.user_achievements_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_phenotypes ALTER COLUMN id SET DEFAULT nextval('public.user_phenotypes_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_picture_phenotypes ALTER COLUMN id SET DEFAULT nextval('public.user_picture_phenotypes_id_seq'::regclass); - - --- --- Name: id; Type: DEFAULT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); - - --- --- Name: achievements_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.achievements - ADD CONSTRAINT achievements_pkey PRIMARY KEY (id); - - --- --- Name: admin_notes_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.active_admin_comments - ADD CONSTRAINT admin_notes_pkey PRIMARY KEY (id); - - --- --- Name: admin_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.admin_users - ADD CONSTRAINT admin_users_pkey PRIMARY KEY (id); - - --- --- Name: file_links_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.file_links - ADD CONSTRAINT file_links_pkey PRIMARY KEY (id); - - --- --- Name: friendly_id_slugs_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.friendly_id_slugs - ADD CONSTRAINT friendly_id_slugs_pkey PRIMARY KEY (id); - - --- --- Name: genome_gov_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.genome_gov_papers - ADD CONSTRAINT genome_gov_papers_pkey PRIMARY KEY (id); - - --- --- Name: genotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.genotypes - ADD CONSTRAINT genotypes_pkey PRIMARY KEY (id); - - --- --- Name: homepages_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.homepages - ADD CONSTRAINT homepages_pkey PRIMARY KEY (id); - - --- --- Name: mendeley_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.mendeley_papers - ADD CONSTRAINT mendeley_papers_pkey PRIMARY KEY (id); - - --- --- Name: messages_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.messages - ADD CONSTRAINT messages_pkey PRIMARY KEY (id); - - --- --- Name: open_humans_profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.open_humans_profiles - ADD CONSTRAINT open_humans_profiles_pkey PRIMARY KEY (id); - - --- --- Name: pgp_annotations_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.pgp_annotations - ADD CONSTRAINT pgp_annotations_pkey PRIMARY KEY (id); - - --- --- Name: phenotype_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.phenotype_comments - ADD CONSTRAINT phenotype_comments_pkey PRIMARY KEY (id); - - --- --- Name: phenotype_sets_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.phenotype_sets - ADD CONSTRAINT phenotype_sets_pkey PRIMARY KEY (id); - - --- --- Name: phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.phenotypes - ADD CONSTRAINT phenotypes_pkey PRIMARY KEY (id); - - --- --- Name: picture_phenotype_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.picture_phenotype_comments - ADD CONSTRAINT picture_phenotype_comments_pkey PRIMARY KEY (id); - - --- --- Name: picture_phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.picture_phenotypes - ADD CONSTRAINT picture_phenotypes_pkey PRIMARY KEY (id); - - --- --- Name: plos_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.plos_papers - ADD CONSTRAINT plos_papers_pkey PRIMARY KEY (id); - - --- --- Name: snp_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.snp_comments - ADD CONSTRAINT snp_comments_pkey PRIMARY KEY (id); - - --- --- Name: snpedia_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.snpedia_papers - ADD CONSTRAINT snpedia_papers_pkey PRIMARY KEY (id); - - --- --- Name: snps_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.snps - ADD CONSTRAINT snps_pkey PRIMARY KEY (id); - - --- --- Name: user_achievements_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_achievements - ADD CONSTRAINT user_achievements_pkey PRIMARY KEY (id); - - --- --- Name: user_phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_phenotypes - ADD CONSTRAINT user_phenotypes_pkey PRIMARY KEY (id); - - --- --- Name: user_picture_phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_picture_phenotypes - ADD CONSTRAINT user_picture_phenotypes_pkey PRIMARY KEY (id); - - --- --- Name: user_snps_new_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_snps - ADD CONSTRAINT user_snps_new_pkey PRIMARY KEY (genotype_id, snp_name); - - --- --- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.users - ADD CONSTRAINT users_pkey PRIMARY KEY (id); - - --- --- Name: idx_user_snps_snp_name; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX idx_user_snps_snp_name ON public.user_snps USING btree (snp_name); - - --- --- Name: index_active_admin_comments_on_author_type_and_author_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_active_admin_comments_on_author_type_and_author_id ON public.active_admin_comments USING btree (author_type, author_id); - - --- --- Name: index_active_admin_comments_on_namespace; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_active_admin_comments_on_namespace ON public.active_admin_comments USING btree (namespace); - - --- --- Name: index_admin_notes_on_resource_type_and_resource_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_admin_notes_on_resource_type_and_resource_id ON public.active_admin_comments USING btree (resource_type, resource_id); - - --- --- Name: index_admin_users_on_email; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_admin_users_on_email ON public.admin_users USING btree (email); - - --- --- Name: index_admin_users_on_reset_password_token; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_admin_users_on_reset_password_token ON public.admin_users USING btree (reset_password_token); - - --- --- Name: index_friendly_id_slugs_on_slug_and_sluggable_type; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_friendly_id_slugs_on_slug_and_sluggable_type ON public.friendly_id_slugs USING btree (slug, sluggable_type); - - --- --- Name: index_friendly_id_slugs_on_sluggable_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_friendly_id_slugs_on_sluggable_id ON public.friendly_id_slugs USING btree (sluggable_id); - - --- --- Name: index_friendly_id_slugs_on_sluggable_type; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_friendly_id_slugs_on_sluggable_type ON public.friendly_id_slugs USING btree (sluggable_type); - - --- --- Name: index_snp_references_backup_on_paper_id_and_paper_type; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_snp_references_backup_on_paper_id_and_paper_type ON public.snp_references_backup USING btree (paper_id, paper_type); - - --- --- Name: index_snp_references_backup_on_snp_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_snp_references_backup_on_snp_id ON public.snp_references_backup USING btree (snp_id); - - --- --- Name: index_snp_references_on_paper_id_and_paper_type; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_snp_references_on_paper_id_and_paper_type ON public.snp_references USING btree (paper_id, paper_type); - - --- --- Name: index_snp_references_on_snp_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_snp_references_on_snp_id ON public.snp_references USING btree (snp_id); - - --- --- Name: index_snps_chromosome_position; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_snps_chromosome_position ON public.snps USING btree (chromosome, "position"); - - --- --- Name: index_snps_on_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_snps_on_id ON public.snps USING btree (id); - - --- --- Name: index_snps_on_name; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_snps_on_name ON public.snps USING btree (name); - - --- --- Name: index_snps_ranking; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX index_snps_ranking ON public.snps USING btree (ranking); - - --- --- Name: index_users_on_email; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_users_on_email ON public.users USING btree (email); - - --- --- Name: index_users_on_persistence_token; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX index_users_on_persistence_token ON public.users USING btree (persistence_token); - - --- --- Name: snps_position_idx; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX snps_position_idx ON public.snps USING btree ("position"); - - --- --- Name: user_phenotypes_phenotype_id_idx; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX user_phenotypes_phenotype_id_idx ON public.user_phenotypes USING btree (phenotype_id); - - --- --- Name: user_phenotypes_user_id_idx; Type: INDEX; Schema: public; Owner: - --- - -CREATE INDEX user_phenotypes_user_id_idx ON public.user_phenotypes USING btree (user_id); - - --- --- Name: genotypes_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.genotypes - ADD CONSTRAINT genotypes_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); - - --- --- Name: homepages_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.homepages - ADD CONSTRAINT homepages_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); - - --- --- Name: phenotype_comments_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.phenotype_comments - ADD CONSTRAINT phenotype_comments_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); - - --- --- Name: picture_phenotype_comments_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.picture_phenotype_comments - ADD CONSTRAINT picture_phenotype_comments_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); - - --- --- Name: user_achievements_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_achievements - ADD CONSTRAINT user_achievements_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); - - --- --- Name: user_phenotypes_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_phenotypes - ADD CONSTRAINT user_phenotypes_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); - - --- --- Name: user_picture_phenotypes_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_picture_phenotypes - ADD CONSTRAINT user_picture_phenotypes_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); - - --- --- Name: user_snps_genotype_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - --- - -ALTER TABLE ONLY public.user_snps - ADD CONSTRAINT user_snps_genotype_id_fk FOREIGN KEY (genotype_id) REFERENCES public.genotypes(id); - - --- --- PostgreSQL database dump complete --- - -SET search_path TO "$user", public; - -INSERT INTO schema_migrations (version) VALUES ('20110608000645'); - -INSERT INTO schema_migrations (version) VALUES ('20110615045458'); - -INSERT INTO schema_migrations (version) VALUES ('20110615173154'); - -INSERT INTO schema_migrations (version) VALUES ('20110616192820'); - -INSERT INTO schema_migrations (version) VALUES ('20110617144145'); - -INSERT INTO schema_migrations (version) VALUES ('20110819233120'); - -INSERT INTO schema_migrations (version) VALUES ('20110820195410'); - -INSERT INTO schema_migrations (version) VALUES ('20110821112909'); - -INSERT INTO schema_migrations (version) VALUES ('20110822071221'); - -INSERT INTO schema_migrations (version) VALUES ('20110822110806'); - -INSERT INTO schema_migrations (version) VALUES ('20110823032055'); - -INSERT INTO schema_migrations (version) VALUES ('20110824164934'); - -INSERT INTO schema_migrations (version) VALUES ('20110830134100'); - -INSERT INTO schema_migrations (version) VALUES ('20110912190409'); - -INSERT INTO schema_migrations (version) VALUES ('20110914100443'); - -INSERT INTO schema_migrations (version) VALUES ('20110914100516'); - -INSERT INTO schema_migrations (version) VALUES ('20110914151105'); - -INSERT INTO schema_migrations (version) VALUES ('20110917193600'); - -INSERT INTO schema_migrations (version) VALUES ('20110926092220'); - -INSERT INTO schema_migrations (version) VALUES ('20110926172905'); - -INSERT INTO schema_migrations (version) VALUES ('20111005210020'); - -INSERT INTO schema_migrations (version) VALUES ('20111006133700'); - -INSERT INTO schema_migrations (version) VALUES ('20111006163700'); - -INSERT INTO schema_migrations (version) VALUES ('20111007141500'); - -INSERT INTO schema_migrations (version) VALUES ('20111007145000'); - -INSERT INTO schema_migrations (version) VALUES ('20111018040633'); - -INSERT INTO schema_migrations (version) VALUES ('20111028190606'); - -INSERT INTO schema_migrations (version) VALUES ('20111028212506'); - -INSERT INTO schema_migrations (version) VALUES ('20111029180506'); - -INSERT INTO schema_migrations (version) VALUES ('20111102033039'); - -INSERT INTO schema_migrations (version) VALUES ('20111212063354'); - -INSERT INTO schema_migrations (version) VALUES ('20120208020405'); - -INSERT INTO schema_migrations (version) VALUES ('20120324143135'); - -INSERT INTO schema_migrations (version) VALUES ('20120509234035'); - -INSERT INTO schema_migrations (version) VALUES ('20120902113435'); - -INSERT INTO schema_migrations (version) VALUES ('20120902174500'); - -INSERT INTO schema_migrations (version) VALUES ('20120902175000'); - -INSERT INTO schema_migrations (version) VALUES ('20120902175500'); - -INSERT INTO schema_migrations (version) VALUES ('20120916211800'); - -INSERT INTO schema_migrations (version) VALUES ('20120916212700'); - -INSERT INTO schema_migrations (version) VALUES ('20121006230458'); - -INSERT INTO schema_migrations (version) VALUES ('20121020153113'); - -INSERT INTO schema_migrations (version) VALUES ('20121023032404'); - -INSERT INTO schema_migrations (version) VALUES ('20121123234958'); - -INSERT INTO schema_migrations (version) VALUES ('20121123235228'); - -INSERT INTO schema_migrations (version) VALUES ('20121124201111'); - -INSERT INTO schema_migrations (version) VALUES ('20121210131554'); - -INSERT INTO schema_migrations (version) VALUES ('20121213120010'); - -INSERT INTO schema_migrations (version) VALUES ('20130124085042'); - -INSERT INTO schema_migrations (version) VALUES ('20130608135719'); - -INSERT INTO schema_migrations (version) VALUES ('20130904010945'); - -INSERT INTO schema_migrations (version) VALUES ('20130904010949'); - -INSERT INTO schema_migrations (version) VALUES ('20130904010950'); - -INSERT INTO schema_migrations (version) VALUES ('20131117101353'); - -INSERT INTO schema_migrations (version) VALUES ('20131130123430'); - -INSERT INTO schema_migrations (version) VALUES ('20140120005457'); - -INSERT INTO schema_migrations (version) VALUES ('20140221060607'); - -INSERT INTO schema_migrations (version) VALUES ('20140509001806'); - -INSERT INTO schema_migrations (version) VALUES ('20140820071334'); - -INSERT INTO schema_migrations (version) VALUES ('20150524081137'); - -INSERT INTO schema_migrations (version) VALUES ('20150916070052'); - -INSERT INTO schema_migrations (version) VALUES ('20151019160643'); - -INSERT INTO schema_migrations (version) VALUES ('20151028130755'); - -INSERT INTO schema_migrations (version) VALUES ('20151119070640'); - -INSERT INTO schema_migrations (version) VALUES ('20160207043305'); - -INSERT INTO schema_migrations (version) VALUES ('20160626121340'); - -INSERT INTO schema_migrations (version) VALUES ('20160806143618'); - -INSERT INTO schema_migrations (version) VALUES ('20161226175703'); - -INSERT INTO schema_migrations (version) VALUES ('20171113104813'); - -INSERT INTO schema_migrations (version) VALUES ('20180118100003'); - -INSERT INTO schema_migrations (version) VALUES ('20180521160808'); - +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 9.5.11 +-- Dumped by pg_dump version 12.12 (Ubuntu 12.12-0ubuntu0.20.04.1) + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: hstore; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public; + + +-- +-- Name: EXTENSION hstore; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION hstore IS 'data type for storing sets of (key, value) pairs'; + + +-- +-- Name: pg_stat_statements; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA public; + + +-- +-- Name: EXTENSION pg_stat_statements; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION pg_stat_statements IS 'track execution statistics of all SQL statements executed'; + + +-- +-- Name: tablefunc; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS tablefunc WITH SCHEMA public; + + +-- +-- Name: EXTENSION tablefunc; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION tablefunc IS 'functions that manipulate whole tables, including crosstab'; + + +-- +-- Name: find_bad_row(text); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.find_bad_row(tablename text) RETURNS tid + LANGUAGE plpgsql + AS $_$ +DECLARE +result tid; +curs REFCURSOR; +row1 RECORD; +row2 RECORD; +tabName TEXT; +count BIGINT := 0; +BEGIN +SELECT reverse(split_part(reverse($1), '.', 1)) INTO tabName; +OPEN curs FOR EXECUTE 'SELECT ctid FROM ' || tableName; +count := 1; +FETCH curs INTO row1; +WHILE row1.ctid IS NOT NULL LOOP +result = row1.ctid; +count := count + 1; +FETCH curs INTO row1; +EXECUTE 'SELECT (each(hstore(' || tabName || '))).* FROM ' +|| tableName || ' WHERE ctid = $1' INTO row2 +USING row1.ctid; +IF count % 100000 = 0 THEN +RAISE NOTICE 'rows processed: %', count; +END IF; +END LOOP; +CLOSE curs; +RETURN row1.ctid; +EXCEPTION +WHEN OTHERS THEN +RAISE NOTICE 'LAST CTID: %', result; +RAISE NOTICE '%: %', SQLSTATE, SQLERRM; +RETURN result; +END +$_$; + + +-- +-- Name: upsert_user_snps(integer); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.upsert_user_snps(current_genotype_id integer) RETURNS void + LANGUAGE plpgsql + AS $$ + DECLARE + temp_table_name VARCHAR := CONCAT('user_snps_temp_', current_genotype_id::varchar); + query VARCHAR := FORMAT('SELECT snp_name, local_genotype from %s', temp_table_name); + temp_record RECORD; + BEGIN + FOR temp_record IN EXECUTE(query) LOOP + BEGIN + INSERT INTO user_snps (snp_name, genotype_id, local_genotype) + VALUES (temp_record.snp_name, + current_genotype_id, + temp_record.local_genotype); + EXCEPTION WHEN unique_violation THEN + UPDATE user_snps + SET local_genotype = temp_record.local_genotype + WHERE snp_name = temp_record.snp_name + AND user_snps.genotype_id = current_genotype_id; + END; + END LOOP; + END; + $$; + + +SET default_tablespace = ''; + +-- +-- Name: achievements; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.achievements ( + id integer NOT NULL, + award text, + short_name character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: achievements_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.achievements_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: achievements_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.achievements_id_seq OWNED BY public.achievements.id; + + +-- +-- Name: active_admin_comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.active_admin_comments ( + id integer NOT NULL, + resource_id character varying(255) NOT NULL, + resource_type character varying(255) NOT NULL, + author_id integer, + author_type character varying(255), + body text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + namespace character varying(255) +); + + +-- +-- Name: active_admin_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.active_admin_comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: active_admin_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.active_admin_comments_id_seq OWNED BY public.active_admin_comments.id; + + +-- +-- Name: admin_users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.admin_users ( + id integer NOT NULL, + email character varying(255) DEFAULT ''::character varying NOT NULL, + encrypted_password character varying(255) DEFAULT ''::character varying NOT NULL, + reset_password_token character varying(255), + reset_password_sent_at timestamp without time zone, + remember_created_at timestamp without time zone, + sign_in_count integer DEFAULT 0, + current_sign_in_at timestamp without time zone, + last_sign_in_at timestamp without time zone, + current_sign_in_ip character varying(255), + last_sign_in_ip character varying(255), + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: admin_users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.admin_users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: admin_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.admin_users_id_seq OWNED BY public.admin_users.id; + + +-- +-- Name: file_links; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.file_links ( + id integer NOT NULL, + description text, + url text, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: file_links_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.file_links_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: file_links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.file_links_id_seq OWNED BY public.file_links.id; + + +-- +-- Name: friendly_id_slugs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.friendly_id_slugs ( + id integer NOT NULL, + slug character varying(255) NOT NULL, + sluggable_id integer NOT NULL, + sluggable_type character varying(40), + created_at timestamp without time zone +); + + +-- +-- Name: friendly_id_slugs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.friendly_id_slugs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: friendly_id_slugs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.friendly_id_slugs_id_seq OWNED BY public.friendly_id_slugs.id; + + +-- +-- Name: genome_gov_papers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.genome_gov_papers ( + id integer NOT NULL, + first_author text, + title text, + pubmed_link text, + pub_date text, + journal text, + trait text, + pvalue double precision, + pvalue_description text, + confidence_interval text, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: genome_gov_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.genome_gov_papers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: genome_gov_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.genome_gov_papers_id_seq OWNED BY public.genome_gov_papers.id; + + +-- +-- Name: genotypes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.genotypes ( + id integer NOT NULL, + filetype character varying(255) DEFAULT '23andme'::character varying, + user_id integer NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, + md5sum character varying(255), + genotype_file_name character varying(255), + genotype_content_type character varying(255), + genotype_file_size integer, + genotype_updated_at timestamp without time zone +); + + +-- +-- Name: genotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.genotypes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: genotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.genotypes_id_seq OWNED BY public.genotypes.id; + + +-- +-- Name: homepages; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.homepages ( + id integer NOT NULL, + url text, + description text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_id integer +); + + +-- +-- Name: homepages_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.homepages_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: homepages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.homepages_id_seq OWNED BY public.homepages.id; + + +-- +-- Name: mendeley_papers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.mendeley_papers ( + id integer NOT NULL, + first_author text, + title text, + mendeley_url text, + doi text, + pub_year integer, + uuid character varying(255), + open_access boolean, + reader integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: mendeley_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.mendeley_papers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: mendeley_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.mendeley_papers_id_seq OWNED BY public.mendeley_papers.id; + + +-- +-- Name: messages; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.messages ( + id integer NOT NULL, + subject text, + user_id integer, + body text, + sent boolean, + user_has_seen boolean, + from_id integer, + to_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + encrypted_body text, + encrypted_body_iv character varying, + encrypted_subject text, + encrypted_subject_iv character varying +); + + +-- +-- Name: messages_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.messages_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: messages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.messages_id_seq OWNED BY public.messages.id; + + +-- +-- Name: open_humans_profiles; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.open_humans_profiles ( + id integer NOT NULL, + open_humans_user_id character varying, + project_member_id character varying, + user_id integer, + access_token character varying, + refresh_token character varying, + expires_in timestamp without time zone, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: open_humans_profiles_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.open_humans_profiles_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: open_humans_profiles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.open_humans_profiles_id_seq OWNED BY public.open_humans_profiles.id; + + +-- +-- Name: pgp_annotations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.pgp_annotations ( + id integer NOT NULL, + gene text, + qualified_impact text, + inheritance text, + summary text, + trait text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + snp_id integer +); + + +-- +-- Name: pgp_annotations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.pgp_annotations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: pgp_annotations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.pgp_annotations_id_seq OWNED BY public.pgp_annotations.id; + + +-- +-- Name: phenotype_comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phenotype_comments ( + id integer NOT NULL, + comment_text text, + subject text, + user_id integer, + phenotype_id integer, + reply_to_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: phenotype_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.phenotype_comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: phenotype_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.phenotype_comments_id_seq OWNED BY public.phenotype_comments.id; + + +-- +-- Name: phenotype_sets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phenotype_sets ( + id integer NOT NULL, + user_id integer, + title character varying(255), + description text, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: phenotype_sets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.phenotype_sets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: phenotype_sets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.phenotype_sets_id_seq OWNED BY public.phenotype_sets.id; + + +-- +-- Name: phenotype_sets_phenotypes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phenotype_sets_phenotypes ( + phenotype_set_id integer, + phenotype_id integer +); + + +-- +-- Name: phenotypes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.phenotypes ( + id integer NOT NULL, + characteristic character varying(255), + known_phenotypes text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + description text +); + + +-- +-- Name: phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.phenotypes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.phenotypes_id_seq OWNED BY public.phenotypes.id; + + +-- +-- Name: picture_phenotype_comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.picture_phenotype_comments ( + id integer NOT NULL, + comment_text text, + subject text, + user_id integer, + picture_phenotype_id integer, + reply_to_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: picture_phenotype_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.picture_phenotype_comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: picture_phenotype_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.picture_phenotype_comments_id_seq OWNED BY public.picture_phenotype_comments.id; + + +-- +-- Name: picture_phenotypes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.picture_phenotypes ( + id integer NOT NULL, + characteristic character varying(255), + description text, + number_of_users integer DEFAULT 0, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: picture_phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.picture_phenotypes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: picture_phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.picture_phenotypes_id_seq OWNED BY public.picture_phenotypes.id; + + +-- +-- Name: plos_papers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.plos_papers ( + id integer NOT NULL, + first_author text, + title text, + doi text, + pub_date timestamp without time zone, + created_at timestamp without time zone, + updated_at timestamp without time zone, + reader integer +); + + +-- +-- Name: plos_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.plos_papers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: plos_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.plos_papers_id_seq OWNED BY public.plos_papers.id; + + +-- +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.schema_migrations ( + version character varying(255) NOT NULL +); + + +-- +-- Name: snp_comments; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.snp_comments ( + id integer NOT NULL, + comment_text text, + subject text, + user_id integer, + snp_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + reply_to_id integer +); + + +-- +-- Name: snp_comments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.snp_comments_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: snp_comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.snp_comments_id_seq OWNED BY public.snp_comments.id; + + +-- +-- Name: snp_references; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.snp_references ( + snp_id integer, + paper_id integer, + paper_type character varying(255) +); + + +-- +-- Name: snp_references_backup; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.snp_references_backup ( + snp_id integer NOT NULL, + paper_id integer NOT NULL, + paper_type character varying(255) NOT NULL +); + + +-- +-- Name: snpedia_papers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.snpedia_papers ( + id integer NOT NULL, + url character varying(255), + summary text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + revision integer DEFAULT 0 +); + + +-- +-- Name: snpedia_papers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.snpedia_papers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: snpedia_papers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.snpedia_papers_id_seq OWNED BY public.snpedia_papers.id; + + +-- +-- Name: snps; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.snps ( + id integer NOT NULL, + name character varying(255), + "position" character varying(255), + chromosome character varying(255), + genotype_frequency character varying(255) DEFAULT '--- {} +'::character varying, + allele_frequency character varying(255) DEFAULT '--- +A: 0 +T: 0 +G: 0 +C: 0 +'::character varying, + ranking integer DEFAULT 0, + number_of_users integer DEFAULT 0, + mendeley_updated timestamp without time zone DEFAULT '2011-08-24 03:44:32.459467'::timestamp without time zone, + plos_updated timestamp without time zone DEFAULT '2011-08-24 03:44:32.459582'::timestamp without time zone, + snpedia_updated timestamp without time zone DEFAULT '2011-08-24 03:44:32.459627'::timestamp without time zone, + created_at timestamp without time zone, + updated_at timestamp without time zone, + user_snps_count integer +) +WITH (autovacuum_enabled='false', toast.autovacuum_enabled='false'); + + +-- +-- Name: snps_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.snps_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: snps_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.snps_id_seq OWNED BY public.snps.id; + + +-- +-- Name: user_achievements; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.user_achievements ( + id integer NOT NULL, + user_id integer, + achievement_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: user_achievements_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.user_achievements_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: user_achievements_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.user_achievements_id_seq OWNED BY public.user_achievements.id; + + +-- +-- Name: user_phenotypes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.user_phenotypes ( + id integer NOT NULL, + user_id integer, + phenotype_id integer, + variation character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: user_phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.user_phenotypes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: user_phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.user_phenotypes_id_seq OWNED BY public.user_phenotypes.id; + + +-- +-- Name: user_picture_phenotypes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.user_picture_phenotypes ( + id integer NOT NULL, + user_id integer, + picture_phenotype_id integer, + variation character varying(255), + phenotype_picture_file_name character varying(255), + phenotype_picture_content_type character varying(255), + phenotype_picture_file_size integer, + phenotype_picture_updated_at timestamp without time zone, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: user_picture_phenotypes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.user_picture_phenotypes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: user_picture_phenotypes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.user_picture_phenotypes_id_seq OWNED BY public.user_picture_phenotypes.id; + + +-- +-- Name: user_snps; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.user_snps ( + snp_name character varying(32) NOT NULL, + genotype_id integer NOT NULL, + local_genotype bpchar +) +WITH (autovacuum_enabled='false', toast.autovacuum_enabled='false'); + + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.users ( + id integer NOT NULL, + name character varying(255), + email character varying(255), + password_salt character varying(255), + crypted_password character varying(255), + persistence_token character varying(255), + perishable_token character varying(255), + has_sequence boolean DEFAULT false, + sequence_link character varying(255), + description text, + finished_snp_parsing boolean DEFAULT false, + phenotype_creation_counter integer DEFAULT 0, + created_at timestamp without time zone, + updated_at timestamp without time zone, + avatar_file_name character varying(255), + avatar_content_type character varying(255), + avatar_file_size integer, + avatar_updated_at timestamp without time zone, + help_one boolean DEFAULT false, + help_two boolean DEFAULT false, + help_three boolean DEFAULT false, + sex character varying(255) DEFAULT 'rather not say'::character varying, + yearofbirth character varying(255) DEFAULT 'rather not say'::character varying, + message_on_message boolean DEFAULT true, + message_on_snp_comment_reply boolean DEFAULT true, + message_on_phenotype_comment_reply boolean DEFAULT true, + message_on_newsletter boolean DEFAULT true, + message_on_new_phenotype boolean DEFAULT false, + admin boolean DEFAULT false NOT NULL +); + + +-- +-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; + + +-- +-- Name: achievements id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.achievements ALTER COLUMN id SET DEFAULT nextval('public.achievements_id_seq'::regclass); + + +-- +-- Name: active_admin_comments id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.active_admin_comments ALTER COLUMN id SET DEFAULT nextval('public.active_admin_comments_id_seq'::regclass); + + +-- +-- Name: admin_users id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.admin_users ALTER COLUMN id SET DEFAULT nextval('public.admin_users_id_seq'::regclass); + + +-- +-- Name: file_links id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.file_links ALTER COLUMN id SET DEFAULT nextval('public.file_links_id_seq'::regclass); + + +-- +-- Name: friendly_id_slugs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.friendly_id_slugs ALTER COLUMN id SET DEFAULT nextval('public.friendly_id_slugs_id_seq'::regclass); + + +-- +-- Name: genome_gov_papers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.genome_gov_papers ALTER COLUMN id SET DEFAULT nextval('public.genome_gov_papers_id_seq'::regclass); + + +-- +-- Name: genotypes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.genotypes ALTER COLUMN id SET DEFAULT nextval('public.genotypes_id_seq'::regclass); + + +-- +-- Name: homepages id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.homepages ALTER COLUMN id SET DEFAULT nextval('public.homepages_id_seq'::regclass); + + +-- +-- Name: mendeley_papers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.mendeley_papers ALTER COLUMN id SET DEFAULT nextval('public.mendeley_papers_id_seq'::regclass); + + +-- +-- Name: messages id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.messages ALTER COLUMN id SET DEFAULT nextval('public.messages_id_seq'::regclass); + + +-- +-- Name: open_humans_profiles id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.open_humans_profiles ALTER COLUMN id SET DEFAULT nextval('public.open_humans_profiles_id_seq'::regclass); + + +-- +-- Name: pgp_annotations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.pgp_annotations ALTER COLUMN id SET DEFAULT nextval('public.pgp_annotations_id_seq'::regclass); + + +-- +-- Name: phenotype_comments id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phenotype_comments ALTER COLUMN id SET DEFAULT nextval('public.phenotype_comments_id_seq'::regclass); + + +-- +-- Name: phenotype_sets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phenotype_sets ALTER COLUMN id SET DEFAULT nextval('public.phenotype_sets_id_seq'::regclass); + + +-- +-- Name: phenotypes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phenotypes ALTER COLUMN id SET DEFAULT nextval('public.phenotypes_id_seq'::regclass); + + +-- +-- Name: picture_phenotype_comments id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.picture_phenotype_comments ALTER COLUMN id SET DEFAULT nextval('public.picture_phenotype_comments_id_seq'::regclass); + + +-- +-- Name: picture_phenotypes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.picture_phenotypes ALTER COLUMN id SET DEFAULT nextval('public.picture_phenotypes_id_seq'::regclass); + + +-- +-- Name: plos_papers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plos_papers ALTER COLUMN id SET DEFAULT nextval('public.plos_papers_id_seq'::regclass); + + +-- +-- Name: snp_comments id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.snp_comments ALTER COLUMN id SET DEFAULT nextval('public.snp_comments_id_seq'::regclass); + + +-- +-- Name: snpedia_papers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.snpedia_papers ALTER COLUMN id SET DEFAULT nextval('public.snpedia_papers_id_seq'::regclass); + + +-- +-- Name: snps id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.snps ALTER COLUMN id SET DEFAULT nextval('public.snps_id_seq'::regclass); + + +-- +-- Name: user_achievements id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_achievements ALTER COLUMN id SET DEFAULT nextval('public.user_achievements_id_seq'::regclass); + + +-- +-- Name: user_phenotypes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_phenotypes ALTER COLUMN id SET DEFAULT nextval('public.user_phenotypes_id_seq'::regclass); + + +-- +-- Name: user_picture_phenotypes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_picture_phenotypes ALTER COLUMN id SET DEFAULT nextval('public.user_picture_phenotypes_id_seq'::regclass); + + +-- +-- Name: users id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); + + +-- +-- Name: achievements achievements_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.achievements + ADD CONSTRAINT achievements_pkey PRIMARY KEY (id); + + +-- +-- Name: active_admin_comments admin_notes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.active_admin_comments + ADD CONSTRAINT admin_notes_pkey PRIMARY KEY (id); + + +-- +-- Name: admin_users admin_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.admin_users + ADD CONSTRAINT admin_users_pkey PRIMARY KEY (id); + + +-- +-- Name: file_links file_links_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.file_links + ADD CONSTRAINT file_links_pkey PRIMARY KEY (id); + + +-- +-- Name: friendly_id_slugs friendly_id_slugs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.friendly_id_slugs + ADD CONSTRAINT friendly_id_slugs_pkey PRIMARY KEY (id); + + +-- +-- Name: genome_gov_papers genome_gov_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.genome_gov_papers + ADD CONSTRAINT genome_gov_papers_pkey PRIMARY KEY (id); + + +-- +-- Name: genotypes genotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.genotypes + ADD CONSTRAINT genotypes_pkey PRIMARY KEY (id); + + +-- +-- Name: homepages homepages_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.homepages + ADD CONSTRAINT homepages_pkey PRIMARY KEY (id); + + +-- +-- Name: mendeley_papers mendeley_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.mendeley_papers + ADD CONSTRAINT mendeley_papers_pkey PRIMARY KEY (id); + + +-- +-- Name: messages messages_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.messages + ADD CONSTRAINT messages_pkey PRIMARY KEY (id); + + +-- +-- Name: open_humans_profiles open_humans_profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.open_humans_profiles + ADD CONSTRAINT open_humans_profiles_pkey PRIMARY KEY (id); + + +-- +-- Name: pgp_annotations pgp_annotations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.pgp_annotations + ADD CONSTRAINT pgp_annotations_pkey PRIMARY KEY (id); + + +-- +-- Name: phenotype_comments phenotype_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phenotype_comments + ADD CONSTRAINT phenotype_comments_pkey PRIMARY KEY (id); + + +-- +-- Name: phenotype_sets phenotype_sets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phenotype_sets + ADD CONSTRAINT phenotype_sets_pkey PRIMARY KEY (id); + + +-- +-- Name: phenotypes phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phenotypes + ADD CONSTRAINT phenotypes_pkey PRIMARY KEY (id); + + +-- +-- Name: picture_phenotype_comments picture_phenotype_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.picture_phenotype_comments + ADD CONSTRAINT picture_phenotype_comments_pkey PRIMARY KEY (id); + + +-- +-- Name: picture_phenotypes picture_phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.picture_phenotypes + ADD CONSTRAINT picture_phenotypes_pkey PRIMARY KEY (id); + + +-- +-- Name: plos_papers plos_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plos_papers + ADD CONSTRAINT plos_papers_pkey PRIMARY KEY (id); + + +-- +-- Name: snp_comments snp_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.snp_comments + ADD CONSTRAINT snp_comments_pkey PRIMARY KEY (id); + + +-- +-- Name: snpedia_papers snpedia_papers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.snpedia_papers + ADD CONSTRAINT snpedia_papers_pkey PRIMARY KEY (id); + + +-- +-- Name: snps snps_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.snps + ADD CONSTRAINT snps_pkey PRIMARY KEY (id); + + +-- +-- Name: user_achievements user_achievements_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_achievements + ADD CONSTRAINT user_achievements_pkey PRIMARY KEY (id); + + +-- +-- Name: user_phenotypes user_phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_phenotypes + ADD CONSTRAINT user_phenotypes_pkey PRIMARY KEY (id); + + +-- +-- Name: user_picture_phenotypes user_picture_phenotypes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_picture_phenotypes + ADD CONSTRAINT user_picture_phenotypes_pkey PRIMARY KEY (id); + + +-- +-- Name: user_snps user_snps_new_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_snps + ADD CONSTRAINT user_snps_new_pkey PRIMARY KEY (genotype_id, snp_name); + + +-- +-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_pkey PRIMARY KEY (id); + + +-- +-- Name: idx_user_snps_snp_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX idx_user_snps_snp_name ON public.user_snps USING btree (snp_name); + + +-- +-- Name: index_active_admin_comments_on_author_type_and_author_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_active_admin_comments_on_author_type_and_author_id ON public.active_admin_comments USING btree (author_type, author_id); + + +-- +-- Name: index_active_admin_comments_on_namespace; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_active_admin_comments_on_namespace ON public.active_admin_comments USING btree (namespace); + + +-- +-- Name: index_admin_notes_on_resource_type_and_resource_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_admin_notes_on_resource_type_and_resource_id ON public.active_admin_comments USING btree (resource_type, resource_id); + + +-- +-- Name: index_admin_users_on_email; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_admin_users_on_email ON public.admin_users USING btree (email); + + +-- +-- Name: index_admin_users_on_reset_password_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_admin_users_on_reset_password_token ON public.admin_users USING btree (reset_password_token); + + +-- +-- Name: index_friendly_id_slugs_on_slug_and_sluggable_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_friendly_id_slugs_on_slug_and_sluggable_type ON public.friendly_id_slugs USING btree (slug, sluggable_type); + + +-- +-- Name: index_friendly_id_slugs_on_sluggable_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_friendly_id_slugs_on_sluggable_id ON public.friendly_id_slugs USING btree (sluggable_id); + + +-- +-- Name: index_friendly_id_slugs_on_sluggable_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_friendly_id_slugs_on_sluggable_type ON public.friendly_id_slugs USING btree (sluggable_type); + + +-- +-- Name: index_snp_references_backup_on_paper_id_and_paper_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_snp_references_backup_on_paper_id_and_paper_type ON public.snp_references_backup USING btree (paper_id, paper_type); + + +-- +-- Name: index_snp_references_backup_on_snp_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_snp_references_backup_on_snp_id ON public.snp_references_backup USING btree (snp_id); + + +-- +-- Name: index_snp_references_on_paper_id_and_paper_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_snp_references_on_paper_id_and_paper_type ON public.snp_references USING btree (paper_id, paper_type); + + +-- +-- Name: index_snp_references_on_snp_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_snp_references_on_snp_id ON public.snp_references USING btree (snp_id); + + +-- +-- Name: index_snps_chromosome_position; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_snps_chromosome_position ON public.snps USING btree (chromosome, "position"); + + +-- +-- Name: index_snps_on_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_snps_on_id ON public.snps USING btree (id); + + +-- +-- Name: index_snps_on_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_snps_on_name ON public.snps USING btree (name); + + +-- +-- Name: index_snps_ranking; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_snps_ranking ON public.snps USING btree (ranking); + + +-- +-- Name: index_users_on_email; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_email ON public.users USING btree (email); + + +-- +-- Name: index_users_on_persistence_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_persistence_token ON public.users USING btree (persistence_token); + + +-- +-- Name: snps_position_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX snps_position_idx ON public.snps USING btree ("position"); + + +-- +-- Name: user_phenotypes_phenotype_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX user_phenotypes_phenotype_id_idx ON public.user_phenotypes USING btree (phenotype_id); + + +-- +-- Name: user_phenotypes_user_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX user_phenotypes_user_id_idx ON public.user_phenotypes USING btree (user_id); + + +-- +-- Name: genotypes genotypes_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.genotypes + ADD CONSTRAINT genotypes_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: homepages homepages_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.homepages + ADD CONSTRAINT homepages_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: phenotype_comments phenotype_comments_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.phenotype_comments + ADD CONSTRAINT phenotype_comments_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: picture_phenotype_comments picture_phenotype_comments_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.picture_phenotype_comments + ADD CONSTRAINT picture_phenotype_comments_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: user_achievements user_achievements_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_achievements + ADD CONSTRAINT user_achievements_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: user_phenotypes user_phenotypes_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_phenotypes + ADD CONSTRAINT user_phenotypes_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: user_picture_phenotypes user_picture_phenotypes_user_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_picture_phenotypes + ADD CONSTRAINT user_picture_phenotypes_user_id_fk FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: user_snps user_snps_genotype_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_snps + ADD CONSTRAINT user_snps_genotype_id_fk FOREIGN KEY (genotype_id) REFERENCES public.genotypes(id); + + +-- +-- PostgreSQL database dump complete +-- + +SET search_path TO "$user", public; + +INSERT INTO schema_migrations (version) VALUES ('20110608000645'); + +INSERT INTO schema_migrations (version) VALUES ('20110615045458'); + +INSERT INTO schema_migrations (version) VALUES ('20110615173154'); + +INSERT INTO schema_migrations (version) VALUES ('20110616192820'); + +INSERT INTO schema_migrations (version) VALUES ('20110617144145'); + +INSERT INTO schema_migrations (version) VALUES ('20110819233120'); + +INSERT INTO schema_migrations (version) VALUES ('20110820195410'); + +INSERT INTO schema_migrations (version) VALUES ('20110821112909'); + +INSERT INTO schema_migrations (version) VALUES ('20110822071221'); + +INSERT INTO schema_migrations (version) VALUES ('20110822110806'); + +INSERT INTO schema_migrations (version) VALUES ('20110823032055'); + +INSERT INTO schema_migrations (version) VALUES ('20110824164934'); + +INSERT INTO schema_migrations (version) VALUES ('20110830134100'); + +INSERT INTO schema_migrations (version) VALUES ('20110912190409'); + +INSERT INTO schema_migrations (version) VALUES ('20110914100443'); + +INSERT INTO schema_migrations (version) VALUES ('20110914100516'); + +INSERT INTO schema_migrations (version) VALUES ('20110914151105'); + +INSERT INTO schema_migrations (version) VALUES ('20110917193600'); + +INSERT INTO schema_migrations (version) VALUES ('20110926092220'); + +INSERT INTO schema_migrations (version) VALUES ('20110926172905'); + +INSERT INTO schema_migrations (version) VALUES ('20111005210020'); + +INSERT INTO schema_migrations (version) VALUES ('20111006133700'); + +INSERT INTO schema_migrations (version) VALUES ('20111006163700'); + +INSERT INTO schema_migrations (version) VALUES ('20111007141500'); + +INSERT INTO schema_migrations (version) VALUES ('20111007145000'); + +INSERT INTO schema_migrations (version) VALUES ('20111018040633'); + +INSERT INTO schema_migrations (version) VALUES ('20111028190606'); + +INSERT INTO schema_migrations (version) VALUES ('20111028212506'); + +INSERT INTO schema_migrations (version) VALUES ('20111029180506'); + +INSERT INTO schema_migrations (version) VALUES ('20111102033039'); + +INSERT INTO schema_migrations (version) VALUES ('20111212063354'); + +INSERT INTO schema_migrations (version) VALUES ('20120208020405'); + +INSERT INTO schema_migrations (version) VALUES ('20120324143135'); + +INSERT INTO schema_migrations (version) VALUES ('20120509234035'); + +INSERT INTO schema_migrations (version) VALUES ('20120902113435'); + +INSERT INTO schema_migrations (version) VALUES ('20120902174500'); + +INSERT INTO schema_migrations (version) VALUES ('20120902175000'); + +INSERT INTO schema_migrations (version) VALUES ('20120902175500'); + +INSERT INTO schema_migrations (version) VALUES ('20120916211800'); + +INSERT INTO schema_migrations (version) VALUES ('20120916212700'); + +INSERT INTO schema_migrations (version) VALUES ('20121006230458'); + +INSERT INTO schema_migrations (version) VALUES ('20121020153113'); + +INSERT INTO schema_migrations (version) VALUES ('20121023032404'); + +INSERT INTO schema_migrations (version) VALUES ('20121123234958'); + +INSERT INTO schema_migrations (version) VALUES ('20121123235228'); + +INSERT INTO schema_migrations (version) VALUES ('20121124201111'); + +INSERT INTO schema_migrations (version) VALUES ('20121210131554'); + +INSERT INTO schema_migrations (version) VALUES ('20121213120010'); + +INSERT INTO schema_migrations (version) VALUES ('20130124085042'); + +INSERT INTO schema_migrations (version) VALUES ('20130608135719'); + +INSERT INTO schema_migrations (version) VALUES ('20130904010945'); + +INSERT INTO schema_migrations (version) VALUES ('20130904010949'); + +INSERT INTO schema_migrations (version) VALUES ('20130904010950'); + +INSERT INTO schema_migrations (version) VALUES ('20131117101353'); + +INSERT INTO schema_migrations (version) VALUES ('20131130123430'); + +INSERT INTO schema_migrations (version) VALUES ('20140120005457'); + +INSERT INTO schema_migrations (version) VALUES ('20140221060607'); + +INSERT INTO schema_migrations (version) VALUES ('20140509001806'); + +INSERT INTO schema_migrations (version) VALUES ('20140820071334'); + +INSERT INTO schema_migrations (version) VALUES ('20150524081137'); + +INSERT INTO schema_migrations (version) VALUES ('20150916070052'); + +INSERT INTO schema_migrations (version) VALUES ('20151019160643'); + +INSERT INTO schema_migrations (version) VALUES ('20151028130755'); + +INSERT INTO schema_migrations (version) VALUES ('20151119070640'); + +INSERT INTO schema_migrations (version) VALUES ('20160207043305'); + +INSERT INTO schema_migrations (version) VALUES ('20160626121340'); + +INSERT INTO schema_migrations (version) VALUES ('20160806143618'); + +INSERT INTO schema_migrations (version) VALUES ('20161226175703'); + +INSERT INTO schema_migrations (version) VALUES ('20171113104813'); + +INSERT INTO schema_migrations (version) VALUES ('20180118100003'); + +INSERT INTO schema_migrations (version) VALUES ('20180521160808'); + diff --git a/lib/tasks/dump.rake b/lib/tasks/dump.rake index 43457d1..373c2a8 100644 --- a/lib/tasks/dump.rake +++ b/lib/tasks/dump.rake @@ -2,6 +2,6 @@ namespace :dump do desc 'dump all the data' task full: :environment do - Zipfulldata.perform_async + DataZipperWorker.perform_async end end diff --git a/spec/factories/genotypes.rb b/spec/factories/genotypes.rb index a168cdd..f7f0767 100644 --- a/spec/factories/genotypes.rb +++ b/spec/factories/genotypes.rb @@ -2,7 +2,7 @@ FactoryBot.define do factory :genotype do - genotype_file_name { 'foo.txt' } + genotype { File.new(Rails.root.join('spec', 'fixtures', 'files', 'genotype.txt')) } user end end diff --git a/spec/factories/open_humans_profiles.rb b/spec/factories/open_humans_profiles.rb new file mode 100644 index 0000000..6350943 --- /dev/null +++ b/spec/factories/open_humans_profiles.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :open_humans_profile do + sequence(:open_humans_user_id) { |n| "oh-user-#{n}" } + end +end diff --git a/spec/factories/user_picture_phenotypes.rb b/spec/factories/user_picture_phenotypes.rb index 2c7ee8c..858193d 100644 --- a/spec/factories/user_picture_phenotypes.rb +++ b/spec/factories/user_picture_phenotypes.rb @@ -2,6 +2,7 @@ FactoryBot.define do factory :user_picture_phenotype do + phenotype_picture { File.new(Rails.root.join('spec', 'fixtures', 'files', 'image.png')) } variation { 'pink' } end end diff --git a/spec/fixtures/files/genotype.txt b/spec/fixtures/files/genotype.txt new file mode 100644 index 0000000..a2aa755 --- /dev/null +++ b/spec/fixtures/files/genotype.txt @@ -0,0 +1 @@ +assorted genotype data diff --git a/spec/fixtures/files/image.png b/spec/fixtures/files/image.png new file mode 100644 index 0000000..b13988f Binary files /dev/null and b/spec/fixtures/files/image.png differ diff --git a/spec/models/application_record_spec.rb b/spec/models/application_record_spec.rb new file mode 100644 index 0000000..d99cdc7 --- /dev/null +++ b/spec/models/application_record_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +RSpec.describe ApplicationRecord do + describe '.copy_csv' do + it 'returns an enumerator' do + expect(described_class.copy_csv('SELECT 1')).to be_a(Enumerator) + end + + it 'returns the query result as an Array of CSV rows' do + expect(described_class.copy_csv('SELECT 1 AS foo, 2 AS bar').to_a) + .to eq(["foo;bar\n", "1;2\n"]) + end + end +end diff --git a/spec/services/data_zipper_service/generate_user_phenotype_csv_spec.rb b/spec/services/data_zipper_service/generate_user_phenotype_csv_spec.rb new file mode 100644 index 0000000..72c74dc --- /dev/null +++ b/spec/services/data_zipper_service/generate_user_phenotype_csv_spec.rb @@ -0,0 +1,165 @@ +# frozen_string_literal: true + +RSpec.describe DataZipperService::GenerateUserPhenotypeCsv do + subject(:service) { described_class.new } + + # There needs to be at least one phenotype in the database for the CROSSTAB + # query to work. + let!(:phenotype_1) { create(:phenotype, characteristic: "hitchhiker's thumb") } + let!(:phenotype_2) { create(:phenotype, characteristic: 'number of eyes') } + + let(:result) { service.call } + let(:parsed_result) do + CSV.parse( + result.to_a.join, + col_sep: ';', + headers: :first_row + ) + end + + it 'returns an Enumerator' do + expect(result).to be_a(Enumerator) + end + + it 'returns something, that passes as CSV' do + expect(parsed_result).to be_a(CSV::Table) + end + + it 'includes a header in the CSV' do + expect(parsed_result.headers).to match( + %w[ + user_id + genotype_filename + date_of_birth + chrom_sex + openhumans_name + ] + Array.new(Phenotype.count) { an_instance_of(String) } + ) + end + + it 'includes all phenotype characteristics as columns' do + expect(parsed_result.headers) + .to include("hitchhiker's thumb", 'number of eyes') + end + + context 'for users without genotypes' do + let!(:user) { create(:user) } + let!(:user_phenotype) do + create(:user_phenotype, user: user, phenotype: phenotype_1, variation: 'yes') + end + + it 'does not include their phenotypes in the CSV' do + expect(parsed_result['user_id']).not_to include(user.id.to_s) + end + end + + context 'for users without any phenotypes entered' do + let!(:user) { create(:user) } + let!(:genotype) { create(:genotype, user: user) } + + it 'includes them in the CSV' do + expect(parsed_result['user_id']).to include(user.id.to_s) + end + end + + context 'for users with genotypes' do + let!(:user_1) { create(:user, sex: 'why not', yearofbirth: 1990) } + let!(:user_2) { create(:user, sex: 'female', yearofbirth: 1970) } + + let!(:genotype_1) { create(:genotype, user: user_1) } + let!(:genotype_2) { create(:genotype, user: user_2) } + let!(:genotype_3) { create(:genotype, user: user_2) } + + let!(:user_phenotype_1) do + create( + :user_phenotype, + phenotype: phenotype_1, + variation: 'yes', + user: user_1 + ) + end + let!(:user_phenotype_2) do + create( + :user_phenotype, + phenotype: phenotype_1, + variation: 'no', + user: user_2 + ) + end + let!(:user_phenotype_3) do + create( + :user_phenotype, + phenotype: phenotype_2, + variation: '27', + user: user_1 + ) + end + + it 'returns a row per genotype' do + expect(parsed_result.to_a.size).to eq(4) + expect(parsed_result.to_a[1..-1]).to eq( + [ + [ + user_1.id.to_s, + "#{user_1.id}.23andme.#{genotype_1.id}", + '1990', + 'why not', + '-', + 'yes', + '27' + ], + [ + user_2.id.to_s, + "#{user_2.id}.23andme.#{genotype_2.id}", + '1970', + 'female', + '-', + 'no', + '-' + ], + [ + user_2.id.to_s, + "#{user_2.id}.23andme.#{genotype_3.id}", + '1970', + 'female', + '-', + 'no', + '-' + ] + ] + ) + end + end + + context 'when a phenotype characteristic contains a double quote' do + let!(:genotype) { create(:genotype, user: user) } + let!(:user) { create(:user) } + let!(:phenotype) { create(:phenotype, characteristic: 'prefers " over \'') } + let!(:user_phenotype) do + create(:user_phenotype, phenotype: phenotype, variation: 'yes', user: user) + end + + let(:result) do + CSV.parse( + service.call.to_a.join("\n"), + col_sep: ';', + headers: :first_row + ) + end + + it 'does not fail' do + expect(result.headers.last).to eq('prefers " over \'') + expect(result.to_a.last.last).to eq('yes') + end + end + + context 'when a phenotype characteristic clashes with another column name' do + before do + create(:phenotype, characteristic: 'user_yob') + end + + it 'fails' do + expect { service.call.to_a }.to raise_error(PG::DuplicateColumn) + end + end +end diff --git a/spec/services/data_zipper_service/zip_genotype_files_spec.rb b/spec/services/data_zipper_service/zip_genotype_files_spec.rb new file mode 100644 index 0000000..a25c1fa --- /dev/null +++ b/spec/services/data_zipper_service/zip_genotype_files_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +describe DataZipperService::ZipGenotypeFiles do + subject(:zip) do + zipfile = Zip::File.open(Tempfile.new, Zip::File::CREATE) + described_class.new(zipfile).call + zipfile.close + Zip::File.open(zipfile.name) + end + + let!(:user_1) { create(:user, yearofbirth: 1970, sex: 'why not') } + let!(:genotype_1) { create(:genotype, user: user_1) } + let!(:open_humans_profile) do + create(:open_humans_profile, user: user_1, open_humans_user_id: 'oh-user') + end + + let!(:user_2) { create(:user, yearofbirth: 1994, sex: 'no') } + let!(:genotype_2) { create(:genotype, user: user_2) } + + let!(:user_3) { create(:user) } + + it 'zips genotype files' do + expect(zip.glob('user*.txt').map(&:name)).to eq( + [ + "user#{user_1.id}_file#{genotype_1.id}_yearofbirth_1970_sex_why not.23andme.txt", + "user#{user_2.id}_file#{genotype_2.id}_yearofbirth_1994_sex_no.23andme.txt" + ] + ) + + expect(zip.read(zip.glob('user*.txt').first.name)) + .to eq("assorted genotype data\n") + end +end diff --git a/spec/services/data_zipper_service/zip_user_picture_phenotypes_spec.rb b/spec/services/data_zipper_service/zip_user_picture_phenotypes_spec.rb new file mode 100644 index 0000000..0e6f4cc --- /dev/null +++ b/spec/services/data_zipper_service/zip_user_picture_phenotypes_spec.rb @@ -0,0 +1,146 @@ +# frozen_string_literal: true + +RSpec.describe DataZipperService::ZipUserPicturePhenotypes do + subject(:zip) do + zipfile = Zip::File.open(Tempfile.new, Zip::File::CREATE) + described_class.new(zipfile, tmp_dir, time_str).call + zipfile.close + Zip::File.open(zipfile.name) + end + + let(:zipfile_write) { Zip::File.open(zipfile_path, Zip::File::CREATE) } + let(:tempfile) { Tempfile.new } + let(:zipfile_path) { tempfile.path } + let(:tmp_dir) do + Rails.root.join('tmp', 'test', 'data_zipper_service', 'zip_user_picture_phenotypes') + end + let(:time_str) { '123' } + + let!(:user_1) { create(:user, yearofbirth: 1970, sex: 'why not') } + let!(:genotype_1) { create(:genotype, user: user_1) } + let!(:open_humans_profile) do + create(:open_humans_profile, user: user_1, open_humans_user_id: 'oh-user') + end + + let!(:user_2) { create(:user, yearofbirth: 1994, sex: 'no') } + let!(:genotype_2) { create(:genotype, user: user_2) } + + let!(:user_3) { create(:user, yearofbirth: 1922, sex: 'male') } + + let!(:picture_phenotype_1) do + create(:picture_phenotype, characteristic: 'number of eyes') + end + let!(:picture_phenotype_2) do + create(:picture_phenotype, characteristic: 'length of tongue') + end + + let!(:user_picture_phenotype_1) do + create( + :user_picture_phenotype, + picture_phenotype: picture_phenotype_1, + user: user_1 + ) + end + let!(:user_picture_phenotype_2) do + create( + :user_picture_phenotype, + picture_phenotype: picture_phenotype_1, + user: user_2 + ) + end + let!(:user_picture_phenotype_3) do + create( + :user_picture_phenotype, + picture_phenotype: picture_phenotype_2, + user: user_1 + ) + end + + # There needs to be at least one Phenotype for the CROSSTAB query to work. + let!(:phenotype) { create(:phenotype) } + + before do + FileUtils.mkdir_p(tmp_dir) + end + + after do + FileUtils.rm_rf(tmp_dir) + end + + it 'adds a CSV with image data to the zip file' do + picture_phenotypes_csv = zip.glob('picture_phenotypes_*.csv').first + expect(CSV.parse(zip.read(picture_phenotypes_csv.name), col_sep: ';')).to eq( + [ + [ + 'user_id', + 'date_of_birth', + 'chrom_sex', + 'number of eyes', + 'length of tongue' + ], + [ + user_1.id.to_s, + '1970', + 'why not', + "#{user_picture_phenotype_1.id}.png", + "#{user_picture_phenotype_3.id}.png" + ], + [ + user_2.id.to_s, + '1994', + 'no', + "#{user_picture_phenotype_2.id}.png", + '-' + ], + # TODO: Should users without picture phenotypes show up? + [ + user_3.id.to_s, + '1922', + 'male', + '-', + '-' + ] + ] + ) + end + + it 'creates a ZIP file with phenotype images and adds it to the ZIP file' do + zip.extract( + zip.glob('picture_phenotypes_*_all_pics.zip').last.name, + tmp_dir.join('picture_phenotypes_all_pics.zip') + ) + + Zip::File.open(tmp_dir.join('picture_phenotypes_all_pics.zip')) do |zip| + expect(zip.glob('*').map(&:name).sort).to eq( + [ + user_picture_phenotype_1, + user_picture_phenotype_2, + user_picture_phenotype_3 + ].map(&:id).sort.map { |id| "#{id}.png" } + ) + end + end + + context 'when a user picture phenotype is missing an actual image' do + before do + user_picture_phenotype_1.phenotype_picture = nil + user_picture_phenotype_1.save! + end + + it 'ignores them' do + zip.extract( + zip.glob('picture_phenotypes_*_all_pics.zip').last.name, + tmp_dir.join('picture_phenotypes_all_pics.zip') + ) + + Zip::File.open(tmp_dir.join('picture_phenotypes_all_pics.zip')) do |zip| + expect(zip.glob('*').map(&:name).sort).to eq( + [ + user_picture_phenotype_2, + user_picture_phenotype_3 + ].map(&:id).sort.map { |id| "#{id}.png" } + ) + end + end + end +end diff --git a/spec/services/data_zipper_service_spec.rb b/spec/services/data_zipper_service_spec.rb new file mode 100644 index 0000000..69ba7f0 --- /dev/null +++ b/spec/services/data_zipper_service_spec.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true + +describe DataZipperService do + subject(:service) { described_class.new(output_dir: output_dir, logger: logger) } + + let(:output_dir) { Rails.root.join('tmp', 'test', 'zipfulldata') } + let(:symlink) { output_dir.join('opensnp_datadump.current.zip') } + let(:picture_zip) { Dir[output_dir.join('opensnp_picturedump.*.zip')].last } + let(:logger) { instance_double(Logger) } + + before do + FileUtils.mkdir_p(output_dir) + # Add dummy phenotype so the CROSSTAB queries don't trip. + create(:phenotype, characteristic: 'affinity for filling out online questionaires') + allow(logger).to receive(:info) + end + + after do + FileUtils.rm_rf(output_dir) + end + + it 'creates a new dump file and symlink' do + service.call + + expect(File.symlink?(symlink)).to be(true) + expect(File.exist?(File.readlink(symlink))) + end + + it 'adds a README' do + service.call + + Zip::File.open(symlink) do |zip| + readme = zip.read('readme.txt') + expect(readme).to eq(<<~README) + This archive was generated on #{service.time.ctime} UTC. \ + It contains 1 phenotypes, 0 genotypes and 0 picture phenotypes. + + Thanks for using openSNP! + README + end + end + + it 'adds a phenotype csv' do + service.call + + Zip::File.open(symlink) do |zip| + expect(zip.glob('phenotypes_*.csv')).to be_present + end + end + + it 'adds a picture phenotype zip and csv' do + service.call + + Zip::File.open(symlink) do |zip| + expect(zip.glob('picture_phenotypes_*.csv')).to be_present + expect(zip.glob('picture_phenotypes_*_all_pics.zip')).to be_present + end + end + + it 'adds genotype files to the ZIP' do + create(:genotype) + + service.call + + Zip::File.open(symlink) do |zip| + expect(zip.glob('user*.txt').count).to eq(1) + end + end + + context 'when deleting files' do + let(:unrelated_file_path) { output_dir.join('do_not_delete_me.zip') } + let(:old_dump_file_path) { output_dir.join('opensnp_datadump.197001010000.zip') } + + before do + [unrelated_file_path, old_dump_file_path].each do |path| + FileUtils.touch(path) + end + end + + it 'deletes old dump files' do + service.call + + expect(File.exist?(old_dump_file_path)).to be(false) + end + + it 'does not delete unrelated files' do + service.call + + expect(File.exist?(unrelated_file_path)).to be(true) + end + + after do + [unrelated_file_path, old_dump_file_path].each do |path| + FileUtils.rm(path) if File.exist?(path) + end + end + end + + describe '.public_path' do + it 'returns the public path of the zip file' do + expect(described_class.public_path) + .to eq('/data/zip/opensnp_datadump.current.zip') + end + end +end diff --git a/spec/workers/data_zipper_worker_spec.rb b/spec/workers/data_zipper_worker_spec.rb new file mode 100644 index 0000000..4f6e074 --- /dev/null +++ b/spec/workers/data_zipper_worker_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +RSpec.describe DataZipperWorker do + subject(:worker) { described_class.new } + + let(:data_zipper_service) { instance_double(DataZipperService) } + + describe '#perform' do + it 'calls DataZipperService' do + expect(DataZipperService) + .to receive(:new) + .with(logger: worker.logger) + .and_return(data_zipper_service) + expect(data_zipper_service).to receive(:call) + + worker.perform + end + end +end diff --git a/spec/workers/zipfulldata_spec.rb b/spec/workers/zipfulldata_spec.rb deleted file mode 100644 index 863084c..0000000 --- a/spec/workers/zipfulldata_spec.rb +++ /dev/null @@ -1,112 +0,0 @@ -# frozen_string_literal: true -describe Zipfulldata do - let(:user) { create(:user) } - let(:phenotype) { create(:phenotype, characteristic: "jump height") } - let!(:user_phenotype) do - create(:user_phenotype, phenotype_id: phenotype.id, variation: '1km', user: user) - end - let(:genotype) do - create(:genotype, user_id: user.id, - genotype: File.open("#{Rails.root}/test/data/23andMe_test.csv")) - end - let(:job) { Zipfulldata.new } - let(:csv_options) { { col_sep: ';' } } - let(:zipfile) { double('zipfile') } - - before do - allow(Sidekiq::Client).to receive(:enqueue).with(Preparsing, instance_of(Integer)) - tmp_dir = job.instance_variable_get(:@tmp_dir) + '_test_' + - Digest::SHA1.hexdigest("#{Time.now.to_i}#{rand}") - job.instance_variable_set(:@tmp_dir, tmp_dir) - FileUtils.touch job.zip_fs_path.to_s - Dir.mkdir(tmp_dir) - genotype - end - - after do - link = Rails.root.join("public/data/zip/opensnp_datadump.current.zip") - FileUtils.rm(link) if File.exist?(link) - FileUtils.rm(job.zip_fs_path) if File.exist?(job.zip_fs_path) - FileUtils.rm(job.zip_public_path) if File.exist?(job.zip_public_path) - end - - it "creates user CSVs" do - user2 = create(:user) - genotype2 = create(:genotype, user_id: user2.id) - expect(zipfile).to receive(:add). - with("phenotypes_#{job.time_str}.csv", - "#{job.tmp_dir}/dump#{job.time_str}.csv") - job.create_user_csv([genotype, genotype2], zipfile) - csv = CSV.read("#{job.tmp_dir}/dump#{job.time_str}.csv", job.csv_options) - exp_header = ['user_id', 'genotype_filename', 'date_of_birth', 'chrom_sex', - 'openhumans_name', phenotype.characteristic] - exp_row1 = [user.id.to_s, genotype.fs_filename, user.yearofbirth, user.sex, - '-', user.user_phenotypes.first.variation] - exp_row2 = [user2.id.to_s, genotype2.fs_filename, user2.yearofbirth, - user2.sex, '-', '-'] - expect(user.user_phenotypes.first.phenotype).to eq(phenotype) - expect(csv).to eq([exp_header, exp_row1, exp_row2]) - end - - it "creates picture phenotype CSVs" do - user2 = create(:user) - pp = create(:picture_phenotype) - upp = create(:user_picture_phenotype, picture_phenotype: pp, - user: user) - pic = double('picture') - expect(pic).to receive(:path).and_return("#{Rails.root}/foo/bar.png") - allow_any_instance_of(UserPicturePhenotype).to receive(:phenotype_picture). - and_return(pic) - expect(zipfile).to receive(:add). - with("picture_phenotypes_#{job.time_str}.csv", - "#{job.tmp_dir}/picture_dump#{job.time_str}.csv") - job.create_picture_phenotype_csv(zipfile) - csv = CSV.read("#{job.tmp_dir}/picture_dump#{job.time_str}.csv", csv_options) - expect(csv).to eq( - [["user_id", "date_of_birth", "chrom_sex", "Eye color"], - [user.id.to_s, user.yearofbirth, user.sex, "#{upp.id}.png"], - [user2.id.to_s, user2.yearofbirth, user2.sex, '-']] - ) - end - - it "creates a readme file" do - expect(Phenotype).to receive(:count).and_return(42) - expect(Genotype).to receive(:count).and_return(23) - expect(PicturePhenotype).to receive(:count).and_return(5) - expect(zipfile).to receive(:add). - with("readme.txt", "#{job.tmp_dir}/dump#{job.time_str}.txt") - job.create_readme(zipfile) - readme = File.read("#{job.tmp_dir}/dump#{job.time_str}.txt") - exp_text = <<-TXT -This archive was generated on #{job.time.ctime} UTC. It contains 42 phenotypes, 23 genotypes and 5 picture phenotypes. - -Thanks for using openSNP! - TXT - end - - it "zips genotype files" do - expect(zipfile).to receive(:add).with( - "user#{user.id}_file#{genotype.id}_yearofbirth_#{user.yearofbirth}" + - "_sex_#{user.sex}.#{genotype.filetype}.txt", - "#{Rails.root}/public/data/#{genotype.fs_filename}") - job.zip_genotype_files([genotype], zipfile) - end - - it "runs the job" do - upp = double('user_picture_phenotype') - expect(Dir).to receive(:exists?).with(job.tmp_dir).and_return(false) - expect(Dir).to receive(:mkdir).with(job.tmp_dir) - expect(Zip::File).to receive(:open).with(job.zip_fs_path, Zip::File::CREATE). - and_yield(zipfile) - expect(job).to receive(:create_user_csv).with([genotype], zipfile) - expect(job).to receive(:create_picture_phenotype_csv).with(zipfile).and_return([upp]) - expect(job).to receive(:create_picture_zip).with([upp], zipfile) - expect(job).to receive(:create_readme).with(zipfile) - expect(job).to receive(:zip_genotype_files).with([genotype], zipfile) - expect(FileUtils).to receive(:ln_sf).with( - Rails.root.join("public/data/zip/#{job.dump_file_name}.zip"), - Rails.root.join("public/data/zip/opensnp_datadump.current.zip")) - expect(FileUtils).to receive(:rm_rf).with(job.tmp_dir) - expect(job.run).to be(true) - end -end