Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
120 lines
3.8 KiB
JavaScript
120 lines
3.8 KiB
JavaScript
/**
|
|
* Migration: Make contacts.client_id nullable
|
|
*
|
|
* Contacts can exist without being associated with a specific client.
|
|
* This migration removes the NOT NULL constraint if it exists.
|
|
*
|
|
* This is idempotent - it checks if the column is already nullable
|
|
* before attempting to change it.
|
|
*/
|
|
|
|
exports.config = { transaction: true };
|
|
|
|
exports.up = async function(knex) {
|
|
console.log('Checking contacts.client_id nullable constraint...');
|
|
|
|
try {
|
|
// Check if contacts table exists
|
|
const tableExists = await knex.schema.hasTable('contacts');
|
|
if (!tableExists) {
|
|
console.log('⚠ contacts table does not exist, skipping...');
|
|
return;
|
|
}
|
|
|
|
// Check if client_id column exists
|
|
const hasColumn = await knex.schema.hasColumn('contacts', 'client_id');
|
|
if (!hasColumn) {
|
|
console.log('⚠ contacts.client_id column does not exist, skipping...');
|
|
return;
|
|
}
|
|
|
|
// Check if column is already nullable
|
|
const result = await knex.raw(`
|
|
SELECT is_nullable
|
|
FROM information_schema.columns
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'contacts'
|
|
AND column_name = 'client_id'
|
|
`);
|
|
|
|
if (result.rows.length === 0) {
|
|
console.log('⚠ Could not determine nullable status for contacts.client_id, skipping...');
|
|
return;
|
|
}
|
|
|
|
const isNullable = result.rows[0].is_nullable === 'YES';
|
|
|
|
if (isNullable) {
|
|
console.log('✓ contacts.client_id is already nullable, no change needed');
|
|
return;
|
|
}
|
|
|
|
// Column is NOT NULL, so remove the constraint
|
|
console.log('contacts.client_id is NOT NULL, removing constraint...');
|
|
await knex.raw(`ALTER TABLE contacts ALTER COLUMN client_id DROP NOT NULL`);
|
|
|
|
console.log('✓ contacts.client_id is now nullable');
|
|
} catch (error) {
|
|
console.error('❌ Failed to make contacts.client_id nullable:', error.message);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
exports.down = async function(knex) {
|
|
console.log('Rolling back: Checking if we should make contacts.client_id NOT NULL...');
|
|
|
|
try {
|
|
// Check if contacts table exists
|
|
const tableExists = await knex.schema.hasTable('contacts');
|
|
if (!tableExists) {
|
|
console.log('⚠ contacts table does not exist, skipping...');
|
|
return;
|
|
}
|
|
|
|
// Check if client_id column exists
|
|
const hasColumn = await knex.schema.hasColumn('contacts', 'client_id');
|
|
if (!hasColumn) {
|
|
console.log('⚠ contacts.client_id column does not exist, skipping...');
|
|
return;
|
|
}
|
|
|
|
// Check if column is already NOT NULL
|
|
const result = await knex.raw(`
|
|
SELECT is_nullable
|
|
FROM information_schema.columns
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'contacts'
|
|
AND column_name = 'client_id'
|
|
`);
|
|
|
|
if (result.rows.length === 0) {
|
|
console.log('⚠ Could not determine nullable status for contacts.client_id, skipping...');
|
|
return;
|
|
}
|
|
|
|
const isNullable = result.rows[0].is_nullable === 'YES';
|
|
|
|
if (!isNullable) {
|
|
console.log('✓ contacts.client_id is already NOT NULL, no change needed');
|
|
return;
|
|
}
|
|
|
|
// Check for NULL values before adding constraint
|
|
const nullCount = await knex('contacts').whereNull('client_id').count('* as count');
|
|
if (parseInt(nullCount[0].count) > 0) {
|
|
console.log(`⚠ contacts table has ${nullCount[0].count} NULL client_id values`);
|
|
console.log('Cannot add NOT NULL constraint. Please update these records first.');
|
|
throw new Error('Cannot add NOT NULL constraint: NULL values exist');
|
|
}
|
|
|
|
// Add back NOT NULL constraint
|
|
console.log('Making contacts.client_id NOT NULL...');
|
|
await knex.raw(`ALTER TABLE contacts ALTER COLUMN client_id SET NOT NULL`);
|
|
|
|
console.log('✓ contacts.client_id is now NOT NULL');
|
|
} catch (error) {
|
|
console.error('❌ Failed to make contacts.client_id NOT NULL:', error.message);
|
|
throw error;
|
|
}
|
|
};
|