diff --git a/hub-prime/lib/techbd-udi-jooq-ingress.auto.jar b/hub-prime/lib/techbd-udi-jooq-ingress.auto.jar index c583bfa4a38..f5b480e651a 100644 Binary files a/hub-prime/lib/techbd-udi-jooq-ingress.auto.jar and b/hub-prime/lib/techbd-udi-jooq-ingress.auto.jar differ diff --git a/udi-prime/src/main/postgres/ingestion-center/001_idempotent_interaction.psql b/udi-prime/src/main/postgres/ingestion-center/001_idempotent_interaction.psql index 83dc1b9bdd3..5e54062a00f 100644 --- a/udi-prime/src/main/postgres/ingestion-center/001_idempotent_interaction.psql +++ b/udi-prime/src/main/postgres/ingestion-center/001_idempotent_interaction.psql @@ -239,7 +239,6 @@ AS SELECT tenant_id, DROP FUNCTION IF EXISTS techbd_udi_ingress.register_interaction_http_request(text, text, jsonb, text, text, jsonb, jsonb, text, text, text, text, text, text, text, text, timestamptz, text, text, bool, text, bytea, text, text, text, text, text, text, text, text, text, text, text, text, text, text, text, text, text); -DROP FUNCTION IF EXISTS techbd_udi_ingress.register_interaction_http_request(text, text, jsonb, text, text, jsonb, jsonb, text, text, text, text, text, text, text, text, timestamptz, text, text, bool, text, bytea, text, text, text, text, text, text, text, text, text, text, text, text, text, text, text, text, text); CREATE OR REPLACE FUNCTION techbd_udi_ingress.register_interaction_http_request(interaction_id text, interaction_key text, payload jsonb DEFAULT NULL::jsonb, payload_text text DEFAULT NULL::text, rule_namespace text DEFAULT NULL::text, elaboration jsonb DEFAULT NULL::jsonb, nature jsonb DEFAULT NULL::jsonb, content_type text DEFAULT NULL::text, from_state text DEFAULT NULL::text, to_state text DEFAULT NULL::text, state_transition_reason text DEFAULT NULL::text, user_id text DEFAULT NULL::text, user_name text DEFAULT NULL::text, user_session text DEFAULT NULL::text, user_role text DEFAULT NULL::text, created_at timestamp with time zone DEFAULT NULL::timestamp with time zone, created_by text DEFAULT NULL::text, provenance text DEFAULT NULL::text, hub_upsert_behavior boolean DEFAULT true, csv_zip_file_name text DEFAULT NULL::text, csv_zip_file_content bytea DEFAULT NULL::bytea, csv_group_id text DEFAULT NULL::text, csv_status text DEFAULT NULL::text, csv_screening_observation_data_payload_text text DEFAULT NULL::text, csv_screening_profile_data_payload_text text DEFAULT NULL::text, csv_demographic_data_payload_text text DEFAULT NULL::text, csv_qe_admin_data_payload_text text DEFAULT NULL::text, csv_screening_observation_data_file_name text DEFAULT NULL::text, csv_screening_profile_data_file_name text DEFAULT NULL::text, csv_demographic_data_file_name text DEFAULT NULL::text, csv_qe_admin_data_file_name text DEFAULT NULL::text, source_hub_interaction_id text DEFAULT NULL::text, client_ip_address text DEFAULT NULL::text, user_agent text DEFAULT NULL::text, origin text DEFAULT NULL::text, source_type text DEFAULT NULL::text, group_hub_interaction_id text DEFAULT NULL::text, sftp_session_id text DEFAULT NULL::text) RETURNS jsonb @@ -368,9 +367,10 @@ BEGIN 'Insert into sat_interaction_http_request'::text, v_user_id, 'success'::text, NULL::text, 0, v_elaboration); /*------------------------------*/ --1) Call the function with the defined parameters to upsert user info - IF((v_nature_denorm = 'org.techbd.service.http.Interactions$RequestResponseEncountered' AND trim(register_interaction_http_request.interaction_key) NOT IN ('/Hl7/v2', '/Hl7/v2/', '/flatfile/csv/Bundle', '/flatfile/csv/Bundle/', '/flatfile/csv/Bundle/$validate', '/flatfile/csv/Bundle/$validate/')) /*fhir bundle*/ + IF((v_nature_denorm = 'org.techbd.service.http.Interactions$RequestResponseEncountered' AND trim(register_interaction_http_request.interaction_key) NOT IN ('/Hl7/v2', '/Hl7/v2/', '/flatfile/csv/Bundle', '/flatfile/csv/Bundle/', '/flatfile/csv/Bundle/$validate', '/flatfile/csv/Bundle/$validate/', '/ccda/Bundle', '/ccda/Bundle/')) /*fhir bundle*/ OR (v_nature_denorm = 'Original HL7 Payload' AND trim(register_interaction_http_request.interaction_key) IN ('/Hl7/v2', '/Hl7/v2/')) /*hl7*/ OR (v_nature_denorm = 'Original CSV Zip Archive' AND trim(register_interaction_http_request.interaction_key) IN ('/flatfile/csv/Bundle', '/flatfile/csv/Bundle/', '/flatfile/csv/Bundle/$validate', '/flatfile/csv/Bundle/$validate/')) /*csv*/ + OR (v_nature_denorm = 'Original CCDA Payload' AND trim(register_interaction_http_request.interaction_key) IN ('/ccda/Bundle', '/ccda/Bundle/')) /*ccda*/ ) THEN PERFORM techbd_udi_ingress.sat_interaction_user_upserted( hub_interaction_id => register_interaction_http_request.interaction_id, @@ -403,7 +403,7 @@ BEGIN --2.1) Call the function with the defined parameters to upsert interaction FHIR request info. IF trim(register_interaction_http_request.interaction_key) IN ('/Bundle', '/Bundle/', '/Bundle/$validate', '/api/expect/fhir/bundle', '/Hl7/v2', '/Hl7/v2/', '/flatfile/csv/Bundle', '/flatfile/csv/Bundle/', '/flatfile/csv/Bundle/$validate', '/flatfile/csv/Bundle/$validate/', '/ccda/Bundle', '/ccda/Bundle/') - AND v_nature_denorm NOT IN ('Original HL7 Payload', 'Original CSV Zip Archive', 'Original Flat File CSV', 'CSV Validation Result', 'Converted to FHIR') THEN + AND v_nature_denorm NOT IN ('Original HL7 Payload', 'Original CSV Zip Archive', 'Original Flat File CSV', 'CSV Validation Result', 'Converted to FHIR', 'Original CCDA Payload') THEN PERFORM techbd_udi_ingress.sat_interaction_fhir_request_upserted( hub_interaction_id => register_interaction_http_request.interaction_id, @@ -510,6 +510,23 @@ BEGIN CALL techbd_udi_ingress.register_diagnostic_log(v_exception_id, register_interaction_http_request.interaction_key, v_created_by, v_provenance, 'info'::text, 'Insert into sat_interaction_csv_request'::text, v_user_id, 'success'::text, NULL::text, 0, v_elaboration); /*------------------------------*/ + --2.4) Call the function with the defined parameters to upsert interaction CCDA request info. + ELSIF trim(register_interaction_http_request.interaction_key) IN ('/ccda/Bundle', '/ccda/Bundle/') AND v_nature_denorm IN ('Original CCDA Payload') THEN + PERFORM techbd_udi_ingress.sat_interaction_ccda_request_upserted( + register_interaction_http_request.interaction_id, + v_tenant_id_denorm, + register_interaction_http_request.interaction_key, + v_nature_denorm, + register_interaction_http_request.from_state, + register_interaction_http_request.to_state, + register_interaction_http_request.payload, + register_interaction_http_request.payload_text, + register_interaction_http_request.state_transition_reason, + v_created_at, + v_created_by, + v_provenance, + register_interaction_http_request.elaboration + ); END IF; /*==============================================================================================================================*/ @@ -4303,3 +4320,108 @@ from techbd_udi_ingress.sat_interaction_fhir_session_diagnostic intr_diagno where severity in ('warning','ERROR','WARING','error') and message != ''; + +DROP FUNCTION IF EXISTS techbd_udi_ingress.sat_interaction_ccda_request_upserted(text, text, text, text, text, text, jsonb, text, timestamptz, text, text, jsonb, text, text, text); + +CREATE OR REPLACE FUNCTION techbd_udi_ingress.sat_interaction_ccda_request_upserted(hub_interaction_id text, tenant_id text, uri text, nature text, from_state text, to_state text, payload jsonb DEFAULT NULL::jsonb, ccda_payload_text TEXT DEFAULT NULL::text, state_transition_reason text DEFAULT NULL::text, created_at timestamp with time zone DEFAULT NULL::timestamp with time zone, created_by text DEFAULT NULL::text, provenance text DEFAULT NULL::text, elaboration jsonb DEFAULT NULL::jsonb, client_ip_address text DEFAULT NULL::text, user_agent text DEFAULT NULL::text, origin text DEFAULT 'http'::text) + RETURNS text + LANGUAGE plpgsql +AS $function$ +DECLARE + -- Declare variables to hold error and extracted data + v_error_msg TEXT; + v_error_type TEXT; + v_sqlstate TEXT; + v_pg_detail TEXT; + v_pg_hint TEXT; + v_pg_context TEXT; + v_created_at TIMESTAMPTZ := COALESCE(created_at, CURRENT_TIMESTAMP); -- Ensure created_at is not null + v_created_by TEXT := COALESCE(created_by, current_user); -- Default created_by to the current user if not provided + v_provenance TEXT := COALESCE(provenance, 'unknown'); -- Set default provenance + v_exception_id TEXT; + + -- Additional variables for extracting and holding data from the payload JSONB + v_return TEXT := NULL; + +BEGIN + IF NOT EXISTS(SELECT 1 FROM techbd_udi_ingress.hub_interaction t + WHERE t.hub_interaction_id = sat_interaction_ccda_request_upserted.hub_interaction_id + AND t."key" = sat_interaction_ccda_request_upserted.uri) THEN + RETURN NULL; + END IF; + + IF sat_interaction_ccda_request_upserted.ccda_payload_text IS NULL THEN + RETURN NULL; + END IF; + + -- The INSERT statement inserts a new record into the sat_interaction_ccda_request table, generating a UUID for the primary key. + -- If the operation succeeds, the generated UUID is returned. + INSERT INTO techbd_udi_ingress.sat_interaction_ccda_request ( + sat_interaction_ccda_request_id, + hub_interaction_id, + tenant_id, + tenant_id_lower, + uri, + nature, + payload, + ccda_payload_text, + from_state, + to_state, + state_transition_reason, + created_by, + provenance, + elaboration, + client_ip_address, + user_agent, + origin + ) + VALUES ( + gen_random_uuid()::TEXT, -- Generate a unique UUID for the primary key + hub_interaction_id, + tenant_id, + LOWER(tenant_id), -- Store the tenant ID in lowercase for consistency + uri, + nature, + payload, + ccda_payload_text, + from_state, + to_state, + state_transition_reason, + created_by, + provenance, + elaboration, + client_ip_address, + user_agent, + origin + ) RETURNING sat_interaction_ccda_request_id INTO v_return; -- Return the generated UUID + + RETURN v_return; +EXCEPTION + WHEN OTHERS THEN + -- Capture exception details + GET STACKED DIAGNOSTICS + v_error_msg = MESSAGE_TEXT, + v_sqlstate = RETURNED_SQLSTATE, + v_pg_detail = PG_EXCEPTION_DETAIL, + v_pg_hint = PG_EXCEPTION_HINT, + v_pg_context = PG_EXCEPTION_CONTEXT; + v_error_type = 'SQL'; + + RAISE NOTICE 'Error occurred: %', SQLERRM; /*Test purpose*/ + + -- Log the exception, reusing the previous exception ID if it exists + v_exception_id := techbd_udi_ingress.register_issue( + COALESCE(v_exception_id,NULL), + sat_interaction_ccda_request_upserted.uri, + v_error_msg, + v_error_type, + v_sqlstate, + v_pg_detail, + v_pg_hint, + v_pg_context, + v_created_by, + v_provenance); + RETURN NULL; +END; +$function$ +; \ No newline at end of file diff --git a/udi-prime/src/test/postgres/ingestion-center/001-idempotent-interaction-unit-test.psql b/udi-prime/src/test/postgres/ingestion-center/001-idempotent-interaction-unit-test.psql index c973a72290c..adf59de53d2 100644 --- a/udi-prime/src/test/postgres/ingestion-center/001-idempotent-interaction-unit-test.psql +++ b/udi-prime/src/test/postgres/ingestion-center/001-idempotent-interaction-unit-test.psql @@ -90,6 +90,11 @@ BEGIN RETURN NEXT has_function(schema_name, 'sat_interaction_csv_request_upserted', ARRAY['text', 'text', 'text', 'text', 'text', 'bytea', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'text', 'jsonb', 'text', 'text', 'text', 'timestamptz', 'text', 'text', 'jsonb', 'text', 'text', 'text', 'text', 'text', 'jsonb'], 'Function sat_interaction_csv_request_upserted exists'); + + RETURN NEXT has_function(schema_name, 'sat_interaction_ccda_request_upserted', ARRAY['text', 'text', 'text', 'text', 'text', 'text', 'jsonb', 'text', 'text','timestamptz', 'text', 'text', 'jsonb', 'text', 'text', 'text'], + 'Function sat_interaction_ccda_request_upserted exists' + ); + RETURN NEXT has_table(schema_name, 'sat_interaction_flat_file_csv_request', 'The table techbd_udi_ingress.sat_interaction_flat_file_csv_request should exist.'); RETURN NEXT has_pk(schema_name, 'sat_interaction_flat_file_csv_request', 'The table techbd_udi_ingress.sat_interaction_flat_file_csv_request should have a primary key.'); @@ -127,6 +132,18 @@ BEGIN RETURN NEXT col_not_null(schema_name, 'sat_interaction_zip_file_request', 'hub_interaction_id', 'The column hub_interaction_id should be NOT NULL.'); + RETURN NEXT has_table(schema_name, 'sat_interaction_ccda_request', 'The table techbd_udi_ingress.sat_interaction_ccda_request should exist.'); + + RETURN NEXT has_pk(schema_name, 'sat_interaction_ccda_request', 'The table techbd_udi_ingress.sat_interaction_ccda_request should have a primary key.'); + + RETURN NEXT col_is_fk(schema_name::name, 'sat_interaction_ccda_request'::name, 'hub_interaction_id'::name, 'The foreign key from hub_interaction_id to techbd_udi_ingress.hub_interaction should exist.'); + + RETURN NEXT columns_are(schema_name, 'sat_interaction_ccda_request', + ARRAY['sat_interaction_ccda_request_id', 'hub_interaction_id', 'tenant_id', 'tenant_id_lower', 'uri', 'nature', 'payload', 'ccda_payload_text', + 'client_ip_address', 'user_agent', 'from_state', 'to_state', 'state_transition_reason', 'elaboration', 'origin', 'created_at', 'created_by', 'provenance'], + 'The columns of techbd_udi_ingress.sat_interaction_ccda_request should match the expected structure.' + ); + /*=================== Testing with FHIR bundle ========================*/ PERFORM techbd_udi_ingress.register_interaction_http_request( @@ -903,6 +920,302 @@ PID|||112024345690^123^12345||Doe Le^John^^^MR||19651015|M||2054-5^Black|123 Mai /*======================END of HL7 Testing===========================*/ + /*=================== Testing with CCDA File ========================*/ + + /* First call to insert CCDA xml payload */ + v_interaction_id := 'c56ccd65-9a4f-5cc8-9c5d-b65245d90fb0'; + v_interaction_key := '/ccda/Bundle'; + v_nature := '{"nature":"Original CCDA Payload", "tenant_id":"N/A"}'; + v_from_state := NULL; + v_to_state := 'CCDA_ACCEPT'; + v_hl7_json := + '{ + "resourceType" : "Bundle", + "id" : "AHCHRSNQuestionnaireResponseExample", + "meta" : { + "lastUpdated" : "2024-02-23T00:00:00Z", + "profile" : ["http://shinny.org/us/ny/hrsn/StructureDefinition/SHINNYBundleProfile"] + }, + "type" : "transaction", + "timestamp" : "2024-02-23T00:00:00Z", + "entry" : [{ + "fullUrl" : "http://shinny.org/us/ny/hrsn/Patient/PatientExample", + "resource" : { + "resourceType" : "Patient", + "id" : "PatientExample", + "meta" : { + "lastUpdated" : "2024-02-23T00:00:00.00Z", + "profile" : ["http://shinny.org/us/ny/hrsn/StructureDefinition/shinny-patient"] + }, + "language" : "en", + "extension" : [{ + "extension" : [{ + "url" : "ombCategory", + "valueCoding" : { + "system" : "urn:oid:2.16.840.1.113883.6.238", + "code" : "2028-9", + "display" : "Asian" + } + }, + { + "url" : "text", + "valueString" : "Asian" + }], + "url" : "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race" + }, + { + "extension" : [{ + "url" : "ombCategory", + "valueCoding" : { + "system" : "urn:oid:2.16.840.1.113883.6.238", + "code" : "2135-2", + "display" : "Hispanic or Latino" + } + }, + { + "url" : "text", + "valueString" : "Hispanic or Latino" + }], + "url" : "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity" + }], + "identifier" : [{ + "type" : { + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/v2-0203", + "code" : "MR" + }] + }, + "system" : "http://www.scn.gov/facility/CUMC", + "value" : "11223344", + "assigner" : { + "reference" : "Organization/OrganizationExampleOther-SCN1" + } + }, + { + "type" : { + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/v2-0203", + "code" : "MA" + }] + }, + "system" : "http://www.medicaid.gov/", + "value" : "AA12345C" + }, + { + "type" : { + "coding" : [{ + "system" : "http://terminology.hl7.org/CodeSystem/v2-0203", + "code" : "SS", + "display" : "Social Security Number" + }], + "text" : "Social Security Number" + }, + "system" : "http://www.ssa.gov/", + "value" : "999-34-2964" + }], + "name" : [{ + "extension" : [{ + "url" : "http://shinny.org/us/ny/hrsn/StructureDefinition/middle-name", + "valueString" : "Bob" + }], + "family" : "Doe", + "given" : ["Jon"] + }], + "telecom" : [{ + "system" : "phone", + "value" : "555-120-6047", + "use" : "home" + }], + "gender" : "male", + "birthDate" : "1981-07-16", + "address" : [{ + "text" : "115 Broadway Apt2 New York, NY 10032", + "line" : ["115 Broadway Apt2"], + "city" : "New York", + "district" : "MANHATTAN", + "state" : "NY", + "postalCode" : "10032" + }] + }, + "request" : { + "method" : "POST", + "url" : "http://shinny.org/us/ny/hrsn/Patient/PatientExample" + } + }] + }'; + v_payload_text := ' + + + + CCDA Sample + + + + + + + John + Doe + + + + + + + + + + '; + + + PERFORM techbd_udi_ingress.register_interaction_http_request( + interaction_id => v_interaction_id, + interaction_key => v_interaction_key, + payload => NULL, + payload_text => v_payload_text, + rule_namespace => v_rule_namespace, + elaboration => v_elaboration, + nature => v_nature, + content_type => v_content_type, + from_state => v_from_state, + to_state => v_to_state, + state_transition_reason => v_state_transition_reason, + created_at => v_created_at, + created_by => v_created_by, + provenance => v_provenance, + hub_upsert_behavior => true + ); + + RETURN NEXT ok( + EXISTS(SELECT 1 FROM techbd_udi_ingress.hub_interaction hub_intr + WHERE hub_intr.hub_interaction_id = v_interaction_id + AND hub_intr."key" = v_interaction_key + AND hub_intr.created_by = v_created_by + AND hub_intr.provenance = v_provenance + ), + 'CCDA - Successfully inserted into the table hub_interaction' + ); + + /*Test 1 raw is inserted into sat_interaction_http_request table*/ + RETURN NEXT ok( + EXISTS(SELECT 1 FROM techbd_udi_ingress.sat_interaction_http_request sat_intr + WHERE sat_intr.hub_interaction_id = v_interaction_id + AND sat_intr.nature = v_nature + AND sat_intr.nature_denorm = v_nature->>'nature' + AND sat_intr.content_type = v_content_type + AND sat_intr.to_state = v_to_state + AND sat_intr.state_transition_reason = v_state_transition_reason + AND sat_intr.payload_text = v_payload_text + AND sat_intr.elaboration = v_elaboration + AND sat_intr.created_by = v_created_by + AND sat_intr.provenance = v_provenance + ), + 'CCDA - Successfully inserted one record into the table sat_interaction_http_request with "Original CCDA Payload" as nature' + ); + + /*Test 1 raw is inserted into sat_interaction_ccda_request table*/ + RETURN NEXT ok( + EXISTS(SELECT 1 FROM techbd_udi_ingress.sat_interaction_ccda_request sat_intr + WHERE sat_intr.hub_interaction_id = v_interaction_id + AND sat_intr.uri = v_interaction_key + AND sat_intr.nature = v_nature->>'nature' + AND sat_intr.to_state = v_to_state + AND sat_intr.created_by = v_created_by + AND sat_intr.provenance = v_provenance + ), + 'CCDA - Successfully inserted one record into the table sat_interaction_ccda_request with "Original CCDA Payload" as nature' + ); + + /*Test one record is inserted into sat_interaction_user table*/ + RETURN NEXT ok( + EXISTS(SELECT 1 FROM techbd_udi_ingress.sat_interaction_user sat_intr + WHERE sat_intr.hub_interaction_id = v_interaction_id + AND sat_intr.uri = v_interaction_key + AND sat_intr.nature = v_nature->>'nature' + AND sat_intr.created_by = v_created_by + AND sat_intr.provenance = v_provenance + ), + 'CCDA - Successfully inserted into the table sat_interaction_user' + ); + + /* Second call to insert the FHIR bundle which is generated from CCDA json with interaction_key = '/Ccda'*/ + v_nature := '{"nature": "org.techbd.service.http.Interactions$RequestResponseEncountered", "tenant_id": "N/A"}'; + v_to_state := NULL; + + + PERFORM techbd_udi_ingress.register_interaction_http_request( + interaction_id => v_interaction_id, + interaction_key => v_interaction_key, + payload => v_hl7_json, + payload_text => NULL, + rule_namespace => v_rule_namespace, + elaboration => v_elaboration, + nature => v_nature, + content_type => v_content_type, + from_state => v_from_state, + to_state => v_to_state, + state_transition_reason => v_state_transition_reason, + created_at => v_created_at, + created_by => v_created_by, + provenance => v_provenance, + hub_upsert_behavior => true + ); + + /*Test 3 raws are inserted into sat_interaction_http_request table*/ + RETURN NEXT ok( + CASE + WHEN ( + SELECT count(hub_interaction_id) + FROM techbd_udi_ingress.sat_interaction_http_request sat_intr + WHERE sat_intr.hub_interaction_id = v_interaction_id + AND sat_intr.nature_denorm IN ( + 'org.techbd.service.http.Interactions$RequestResponseEncountered', + 'Original FHIR Payload', + 'techByDesignDisposition' + ) + AND sat_intr.created_by = v_created_by + AND sat_intr.provenance = v_provenance + ) = 3 + THEN TRUE + ELSE FALSE + END, + 'CCDA - Successfully inserted 3 records into the table sat_interaction_http_request' + ); + + /*Test 3 raws are inserted into sat_interaction_fhir_request table*/ + RETURN NEXT ok( + CASE + WHEN ( + SELECT count(hub_interaction_id) + FROM techbd_udi_ingress.sat_interaction_fhir_request sat_intr + WHERE sat_intr.hub_interaction_id = v_interaction_id + AND sat_intr.uri = v_interaction_key + AND sat_intr.nature IN ( + 'org.techbd.service.http.Interactions$RequestResponseEncountered', + 'Original FHIR Payload', + 'techByDesignDisposition' + ) + AND sat_intr.created_by = v_created_by + AND sat_intr.provenance = v_provenance + ) = 3 + THEN TRUE + ELSE FALSE + END, + 'CCDA - Successfully inserted 3 records into the table sat_interaction_fhir_request' + ); + + /*======================END of CCDA Testing==========================*/ + /*===================================================================*/ /*Test the exception handling with Unique Constraint Violation*/ diff --git a/udi-prime/udictl.ts b/udi-prime/udictl.ts index 169d90e9cea..a0d3b43a665 100755 --- a/udi-prime/udictl.ts +++ b/udi-prime/udictl.ts @@ -156,7 +156,7 @@ const CLI = new Command() const generated = await module.generated(); driverGenerateMigrationSQL = driverGenerateMigrationSQL + '\n' + generated.driverGenerateMigrationSQL; destroySQL = destroySQL + '\n' +generated.destroySQL; - if(module.migrationInput.description.length >= 20){ + if(module.migrationInput.description.length > 20){ throw new Error('Migration version description `'+module.migrationInput.description+'` length cannot exceed 20 characters'); } if(migrateIc.ic.length-1==index){