Commit 852a5636 authored by PiTrem's avatar PiTrem
Browse files

BackEnd Ex/Import collection as json (react/sampl)

does not persist attachments (but Attachment.new available)

vanilla sql to export as json
 - reactions:
  - code_log

 - samples:
   - residues
   - elemental_compositions
   - reactions_starting_material_sample
   - reactions_solvent_sample
   - reactions_reactant_sample
   - reactions_product_sample
   - code_log
   - svg data (sample or molecule)

 - analyses:
   - attachments (no files)
parent d28d6553
......@@ -16,9 +16,8 @@ export default class ReactionSvgFetcher {
solvents
})
}).then(response => {
return response.json()
})
.catch(errorMessage => {
return response.status == 201 ? response.json() : {}
}).catch(errorMessage => {
console.log(errorMessage);
});
......
......@@ -68,6 +68,7 @@ class Reaction < ActiveRecord::Base
has_many :collections_reactions, dependent: :destroy
has_many :collections, through: :collections_reactions
accepts_nested_attributes_for :collections_reactions
has_many :reactions_starting_material_samples, dependent: :destroy
has_many :starting_materials, through: :reactions_starting_material_samples, source: :sample
......
module Export
end
module Export
class ExportJson
attr_accessor :collection_id
attr_reader :data
def initialize(**arg)
@collection_id = arg[:collection_id]
@data = { 'reactions' => {}, 'samples' => {}, 'analysis' => {} }
end
def export
query
prepare_data
end
def to_json
@data.to_json
end
def to_file(file_name)
file_name += '.json' if File.extname(file_name) != '.json'
File.write(file_name, to_json)
end
private
def query
@data['reactions'] = db_exec_query(reaction_sql)
@data['samples'] = db_exec_query(sample_sql)
@data['analyses'] = db_exec_query(analyses_sql)
@data
end
def prepare_data
reactions_data
samples_data
analyses_data
end
def analyses_data
h = {}
@data['analyses'].each do |e|
h[e['uuid']] = e['analyses'] && JSON.parse(e['analyses']) || []
end
@data['analyses'] = h
end
def samples_data
@data['samples'].each do |el|
[
'reaction_sample',
'residues_attributes',
'elemental_compositions_attributes'
].each do |column|
el[column] = el[column] && JSON.parse(el[column])
end
svg_file = if !el['sample_svg_file'].blank?
File.join('samples', el['sample_svg_file'])
elsif !el['molecule_svg_file'].blank?
File.join('molecules', el['molecule_svg_file'])
end
svg_path = svg_file && Rails.root.join(
'public', 'images', svg_file
)
svg = File.read(svg_path) if File.exist?(svg_path)
el['sample_svg_file'] = svg || nil
end
end
def reactions_data
@data['reactions'].each do |el|
%w(description temperature observation).each do |column|
el[column] = JSON.parse(YAML.load(el[column]).to_json) if el[column]
end
if (dp = el['dangerous_products']).is_a?(String)
el['dangerous_products'] = dp.gsub(/"|\{|\}/, '').split(',')
end
if (pu = el['purification']).is_a?(String)
el['purification'] = pu.gsub(/"|\{|\}/, '').split(',')
end
end
end
def db_connect
ActiveRecord::Base.establish_connection
end
def db_exec_query(sql)
db_connect.connection.exec_query(sql)
end
def reaction_sql(c_id = collection_id)
<<-SQL
select r."name", r.created_at, r.updated_at, r.description, r."role"
, r.timestamp_start, r.timestamp_stop, r.observation, r.purification
, r.dangerous_products, r.tlc_solvents, r.tlc_description, r.origin
, r.rf_value, r.temperature, r.status, r.solvent, r.short_label
--, r.created_by, r.reaction_svg_file, r.deleted_at
, cl.id as uuid
from reactions r
inner join collections_reactions cr on cr.reaction_id = r.id and cr.deleted_at isnull
inner join code_logs cl on cl."source" = 'reaction' and cl.source_id = r.id
where cr.collection_id = #{c_id};
SQL
end
def sample_sql(c_id = collection_id)
<<-SQL
select
-- , s.ancestry, s.user_id, s.created_by, s.molfile, s.molecule_id
-- ,s.xref,s.fingerprint_id, s.deleted_at
s.id, s."name", encode(s.molfile,'escape') as molfile
, s.target_amount_value, s.target_amount_unit
, s.real_amount_value, s.real_amount_unit
, s.molarity_value, s.molarity_unit
, s.created_at, s.updated_at, s.description
, s.purity, s.solvent, s.impurities, s.location, s.is_top_secret
, s.external_label, s.short_label
, s.imported_readout, s.sample_svg_file, s.identifier
, s.density, s.melting_point, s.boiling_point
, m.inchikey, m.molecule_svg_file
, cl.id as uuid
, cl_r.id as r_uuid
, array_to_json(array[rsm.id::boolean, rs.id::boolean,rr.id::boolean,rp.id::boolean]) as reaction_sample
, coalesce (rsm.reference, rs.reference, rr.reference, rp.reference) as r_reference
, coalesce(rsm.equivalent, rs.equivalent, rr.equivalent, rp.equivalent) as r_equivalent
, r.created_at as r_created_at
, (select array_to_json(array_agg(row_to_json(ecd)))
from (select ec.composition_type, ec.loading, ec."data" from elemental_compositions ec where s.id = ec.sample_id) ecd) as elemental_compositions_attributes
, (select array_to_json(array_agg(row_to_json(red)))
from (select re.custom_info,'residue_type', re.residue_type from residues re where s.id = re.sample_id) red) as residues_attributes
from samples s
inner join molecules m on s.molecule_id = m.id
inner join collections_samples cs on cs.sample_id = s.id and cs.deleted_at isnull
inner join code_logs cl on cl."source" = 'sample' and cl.source_id = s.id
left join reactions_starting_material_samples rsm on (rsm.sample_id = s.id and rsm.deleted_at isnull)
left join reactions_solvent_samples rs on (rs.sample_id = s.id and rs.deleted_at isnull)
left join reactions_reactant_samples rr on rr.sample_id = s.id and rr.deleted_at isnull
left join reactions_product_samples rp on rp.sample_id = s.id and rp.deleted_at isnull
left join reactions r on r.id = coalesce (rsm.reaction_id, rs.reaction_id, rr.reaction_id, rp.reaction_id)
left join code_logs cl_r on cl_r."source" = 'reaction' and cl_r.source_id = r.id
where cs.collection_id = #{c_id}
order by r_uuid asc;
SQL
end
def analyses_sql(c_id = collection_id)
<<-SQL
select cl.id as uuid
, (select array_to_json(array_agg(row_to_json(analysis)))
from (
select anac.id, anac.description, anac.extended_metadata, clg.id
, (select array_to_json(array_agg(row_to_json(attachment)))
from (
select att.filename, att.identifier, att.checksum
from attachments att
where att.container_id = anac.id) attachment ) as attachments
from containers cont
inner join container_hierarchies ch on cont.id = ch.ancestor_id and ch.generations = 3
inner join containers anac on anac.id = ch.descendant_id
left join code_logs clg on clg."source" = 'container' and clg.source_id = anac.id
where cont.containable_type = 'Sample'and cont.containable_id = s.id
) analysis
) as analyses
from samples s
inner join code_logs cl on cl."source" = 'sample' and cl.source_id = s.id
inner join collections_samples cs on cs.sample_id = s.id and cs.deleted_at isnull
where cs.collection_id = #{c_id};
SQL
end
end
end
module Import
end
\ No newline at end of file
end
# frozen_string_literal: true
class Import::ImportJson
attr_accessor :data, :force_uuid
attr_reader :user_id, :collection_id, :collection, :all_collection, :user,
:new_data, :log, :new_attachments
#Dir["public/images/reactions/*"].each{|f| if !(Reaction.find_by(reaction_svg_file: File.basename(f))) then File.delete(f) end}
# def dummy_data
# {
# 'reactions' => [
# {
# # 'id' => nil,
# 'name' => nil,
# 'created_at' => nil,
# 'updated_at' => nil,
# 'description' => nil,
# 'timestamp_start' => nil,
# 'timestamp_stop' => nil,
# 'observation' => nil,
# 'purification' => nil,
# 'dangerous_products' => nil,
# 'tlc_solvents' => nil,
# 'tlc_description' => nil,
# 'rf_value' => nil,
# 'temperature' => nil,
# 'status' => nil,
# # 'reaction_svg_file' => nil, # to process
# 'solvent' => nil,
# 'deleted_at' => nil,
# 'short_label' => nil,
# # 'created_by' => nil, # reprocessed
# 'role' => nil,
# 'origin' => nil,
# ##### CodeLog
# 'uuid' => nil # from reaction.code_log.id
# }
# ],
# 'samples' => [
# # 'id' => nil,
# # 'ancestry' => nil,
# # IDEA pass uuid of ancestors if present in acestry_uuids?
# # 'created_by' => nil,
# # IDEA reprocessed with user_id? use ORCID in created_by_orcid
# # 'user_id' => nil, # NB this column is not used
# 'name' => nil,
# 'target_amount_value' => nil,
# 'target_amount_unit' => nil,
# 'created_at' => nil,
# 'updated_at' => nil,
# 'description' => nil,
# 'molecule_id' => nil,
# 'molfile' => nil,
# 'purity' => nil,
# 'solvent' => nil,
# 'impurities' => nil,
# 'location' => nil,
# 'is_top_secret' => nil,
# 'external_label' => nil,
# 'short_label' => nil,
# 'real_amount_value' => nil,
# 'real_amount_unit' => nil,
# 'imported_readout' => nil,
# 'deleted_at' => nil,
# 'sample_svg_file' => nil,
# 'identifier' => nil,
# 'density' => nil,
# 'melting_point' => nil,
# 'boiling_point' => nil,
# 'fingerprint_id' => nil,
# 'xref' => nil,
# 'molarity_value' => nil,
# 'molarity_unit' => nil,
# ##### CodeLog
# 'uuid' => nil, # from sample.code_log.id
# ##### ReactionsStartingMaterialSample, ReactionsSolventSample,
# ##### ReactionsReactantSample, ReactionsProductSample
# 'reaction_sample' => [nil,nil,nil,nil]
# 'r_uuid' => nil,
# 'r_reference' => nil,
# 'r_equivalent' => nil,
# ]
# }
# end
def initialize(**arg)
d = arg[:data]
@data = d.is_a?(String) && JSON.parse(d, allow_nan: true) || d
@user_id = arg[:user_id]
@collection_id = arg[:collection_id]
@new_data = { }
@new_attachments = { }
@log = { 'reactions' => {}, 'samples' => {} }
@force_uuid = arg[:force_uuid]
find_collection
find_collection_all
end
def import
map_data_uuids(@log)
unless collections?
@log['collections'] = 'could not find collection or user'
return @log
end
#begin
import_reactions
import_samples
import_attachments
#rescue
#end
File.write("log_#{Time.now.to_i}.json", JSON.pretty_generate(@log))
end
def collection_id= id
@collection_id = id
find_collection
id
end
def user_id= id
@user_id = id
find_collection_all
id
end
private
def import_reactions
return unless collections?
attribute_names = filter_attributes(Reaction)
reactions.each do |el|
attribs = el.slice(*attribute_names).merge(
created_by: user_id,
collections_reactions_attributes: [
{collection_id: collection.id},
{collection_id: all_collection.id}
]
)
create_element(el['uuid'], attribs, Reaction, 'reaction')
end
end
def import_samples
return unless collections?
attribute_names = filter_attributes(Sample)
samples.each do |el|
attribs = el.slice(*attribute_names).merge(
created_by: user_id,
collections_samples_attributes: [
{ collection_id: collection.id },
{ collection_id: all_collection.id }
]
)
new_el = create_element(el['uuid'], attribs, Sample, 'sample')
next unless new_el
klass = if el['reaction_sample'][0]
ReactionsStartingMaterialSample
elsif el['reaction_sample'][2]
ReactionsReactantSample
elsif el['reaction_sample'][1]
ReactionsSolventSample
elsif el['reaction_sample'][3]
ReactionsProductSample
end
add_to_reaction(klass, el, new_el) if klass
end
end
def map_data_uuids(h)
reactions.map do |r|
r['uuid'].is_a?(String) && h['reactions'][r['uuid']] = {}
end
samples.map do |r|
r['uuid'].is_a?(String) && h['samples'][r['uuid']] = {}
end
end
def create_element(uuid, element, klass, source)
#ActiveRecord::Base.transaction do
if force_uuid && CodeLog.find_by(id: uuid)
@log[source + 's'][uuid]['uuid'] = 'already attributed'
return
end
new_el = klass.new(element)
if new_el.save!
if force_uuid
new_el.code_log.really_destroy!
CodeLog.create(id: uuid, source: source, source_id: new_el.id)
end
@new_data[uuid] = {'id' => new_el.id, 'type' => source}
@log[source + 's'][uuid]['created_at'] = new_el.created_at
if !(new_el.container)
c = Container.create_root_container(
containable_id: new_el.id,
containable_type: klass.name,
)
end
create_analyses(uuid, new_el)
new_el
else
@log[source + 's'][uuid]['created_at'] = 'not created'
nil
end
#end
end
def create_analyses(uuid, el)
analyses[uuid]&.each do |a|
new_a = el.container.children.where(container_type: 'analyses')
.first.children.create(
container_type: 'analysis',
extended_metadata: a['extended_metadata'],
description: a['description']
)
a['attachments']&.each do |att|
@new_attachments[att['identifier']] = Attachment.new(
filename: att['filename'],
identifier: att['identifier'],
checksum: att['checksum'],
container_id: new_a.id
)
end
end
end
def filter_attributes(klass)
attributes = klass.attribute_names - %w(id user_id created_by deleted_at )
case klass
when Sample
attributes -= [
'ancestry', 'molecule_id', 'xref', 'fingerprint_id',
'is_top_secret', 'molecule_svg_file'
]
attributes += ['residues_attributes', 'elemental_compositions_attributes']
when Reaction
attributes -= ['reaction_svg_file']
end
attributes
end
def add_to_reaction(klass, el, new_el)
el_uuid = el['uuid']
r_uuid = el['r_uuid']
ref = (el['r_reference'] == 't') || el['r_reference'] == 'f'
eq = el['r_equivalent']
@log['samples'][el_uuid][klass.name] = klass.create!(
sample_id: new_el.id, reaction_id: new_data[r_uuid]['id'],
reference: ref, equivalent: eq
) && '201' || '500'
end
def reactions
data && data['reactions'] || []
end
def samples
data && data['samples'] || []
end
def analyses
data && data['analyses'] || []
end
def collections?
@collection && @all_collection
end
def find_collection(c_id = collection_id)
@collection = Collection.find_by(id: c_id) if c_id.is_a?(Integer)
end
def find_collection_all(id = user_id)
return unless id.is_a?(Integer)
@all_collection = Collection.get_all_collection_for_user(id)
end
end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment