diff --git a/screening/resource/test-data/FeatureVectorsDropboxTest/features.csv b/screening/resource/test-data/FeatureVectorsDropboxTest/features.csv index c82d36b5b6907ad256e6f9a8364f01c0dcc9ac54..fec4f30d1a29a57ad53474ee79c66ec7873866b2 100644 --- a/screening/resource/test-data/FeatureVectorsDropboxTest/features.csv +++ b/screening/resource/test-data/FeatureVectorsDropboxTest/features.csv @@ -1,97 +1,97 @@ -barcode,Well,row number,column number,TPU,STATE -PLATE-1,A1,1,1,0.0109905507275,UNSTABLE -PLATE-1,A2,1,2,-0.0182003436984,UNSTABLE -PLATE-1,A3,1,3,-0.00805361743168,STABLE -PLATE-1,A4,1,4,0.0810000328417,STABLE -PLATE-1,A5,1,5,0.0259230435927,STABLE -PLATE-1,A6,1,6,-0.036430571554,UNSTABLE -PLATE-1,A7,1,7,-0.0101872401882,UNSTABLE -PLATE-1,A8,1,8,-0.00727317718048,STABLE -PLATE-1,A9,1,9,0.0315700979161,STABLE -PLATE-1,A10,1,10,0.168559091956,STABLE -PLATE-1,A11,1,11,-0.0250794227724,STABLE -PLATE-1,A12,1,12,0.257636061574,STABLE -PLATE-1,B1,2,1,0.100434155899,STABLE -PLATE-1,B2,2,2,0.0976115450765,UNSTABLE -PLATE-1,B3,2,3,0.0864925097496,UNSTABLE -PLATE-1,B4,2,4,0.0878168382557,STABLE -PLATE-1,B5,2,5,0.00728303315339,STABLE -PLATE-1,B6,2,6,0.00135844915617,UNSTABLE -PLATE-1,B7,2,7,0.071667990849,UNSTABLE -PLATE-1,B8,2,8,0.134576738033,STABLE -PLATE-1,B9,2,9,0.062517688301,STABLE -PLATE-1,B10,2,10,-0.0559872246124,STABLE -PLATE-1,B11,2,11,-0.0619564845848,STABLE -PLATE-1,B12,2,12,0.0324420596004,UNSTABLE -PLATE-1,C1,3,1,0.206954055141,UNSTABLE -PLATE-1,C2,3,2,0.19680434536,UNSTABLE -PLATE-1,C3,3,3,0.229279401419,UNSTABLE -PLATE-1,C4,3,4,0.193351284437,STABLE -PLATE-1,C5,3,5,0.129062893555,STABLE -PLATE-1,C6,3,6,0.126673623384,STABLE -PLATE-1,C7,3,7,0.229037975734,STABLE -PLATE-1,C8,3,8,0.223431359979,STABLE -PLATE-1,C9,3,9,0.190028172309,STABLE -PLATE-1,C10,3,10,-0.0674441033456,UNSTABLE -PLATE-1,C11,3,11,0.0339637772352,STABLE -PLATE-1,C12,3,12,0.164178194792,STABLE -PLATE-1,D1,4,1,0.297974218656,UNSTABLE -PLATE-1,D2,4,2,0.298059135512,STABLE -PLATE-1,D3,4,3,0.350772745466,UNSTABLE -PLATE-1,D4,4,4,0.313919901769,UNSTABLE -PLATE-1,D5,4,5,0.252290578613,STABLE -PLATE-1,D6,4,6,0.324830425263,UNSTABLE -PLATE-1,D7,4,7,0.162928227992,STABLE -PLATE-1,D8,4,8,0.265496427715,UNSTABLE -PLATE-1,D9,4,9,0.123242462625,STABLE -PLATE-1,D10,4,10,0.0156365936527,STABLE -PLATE-1,D11,4,11,0.318001502397,STABLE -PLATE-1,D12,4,12,0.20854731993,STABLE -PLATE-1,E1,5,1,0.393536251276,UNSTABLE -PLATE-1,E2,5,2,0.399605077357,STABLE -PLATE-1,E3,5,3,0.433901537831,STABLE -PLATE-1,E4,5,4,0.378871120619,UNSTABLE -PLATE-1,E5,5,5,0.453098222167,STABLE -PLATE-1,E6,5,6,0.308155666544,UNSTABLE -PLATE-1,E7,5,7,0.45538138854,STABLE -PLATE-1,E8,5,8,0.372161727461,STABLE -PLATE-1,E9,5,9,0.308752403413,STABLE -PLATE-1,E10,5,10,0.357322858215,UNSTABLE -PLATE-1,E11,5,11,0.408261827863,UNSTABLE -PLATE-1,E12,5,12,0.276512650311,UNSTABLE -PLATE-1,F1,6,1,0.518565455665,UNSTABLE -PLATE-1,F2,6,2,0.501353504253,UNSTABLE -PLATE-1,F3,6,3,0.486441514218,UNSTABLE -PLATE-1,F4,6,4,0.530701442681,STABLE -PLATE-1,F5,6,5,0.526764248567,UNSTABLE -PLATE-1,F6,6,6,0.535393254659,STABLE -PLATE-1,F7,6,7,0.485971393901,STABLE -PLATE-1,F8,6,8,0.446866206382,STABLE -PLATE-1,F9,6,9,0.500105016099,STABLE -PLATE-1,F10,6,10,0.572554837409,UNSTABLE -PLATE-1,F11,6,11,0.421581223622,UNSTABLE -PLATE-1,F12,6,12,0.566179719687,STABLE -PLATE-1,G1,7,1,0.597014347164,STABLE -PLATE-1,G2,7,2,0.595574322803,STABLE -PLATE-1,G3,7,3,0.573275879833,UNSTABLE -PLATE-1,G4,7,4,0.565598774935,UNSTABLE -PLATE-1,G5,7,5,0.580255468506,UNSTABLE -PLATE-1,G6,7,6,0.731126618477,UNSTABLE -PLATE-1,G7,7,7,0.586449329876,STABLE -PLATE-1,G8,7,8,0.504383391301,UNSTABLE -PLATE-1,G9,7,9,0.57029228861,UNSTABLE -PLATE-1,G10,7,10,0.571055758388,UNSTABLE -PLATE-1,G11,7,11,0.729508274912,STABLE -PLATE-1,G12,7,12,0.651282199669,UNSTABLE -PLATE-1,H1,8,1,0.708336042851,UNSTABLE -PLATE-1,H2,8,2,0.693510468853,STABLE -PLATE-1,H3,8,3,0.680500191339,UNSTABLE -PLATE-1,H4,8,4,0.682631399189,UNSTABLE -PLATE-1,H5,8,5,0.771686970996,UNSTABLE -PLATE-1,H6,8,6,0.592031721228,STABLE -PLATE-1,H7,8,7,0.683612608169,STABLE -PLATE-1,H8,8,8,0.632227578807,UNSTABLE -PLATE-1,H9,8,9,0.90031946922,UNSTABLE -PLATE-1,H10,8,10,0.750539227015,STABLE -PLATE-1,H11,8,11,0.826335733676,UNSTABLE -PLATE-1,H12,8,12,0.467946755513,UNSTABLE +barcode,Well,row number,column number,TPU,STATE, Z_VERY_LONG_FEATURE_LONGER_THAN_80_CHARS_123456789012345678901234567890123456789012345678901234567890 +PLATE-1,A1,1,1,0.0109905507275,UNSTABLE, 0 +PLATE-1,A2,1,2,-0.0182003436984,UNSTABLE, 0 +PLATE-1,A3,1,3,-0.00805361743168,STABLE, 0 +PLATE-1,A4,1,4,0.0810000328417,STABLE, 0 +PLATE-1,A5,1,5,0.0259230435927,STABLE, 0 +PLATE-1,A6,1,6,-0.036430571554,UNSTABLE, 0 +PLATE-1,A7,1,7,-0.0101872401882,UNSTABLE, 0 +PLATE-1,A8,1,8,-0.00727317718048,STABLE, 0 +PLATE-1,A9,1,9,0.0315700979161,STABLE, 0 +PLATE-1,A10,1,10,0.168559091956,STABLE, 0 +PLATE-1,A11,1,11,-0.0250794227724,STABLE, 0 +PLATE-1,A12,1,12,0.257636061574,STABLE, 0 +PLATE-1,B1,2,1,0.100434155899,STABLE, 0 +PLATE-1,B2,2,2,0.0976115450765,UNSTABLE, 0 +PLATE-1,B3,2,3,0.0864925097496,UNSTABLE, 0 +PLATE-1,B4,2,4,0.0878168382557,STABLE, 0 +PLATE-1,B5,2,5,0.00728303315339,STABLE, 0 +PLATE-1,B6,2,6,0.00135844915617,UNSTABLE, 0 +PLATE-1,B7,2,7,0.071667990849,UNSTABLE, 0 +PLATE-1,B8,2,8,0.134576738033,STABLE, 0 +PLATE-1,B9,2,9,0.062517688301,STABLE, 0 +PLATE-1,B10,2,10,-0.0559872246124,STABLE, 0 +PLATE-1,B11,2,11,-0.0619564845848,STABLE, 0 +PLATE-1,B12,2,12,0.0324420596004,UNSTABLE, 0 +PLATE-1,C1,3,1,0.206954055141,UNSTABLE, 0 +PLATE-1,C2,3,2,0.19680434536,UNSTABLE, 0 +PLATE-1,C3,3,3,0.229279401419,UNSTABLE, 0 +PLATE-1,C4,3,4,0.193351284437,STABLE, 0 +PLATE-1,C5,3,5,0.129062893555,STABLE, 0 +PLATE-1,C6,3,6,0.126673623384,STABLE, 0 +PLATE-1,C7,3,7,0.229037975734,STABLE, 0 +PLATE-1,C8,3,8,0.223431359979,STABLE, 0 +PLATE-1,C9,3,9,0.190028172309,STABLE, 0 +PLATE-1,C10,3,10,-0.0674441033456,UNSTABLE, 0 +PLATE-1,C11,3,11,0.0339637772352,STABLE, 0 +PLATE-1,C12,3,12,0.164178194792,STABLE, 0 +PLATE-1,D1,4,1,0.297974218656,UNSTABLE, 0 +PLATE-1,D2,4,2,0.298059135512,STABLE, 0 +PLATE-1,D3,4,3,0.350772745466,UNSTABLE, 0 +PLATE-1,D4,4,4,0.313919901769,UNSTABLE, 0 +PLATE-1,D5,4,5,0.252290578613,STABLE, 0 +PLATE-1,D6,4,6,0.324830425263,UNSTABLE, 0 +PLATE-1,D7,4,7,0.162928227992,STABLE, 0 +PLATE-1,D8,4,8,0.265496427715,UNSTABLE, 0 +PLATE-1,D9,4,9,0.123242462625,STABLE, 0 +PLATE-1,D10,4,10,0.0156365936527,STABLE, 0 +PLATE-1,D11,4,11,0.318001502397,STABLE, 0 +PLATE-1,D12,4,12,0.20854731993,STABLE, 0 +PLATE-1,E1,5,1,0.393536251276,UNSTABLE, 0 +PLATE-1,E2,5,2,0.399605077357,STABLE, 0 +PLATE-1,E3,5,3,0.433901537831,STABLE, 0 +PLATE-1,E4,5,4,0.378871120619,UNSTABLE, 0 +PLATE-1,E5,5,5,0.453098222167,STABLE, 0 +PLATE-1,E6,5,6,0.308155666544,UNSTABLE, 0 +PLATE-1,E7,5,7,0.45538138854,STABLE, 0 +PLATE-1,E8,5,8,0.372161727461,STABLE, 0 +PLATE-1,E9,5,9,0.308752403413,STABLE, 0 +PLATE-1,E10,5,10,0.357322858215,UNSTABLE, 0 +PLATE-1,E11,5,11,0.408261827863,UNSTABLE, 0 +PLATE-1,E12,5,12,0.276512650311,UNSTABLE, 0 +PLATE-1,F1,6,1,0.518565455665,UNSTABLE, 0 +PLATE-1,F2,6,2,0.501353504253,UNSTABLE, 0 +PLATE-1,F3,6,3,0.486441514218,UNSTABLE, 0 +PLATE-1,F4,6,4,0.530701442681,STABLE, 0 +PLATE-1,F5,6,5,0.526764248567,UNSTABLE, 0 +PLATE-1,F6,6,6,0.535393254659,STABLE, 0 +PLATE-1,F7,6,7,0.485971393901,STABLE, 0 +PLATE-1,F8,6,8,0.446866206382,STABLE, 0 +PLATE-1,F9,6,9,0.500105016099,STABLE, 0 +PLATE-1,F10,6,10,0.572554837409,UNSTABLE, 0 +PLATE-1,F11,6,11,0.421581223622,UNSTABLE, 0 +PLATE-1,F12,6,12,0.566179719687,STABLE, 0 +PLATE-1,G1,7,1,0.597014347164,STABLE, 0 +PLATE-1,G2,7,2,0.595574322803,STABLE, 0 +PLATE-1,G3,7,3,0.573275879833,UNSTABLE, 0 +PLATE-1,G4,7,4,0.565598774935,UNSTABLE, 0 +PLATE-1,G5,7,5,0.580255468506,UNSTABLE, 0 +PLATE-1,G6,7,6,0.731126618477,UNSTABLE, 0 +PLATE-1,G7,7,7,0.586449329876,STABLE, 0 +PLATE-1,G8,7,8,0.504383391301,UNSTABLE, 0 +PLATE-1,G9,7,9,0.57029228861,UNSTABLE, 0 +PLATE-1,G10,7,10,0.571055758388,UNSTABLE, 0 +PLATE-1,G11,7,11,0.729508274912,STABLE, 0 +PLATE-1,G12,7,12,0.651282199669,UNSTABLE, 0 +PLATE-1,H1,8,1,0.708336042851,UNSTABLE, 0 +PLATE-1,H2,8,2,0.693510468853,STABLE, 0 +PLATE-1,H3,8,3,0.680500191339,UNSTABLE, 0 +PLATE-1,H4,8,4,0.682631399189,UNSTABLE, 0 +PLATE-1,H5,8,5,0.771686970996,UNSTABLE, 0 +PLATE-1,H6,8,6,0.592031721228,STABLE, 0 +PLATE-1,H7,8,7,0.683612608169,STABLE, 0 +PLATE-1,H8,8,8,0.632227578807,UNSTABLE, 0 +PLATE-1,H9,8,9,0.90031946922,UNSTABLE, 0 +PLATE-1,H10,8,10,0.750539227015,STABLE, 0 +PLATE-1,H11,8,11,0.826335733676,UNSTABLE, 0 +PLATE-1,H12,8,12,0.467946755513,UNSTABLE, 0 diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java index 949036400c582cfd69d71a8d7a880d315ffe183c..8dfdfb31dbe2a0aecef290dc2096fb61f4ac0a9b 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/ImagingDatabaseVersionHolder.java @@ -28,6 +28,6 @@ public class ImagingDatabaseVersionHolder implements IDatabaseVersionHolder @Override public String getDatabaseVersion() { - return "022"; // changed in S129 + return "023"; // changed in S153 } } diff --git a/screening/source/sql/imaging/postgresql/023/schema-023.sql b/screening/source/sql/imaging/postgresql/023/schema-023.sql new file mode 100644 index 0000000000000000000000000000000000000000..f08d694fcc0d1d58071c9206904311a3cf8a6109 --- /dev/null +++ b/screening/source/sql/imaging/postgresql/023/schema-023.sql @@ -0,0 +1,425 @@ + +/* ---------------------------------------------------------------------- */ +/* Domains */ +/* ---------------------------------------------------------------------- */ + +CREATE DOMAIN TECH_ID AS BIGINT; + +CREATE DOMAIN CODE AS VARCHAR(40); + +CREATE DOMAIN LONG_NAME AS TEXT; + +CREATE DOMAIN DESCRIPTION AS VARCHAR(200); + +CREATE DOMAIN FILE_PATH as VARCHAR(1000); + +CREATE DOMAIN COLOR_COMPONENT AS VARCHAR(40) CHECK (VALUE IN ('RED', 'GREEN', 'BLUE')); + +CREATE DOMAIN CHANNEL_COLOR AS VARCHAR(20) CHECK (VALUE IN ('BLUE', 'GREEN', 'RED', 'RED_GREEN', 'RED_BLUE', 'GREEN_BLUE')); + +CREATE DOMAIN BOOLEAN_CHAR AS BOOLEAN DEFAULT FALSE; + +/* ---------------------------------------------------------------------- */ +/* Tables */ +/* ---------------------------------------------------------------------- */ + +CREATE TABLE EXPERIMENTS ( + ID BIGSERIAL NOT NULL, + PERM_ID CODE NOT NULL, + IMAGE_TRANSFORMER_FACTORY BYTEA, + + PRIMARY KEY (ID), + UNIQUE (PERM_ID) +); + +CREATE TABLE CONTAINERS ( + ID BIGSERIAL NOT NULL, + PERM_ID CODE NOT NULL, + + SPOTS_WIDTH INTEGER, + SPOTS_HEIGHT INTEGER, + + EXPE_ID TECH_ID NOT NULL, + + PRIMARY KEY (ID), + UNIQUE (PERM_ID), + CONSTRAINT FK_SAMPLE_1 FOREIGN KEY (EXPE_ID) REFERENCES EXPERIMENTS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX CONTAINERS_EXPE_IDX ON CONTAINERS(EXPE_ID); + +CREATE TABLE SPOTS ( + ID BIGSERIAL NOT NULL, + + -- position in the container, one-based + X INTEGER, + Y INTEGER, + CONT_ID TECH_ID NOT NULL, + + PRIMARY KEY (ID), + CONSTRAINT FK_SPOT_1 FOREIGN KEY (CONT_ID) REFERENCES CONTAINERS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX SPOTS_CONT_IDX ON SPOTS(CONT_ID); +-- allows to select one spot of the container quicker +CREATE INDEX SPOTS_COORDS_IDX ON SPOTS(CONT_ID, X, Y); + +CREATE TABLE ANALYSIS_DATA_SETS ( + ID BIGSERIAL NOT NULL, + PERM_ID CODE NOT NULL, + + CONT_ID TECH_ID, + + PRIMARY KEY (ID), + UNIQUE (PERM_ID), + CONSTRAINT FK_ANALYSIS_DATA_SET_1 FOREIGN KEY (CONT_ID) REFERENCES CONTAINERS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX ANALYSIS_DATA_SETS_CONT_IDX ON ANALYSIS_DATA_SETS(CONT_ID); + + +CREATE TABLE IMAGE_DATA_SETS ( + ID BIGSERIAL NOT NULL, + PERM_ID CODE NOT NULL, + + ---- image dataset specific fields (should be refactored) + FIELDS_WIDTH INTEGER, + FIELDS_HEIGHT INTEGER, + -- transformation for merged channels on the dataset level, overrides experiment level transformation + IMAGE_TRANSFORMER_FACTORY BYTEA, + -- a redundant information if there are timepoint or depth stack data for any spots in this dataset + IS_MULTIDIMENSIONAL BOOLEAN_CHAR NOT NULL, + + -- Which image library should be used to read the image? + -- If not specified, some heuristics are used, but it is slower and does not try with all the available libraries. + IMAGE_LIBRARY_NAME LONG_NAME, + -- Which reader in the library should be used? Valid only if the library LONG_NAME is specified. + -- Should be specified when library LONG_NAME is specified. + IMAGE_LIBRARY_READER_NAME LONG_NAME, + ---- END image dataset specific fields + + CONT_ID TECH_ID, + + PRIMARY KEY (ID), + UNIQUE (PERM_ID), + CONSTRAINT FK_IMAGE_DATA_SET_1 FOREIGN KEY (CONT_ID) REFERENCES CONTAINERS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX IMAGE_DATA_SETS_CONT_IDX ON IMAGE_DATA_SETS(CONT_ID); + +CREATE TABLE CHANNELS ( + ID BIGSERIAL NOT NULL, + + CODE LONG_NAME NOT NULL, + LABEL LONG_NAME NOT NULL, + DESCRIPTION DESCRIPTION, + WAVELENGTH INTEGER, + + -- RGB color components specify the color in which channel should be displayed + RED_CC INTEGER NOT NULL, + GREEN_CC INTEGER NOT NULL, + BLUE_CC INTEGER NOT NULL, + + DS_ID TECH_ID, + EXP_ID TECH_ID, + + PRIMARY KEY (ID), + CONSTRAINT FK_CHANNELS_1 FOREIGN KEY (DS_ID) REFERENCES IMAGE_DATA_SETS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_CHANNELS_2 FOREIGN KEY (EXP_ID) REFERENCES EXPERIMENTS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT CHANNELS _DS_EXP_ARC_CK CHECK ((DS_ID IS NOT NULL AND EXP_ID IS NULL) OR (DS_ID IS NULL AND EXP_ID IS NOT NULL)), + + CONSTRAINT CHANNELS_UK_1 UNIQUE(CODE, DS_ID), + CONSTRAINT CHANNELS_UK_2 UNIQUE(CODE, EXP_ID) +); + +CREATE INDEX CHANNELS_DS_IDX ON CHANNELS(DS_ID); + +CREATE TABLE IMAGE_TRANSFORMATIONS ( + ID BIGSERIAL NOT NULL, + + CODE LONG_NAME NOT NULL, + LABEL LONG_NAME NOT NULL, + DESCRIPTION character varying(1000), + IMAGE_TRANSFORMER_FACTORY BYTEA NOT NULL, + + -- For now there can be only one transformation for each channel which is editable by Image Viewer, + -- but when GUI will support more then this column will become really useful. + IS_EDITABLE BOOLEAN_CHAR NOT NULL, + + -- The default choice to present the image. + -- If not present a 'hard-coded' default transformation will become available. + IS_DEFAULT BOOLEAN_CHAR NOT NULL DEFAULT 'F', + + CHANNEL_ID TECH_ID NOT NULL, + + PRIMARY KEY (ID), + CONSTRAINT FK_IMAGE_TRANSFORMATIONS_CHANNEL FOREIGN KEY (CHANNEL_ID) REFERENCES CHANNELS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + + CONSTRAINT IMAGE_TRANSFORMATIONS_UK_1 UNIQUE(CODE, CHANNEL_ID) +); + +CREATE INDEX IMAGE_TRANSFORMATIONS_CHANNELS_IDX ON IMAGE_TRANSFORMATIONS(CHANNEL_ID); + +CREATE TABLE IMAGE_ZOOM_LEVELS ( + ID BIGSERIAL NOT NULL, + + IS_ORIGINAL BOOLEAN_CHAR NOT NULL, + CONTAINER_DATASET_ID TECH_ID NOT NULL, + + -- Perm id of the 'physical' dataset which contains all images with this zoom. + -- Physical datasets are not stored in "image_data_sets" table, but we need the reference to them + -- when we delete or archive one zoom level. + PHYSICAL_DATASET_PERM_ID TEXT NOT NULL, + + PATH FILE_PATH, + WIDTH INTEGER, + HEIGHT INTEGER, + COLOR_DEPTH INTEGER, + FILE_TYPE VARCHAR(20), + + PRIMARY KEY (ID), + CONSTRAINT FK_IMAGE_ZOOM_LEVELS_1 FOREIGN KEY (CONTAINER_DATASET_ID) REFERENCES IMAGE_DATA_SETS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX IMAGE_ZOOM_LEVELS_PHYS_DS_IDX ON IMAGE_ZOOM_LEVELS (PHYSICAL_DATASET_PERM_ID); +CREATE INDEX IMAGE_ZOOM_LEVELS_CONT_FK_IDX ON IMAGE_ZOOM_LEVELS (CONTAINER_DATASET_ID); + +CREATE TABLE IMAGE_ZOOM_LEVEL_TRANSFORMATIONS ( + ID BIGSERIAL NOT NULL, + + ZOOM_LEVEL_ID TECH_ID NOT NULL, + CHANNEL_ID TECH_ID NOT NULL, + IMAGE_TRANSFORMATION_ID TECH_ID NOT NULL, + + PRIMARY KEY(ID), + CONSTRAINT FK_IMAGE_ZOOM_LEVEL_TRANSFORMATIONS_1 FOREIGN KEY (ZOOM_LEVEL_ID) REFERENCES IMAGE_ZOOM_LEVELS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_IMAGE_ZOOM_LEVEL_TRANSFORMATIONS_2 FOREIGN KEY (CHANNEL_ID) REFERENCES CHANNELS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX IMAGE_ZOOM_LEVEL_TRANSFORMATIONS_ZLID_IDX ON IMAGE_ZOOM_LEVEL_TRANSFORMATIONS(ZOOM_LEVEL_ID); + +CREATE TABLE CHANNEL_STACKS ( + ID BIGSERIAL NOT NULL, + + -- x and y are kind of a two dimensional sequence number, some use case may only use x and leave y alone + X INTEGER, + Y INTEGER, + -- We use the fixed dimension meters here. + Z_in_M REAL, + -- We use the fixed dimension seconds here. + T_in_SEC REAL, + SERIES_NUMBER INTEGER, + + -- For all channel stacks of a well (HCS) or image dataset (microscopy) there should be exactly + -- one record with is_representative = true + is_representative BOOLEAN_CHAR NOT NULL DEFAULT 'F', + + DS_ID TECH_ID NOT NULL, + SPOT_ID TECH_ID, + + PRIMARY KEY (ID), + CONSTRAINT FK_CHANNEL_STACKS_1 FOREIGN KEY (SPOT_ID) REFERENCES SPOTS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_CHANNEL_STACKS_2 FOREIGN KEY (DS_ID) REFERENCES IMAGE_DATA_SETS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX CHANNEL_STACKS_DS_IDX ON CHANNEL_STACKS(DS_ID); +CREATE INDEX CHANNEL_STACKS_SPOT_IDX ON CHANNEL_STACKS(SPOT_ID); +CREATE INDEX CHANNEL_STACKS_DIM_IDX ON CHANNEL_STACKS(X, Y, Z_in_M, T_in_SEC); + +CREATE TABLE IMAGES ( + ID BIGSERIAL NOT NULL, + + PATH FILE_PATH NOT NULL, + IMAGE_ID CODE, + COLOR COLOR_COMPONENT, + + PRIMARY KEY (ID) +); + +CREATE TABLE ACQUIRED_IMAGES ( + ID BIGSERIAL NOT NULL, + + IMG_ID TECH_ID, + THUMBNAIL_ID TECH_ID, + IMAGE_TRANSFORMER_FACTORY BYTEA, + + CHANNEL_STACK_ID TECH_ID NOT NULL, + CHANNEL_ID TECH_ID NOT NULL, + + PRIMARY KEY (ID), + CONSTRAINT FK_IMAGES_1 FOREIGN KEY (CHANNEL_STACK_ID) REFERENCES CHANNEL_STACKS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_IMAGES_2 FOREIGN KEY (CHANNEL_ID) REFERENCES CHANNELS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FK_IMAGES_3 FOREIGN KEY (IMG_ID) REFERENCES IMAGES (ID) ON DELETE SET NULL ON UPDATE CASCADE, + CONSTRAINT FK_IMAGES_4 FOREIGN KEY (THUMBNAIL_ID) REFERENCES IMAGES (ID) ON DELETE SET NULL ON UPDATE CASCADE +); + +CREATE INDEX IMAGES_CHANNEL_STACK_IDX ON ACQUIRED_IMAGES(CHANNEL_STACK_ID); +CREATE INDEX IMAGES_CHANNEL_IDX ON ACQUIRED_IMAGES(CHANNEL_ID); +CREATE INDEX IMAGES_IMG_IDX ON ACQUIRED_IMAGES(IMG_ID); +CREATE INDEX IMAGES_THUMBNAIL_IDX ON ACQUIRED_IMAGES(THUMBNAIL_ID); + +CREATE TABLE EVENTS ( + LAST_SEEN_DELETION_EVENT_ID TECH_ID NOT NULL +); + +/* ---------------------------------------------------------------------- */ +/* FEATURE VECTORS */ +/* ---------------------------------------------------------------------- */ + +CREATE TABLE FEATURE_DEFS ( + ID BIGSERIAL NOT NULL, + + CODE LONG_NAME NOT NULL, + LABEL LONG_NAME NOT NULL, + DESCRIPTION DESCRIPTION, + + DS_ID TECH_ID NOT NULL, + + PRIMARY KEY (ID), + CONSTRAINT FK_FEATURE_DEFS_1 FOREIGN KEY (DS_ID) REFERENCES ANALYSIS_DATA_SETS (ID) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FEATURE_DEFS_UK_1 UNIQUE(CODE, DS_ID) +); + +CREATE INDEX FEATURE_DEFS_DS_IDX ON FEATURE_DEFS(DS_ID); + +CREATE TABLE FEATURE_VOCABULARY_TERMS ( + ID BIGSERIAL NOT NULL, + + CODE LONG_NAME NOT NULL, + SEQUENCE_NUMBER INTEGER NOT NULL, + FD_ID TECH_ID NOT NULL, + + PRIMARY KEY (ID), + CONSTRAINT FK_FEATURE_VOCABULARY_TERMS_1 FOREIGN KEY (FD_ID) REFERENCES FEATURE_DEFS (ID) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX FEATURE_VOCABULARY_TERMS_FD_IDX ON FEATURE_VOCABULARY_TERMS(FD_ID); + +CREATE TABLE FEATURE_VALUES ( + ID BIGSERIAL NOT NULL, + + -- we use the fixed dimension meters here + Z_in_M REAL, + -- we use the fixed dimension seconds here + T_in_SEC REAL, + -- Serialized 2D matrix with values for each spot. + -- Contains floats which can be NaN. + -- It is never a case that the whole matrix contains NaN - in such a case we save nothing. + -- If feature definition has some connected vocabulary terms then the matrix + -- stores FEATURE_VOCABULARY_TERMS.SEQUENCE_NUMBER of the terms (should be casted from float to int). + -- If the term is null the Float.NaN is stored. + VALUES BYTEA NOT NULL, + + FD_ID TECH_ID NOT NULL, + + PRIMARY KEY (ID), + CONSTRAINT FK_FEATURE_VALUES_1 FOREIGN KEY (FD_ID) REFERENCES FEATURE_DEFS (ID) ON DELETE CASCADE ON UPDATE CASCADE + -- This constaint does not make any sense. Leave it out for now. + -- CONSTRAINT FEATURE_VALUES_UK_1 UNIQUE(Z_in_M, T_in_SEC) +); + +CREATE INDEX FEATURE_VALUES_FD_IDX ON FEATURE_VALUES(FD_ID); +CREATE INDEX FEATURE_VALUES_Z_AND_T_IDX ON FEATURE_VALUES(Z_in_M, T_in_SEC); + + +/* ---------------------------------------------------------------------- */ +/* FUNCTIONS AND TRIGGERS */ +/* ---------------------------------------------------------------------- */ + +CREATE OR REPLACE FUNCTION DELETE_UNUSED_IMAGES() RETURNS trigger AS $$ +BEGIN + delete from images where id = OLD.img_id or id = OLD.thumbnail_id; + RETURN NEW; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE TRIGGER UNUSED_IMAGES AFTER DELETE ON ACQUIRED_IMAGES + FOR EACH ROW EXECUTE PROCEDURE DELETE_UNUSED_IMAGES(); + +CREATE OR REPLACE FUNCTION DELETE_UNUSED_NULLED_IMAGES() RETURNS trigger AS $$ +BEGIN + if NEW.img_id IS NULL then + if OLD.img_id IS NOT NULL then + delete from images where id = OLD.img_id; + end if; + end if; + if NEW.thumbnail_id IS NULL then + if OLD.thumbnail_id IS NOT NULL then + delete from images where id = OLD.thumbnail_id; + end if; + end if; + RETURN NEW; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE TRIGGER UNUSED_NULLED_IMAGES AFTER UPDATE ON ACQUIRED_IMAGES + FOR EACH ROW EXECUTE PROCEDURE DELETE_UNUSED_NULLED_IMAGES(); + +CREATE OR REPLACE FUNCTION DELETE_EMPTY_ACQUIRED_IMAGES() RETURNS trigger AS $$ +BEGIN + delete from acquired_images where id = OLD.id; + RETURN NEW; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE TRIGGER EMPTY_ACQUIRED_IMAGES BEFORE UPDATE ON ACQUIRED_IMAGES + FOR EACH ROW + WHEN (NEW.img_id IS NULL AND NEW.thumbnail_id IS NULL) + EXECUTE PROCEDURE DELETE_EMPTY_ACQUIRED_IMAGES(); + + +------------------------------------------------------------------------------------ +-- Purpose: Create trigger CHANNEL_STACKS_CHECK which checks if both spot_id and dataset.cont_id +-- are both null or not null. +------------------------------------------------------------------------------------ + +CREATE OR REPLACE FUNCTION CHANNEL_STACKS_CHECK() RETURNS trigger AS $$ +DECLARE + v_cont_id CODE; +BEGIN + + select cont_id into v_cont_id from image_data_sets where id = NEW.ds_id; + + -- Check that if there is no spot than there is no dataset container as well + if v_cont_id IS NULL then + if NEW.spot_id IS NOT NULL then + RAISE EXCEPTION 'Insert/Update of CHANNEL_STACKS failed, as the dataset container is not set, but spot is (spot id = %).',NEW.spot_id; + end if; + else + if NEW.spot_id IS NULL then + RAISE EXCEPTION 'Insert/Update of CHANNEL_STACKS failed, as the dataset container is set (id = %), but spot is not set.',v_cont_id; + end if; + end if; + RETURN NEW; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE TRIGGER CHANNEL_STACKS_CHECK BEFORE INSERT OR UPDATE ON CHANNEL_STACKS + FOR EACH ROW EXECUTE PROCEDURE CHANNEL_STACKS_CHECK(); + +------------------------------------------------------------------------------------ +-- Purpose: Create trigger IMAGE_TRANSFORMATIONS_DEFAULT_CHECK which checks +-- if at most one channel's transformation is default +------------------------------------------------------------------------------------ + +CREATE OR REPLACE FUNCTION IMAGE_TRANSFORMATIONS_DEFAULT_CHECK() RETURNS trigger AS $$ +DECLARE + v_is_default boolean; +BEGIN + if NEW.is_default = 'T' then + select is_default into v_is_default from IMAGE_TRANSFORMATIONS + where is_default = 'T' + and channel_id = NEW.channel_id + and id != NEW.id; + if v_is_default is NOT NULL then + RAISE EXCEPTION 'Insert/Update of image transformation (Code: %) failed, as the new record has is_default set to true and there is already a default record defined.', NEW.code; + end if; + end if; + + RETURN NEW; +END; +$$ LANGUAGE 'plpgsql'; + +CREATE TRIGGER IMAGE_TRANSFORMATIONS_DEFAULT_CHECK BEFORE INSERT OR UPDATE ON IMAGE_TRANSFORMATIONS + FOR EACH ROW EXECUTE PROCEDURE IMAGE_TRANSFORMATIONS_DEFAULT_CHECK(); + \ No newline at end of file diff --git a/screening/source/sql/imaging/postgresql/migration/migration-022-023.sql b/screening/source/sql/imaging/postgresql/migration/migration-022-023.sql new file mode 100644 index 0000000000000000000000000000000000000000..fff0c987a5e58e5252e70e075c390608ebfa824f --- /dev/null +++ b/screening/source/sql/imaging/postgresql/migration/migration-022-023.sql @@ -0,0 +1,22 @@ +-- Migration from 022 to 023 + +CREATE DOMAIN LONG_NAME AS TEXT; + +ALTER TABLE IMAGE_DATA_SETS + ALTER COLUMN IMAGE_LIBRARY_NAME type LONG_NAME, + ALTER COLUMN IMAGE_LIBRARY_READER_NAME type LONG_NAME; + +ALTER TABLE CHANNELS + ALTER COLUMN CODE TYPE LONG_NAME, + ALTER COLUMN LABEL TYPE LONG_NAME; + +ALTER TABLE IMAGE_TRANSFORMATIONS + ALTER COLUMN CODE TYPE LONG_NAME, + ALTER COLUMN LABEL TYPE LONG_NAME; + +ALTER TABLE FEATURE_DEFS + ALTER COLUMN CODE TYPE LONG_NAME, + ALTER COLUMN LABEL TYPE LONG_NAME; + +ALTER TABLE FEATURE_VOCABULARY_TERMS + ALTER COLUMN CODE TYPE LONG_NAME; \ No newline at end of file diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/FeatureVectorsDropboxTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/FeatureVectorsDropboxTest.java index 820fa0ead8861fc787e6365dbecd8b9da3f73e51..8fd4b3b162364813c0c300c4a33e8a3f7dc7b9c7 100644 --- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/FeatureVectorsDropboxTest.java +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/screening/systemtests/FeatureVectorsDropboxTest.java @@ -32,7 +32,6 @@ import org.testng.annotations.Test; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.servlet.SpringRequestContextProvider; -import ch.systemsx.cisd.openbis.generic.server.util.TestInitializer; import ch.systemsx.cisd.openbis.generic.shared.util.TestInstanceHostUtils; import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.IScreeningOpenbisServiceFacade; import ch.systemsx.cisd.openbis.plugin.screening.client.api.v1.ScreeningOpenbisServiceFacade; @@ -126,7 +125,9 @@ public class FeatureVectorsDropboxTest extends AbstractScreeningSystemTestCase availableFeatureCodes.add(availableFeature.getCode()); } Collections.sort(availableFeatureCodes); - assertEquals("[COLUMN_NUMBER, ROW_NUMBER, STATE, TPU]", availableFeatureCodes.toString()); + assertEquals( + "[COLUMN_NUMBER, ROW_NUMBER, STATE, TPU, Z_VERY_LONG_FEATURE_LONGER_THAN_80_CHARS_123456789012345678901234567890123456789012345678901234567890]", + availableFeatureCodes.toString()); List<FeatureVectorDataset> featureVectorDatasets = screeningFacade.loadFeatures(features, Collections.singletonList("TPU"));