Add all migration files to migrationsv2

Co-authored-by: Fredrik Adelöw <freben@users.noreply.github.com>
Co-authored-by: Ben Lambert <ben@blam.sh>
Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2021-04-26 15:38:31 +02:00
committed by blam
parent ac48004b7d
commit c58f8fd147
19 changed files with 1226 additions and 15 deletions
@@ -0,0 +1,133 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
return (
knex.schema
//
// locations
//
.createTable('locations', table => {
table.comment(
'Registered locations that shall be contiuously scanned for catalog item updates',
);
table
.uuid('id')
.primary()
.notNullable()
.comment('Auto-generated ID of the location');
table.string('type').notNullable().comment('The type of location');
table
.string('target')
.notNullable()
.comment('The actual target of the location');
})
//
// entities
//
.createTable('entities', table => {
table.comment('All entities currently stored in the catalog');
table.uuid('id').primary().comment('Auto-generated ID of the entity');
table
.uuid('location_id')
.references('id')
.inTable('locations')
.nullable()
.comment('The location that originated the entity');
table
.string('etag')
.notNullable()
.comment(
'An opaque string that changes for each update operation to any part of the entity, including metadata.',
);
table
.string('generation')
.notNullable()
.unsigned()
.comment(
'A positive nonzero number that indicates the current generation of data for this entity; the value is incremented each time the spec changes.',
);
table
.string('api_version')
.notNullable()
.comment('The apiVersion field of the entity');
table
.string('kind')
.notNullable()
.comment('The kind field of the entity');
table
.string('name')
.nullable()
.comment('The metadata.name field of the entity');
table
.string('namespace')
.nullable()
.comment('The metadata.namespace field of the entity');
table
.string('metadata')
.notNullable()
.comment('The entire metadata JSON blob of the entity');
table
.string('spec')
.nullable()
.comment('The entire spec JSON blob of the entity');
})
.alterTable('entities', table => {
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta
table.unique(['kind', 'name', 'namespace'], 'entities_unique_name');
})
//
// entities_search
//
.createTable('entities_search', table => {
table.comment(
'Flattened key-values from the entities, used for quick filtering',
);
table
.uuid('entity_id')
.references('id')
.inTable('entities')
.onDelete('CASCADE')
.comment('The entity that matches this key/value');
table
.string('key')
.notNullable()
.comment('A key that occurs in the entity');
table
.string('value')
.nullable()
.comment('The corresponding value to match on');
})
);
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
return knex.schema
.dropTable('entities_search')
.alterTable('entities', table => {
table.dropUnique([], 'entities_unique_name');
})
.dropTable('entities')
.dropTable('locations');
};
@@ -0,0 +1,43 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
return knex.schema.createTable('location_update_log', table => {
table.uuid('id').primary();
table.enum('status', ['success', 'fail']).notNullable();
table.dateTime('created_at').defaultTo(knex.fn.now()).notNullable();
table.string('message');
table
.uuid('location_id')
.references('id')
.inTable('locations')
.onUpdate('CASCADE')
.onDelete('CASCADE');
table.string('entity_name').nullable();
});
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
return knex.schema.dropTableIfExists('location_update_log');
};
@@ -0,0 +1,45 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
// Get list sorted by created_at timestamp in descending order
// Grouped by location_id
return knex.schema.raw(`
CREATE VIEW location_update_log_latest AS
SELECT t1.* FROM location_update_log t1
JOIN
(
SELECT location_id, MAX(created_at) AS MAXDATE
FROM location_update_log
GROUP BY location_id
) t2
ON t1.location_id = t2.location_id
AND t1.created_at = t2.MAXDATE
ORDER BY created_at DESC;
`);
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
return knex.schema.raw(`DROP VIEW location_update_log_latest;`);
};
@@ -0,0 +1,236 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
// SQLite does not support FK and PK
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities_search', table => {
table.dropForeign(['entity_id']);
});
await knex.schema.alterTable('entities', table => {
table.dropPrimary('entities_pkey');
});
}
await knex.schema.alterTable('entities', table => {
table.dropUnique([], 'entities_unique_name');
});
// Setup temporary tables
await knex.schema.renameTable('entities_search', 'tmp_entities_search');
await knex.schema.renameTable('entities', 'tmp_entities');
//
// entities
//
await knex.schema
.createTable('entities', table => {
table.comment('All entities currently stored in the catalog');
table.uuid('id').primary().comment('Auto-generated ID of the entity');
table
.uuid('location_id')
.references('id')
.inTable('locations')
.nullable()
.comment('The location that originated the entity');
table
.string('etag')
.notNullable()
.comment(
'An opaque string that changes for each update operation to any part of the entity, including metadata.',
);
table
.string('generation')
.notNullable()
.unsigned()
.comment(
'A positive nonzero number that indicates the current generation of data for this entity; the value is incremented each time the spec changes.',
);
table
.string('api_version')
.notNullable()
.comment('The apiVersion field of the entity');
table
.string('kind')
.notNullable()
.comment('The kind field of the entity');
table
.string('name')
.nullable()
.comment('The metadata.name field of the entity');
table
.string('namespace')
.nullable()
.comment('The metadata.namespace field of the entity');
table
.text('metadata')
.notNullable()
.comment('The entire metadata JSON blob of the entity');
table
.text('spec')
.nullable()
.comment('The entire spec JSON blob of the entity');
})
.alterTable('entities', table => {
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta
table.unique(['kind', 'name', 'namespace'], 'entities_unique_name');
});
await knex.schema.raw(`INSERT INTO entities SELECT * FROM tmp_entities`);
//
// entities_search
//
await knex.schema.createTable('entities_search', table => {
table.comment(
'Flattened key-values from the entities, used for quick filtering',
);
table
.uuid('entity_id')
.references('id')
.inTable('entities')
.onDelete('CASCADE')
.comment('The entity that matches this key/value');
table
.string('key')
.notNullable()
.comment('A key that occurs in the entity');
table
.string('value')
.nullable()
.comment('The corresponding value to match on');
});
await knex.schema.raw(
`INSERT INTO entities_search SELECT * FROM tmp_entities_search`,
);
// Clean up
await knex.schema.dropTable('tmp_entities');
return knex.schema.dropTable('tmp_entities_search');
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
// SQLite does not support FK and PK
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities_search', table => {
table.dropForeign(['entity_id']);
});
await knex.schema.alterTable('entities', table => {
table.dropPrimary('entities_pkey');
});
}
await knex.schema.alterTable('entities', table => {
table.dropUnique([], 'entities_unique_name');
});
// Setup temporary tables
await knex.schema.renameTable('entities_search', 'tmp_entities_search');
await knex.schema.renameTable('entities', 'tmp_entities');
//
// entities
//
await knex.schema
.createTable('entities', table => {
table.comment('All entities currently stored in the catalog');
table.uuid('id').primary().comment('Auto-generated ID of the entity');
table
.uuid('location_id')
.references('id')
.inTable('locations')
.nullable()
.comment('The location that originated the entity');
table
.string('etag')
.notNullable()
.comment(
'An opaque string that changes for each update operation to any part of the entity, including metadata.',
);
table
.string('generation')
.notNullable()
.unsigned()
.comment(
'A positive nonzero number that indicates the current generation of data for this entity; the value is incremented each time the spec changes.',
);
table
.string('api_version')
.notNullable()
.comment('The apiVersion field of the entity');
table
.string('kind')
.notNullable()
.comment('The kind field of the entity');
table
.string('name')
.nullable()
.comment('The metadata.name field of the entity');
table
.string('namespace')
.nullable()
.comment('The metadata.namespace field of the entity');
table
.string('metadata')
.notNullable()
.comment('The entire metadata JSON blob of the entity');
table
.string('spec')
.nullable()
.comment('The entire spec JSON blob of the entity');
})
.alterTable('entities', table => {
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta
table.unique(['kind', 'name', 'namespace'], 'entities_unique_name');
});
await knex.schema.raw(`INSERT INTO entities SELECT * FROM tmp_entities`);
//
// entities_search
//
await knex.schema.createTable('entities_search', table => {
table.comment(
'Flattened key-values from the entities, used for quick filtering',
);
table
.uuid('entity_id')
.references('id')
.inTable('entities')
.onDelete('CASCADE')
.comment('The entity that matches this key/value');
table
.string('key')
.notNullable()
.comment('A key that occurs in the entity');
table
.string('value')
.nullable()
.comment('The corresponding value to match on');
});
await knex.schema.raw(
`INSERT INTO entities_search SELECT * FROM tmp_entities_search`,
);
// Clean up
await knex.schema.dropTable('tmp_entities');
return knex.schema.dropTable('tmp_entities_search');
};
@@ -0,0 +1,44 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = function up(knex) {
return knex.schema.raw(`DROP VIEW location_update_log_latest;`).raw(`
CREATE VIEW location_update_log_latest AS
SELECT t1.* FROM location_update_log t1
JOIN
(
SELECT location_id, MAX(created_at) AS MAXDATE
FROM location_update_log
GROUP BY location_id
) t2
ON t1.location_id = t2.location_id
AND t1.created_at = t2.MAXDATE
GROUP BY t1.location_id, t1.id
ORDER BY created_at DESC;
`);
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = function down(knex) {
knex.schema.raw(`DROP VIEW location_update_log_latest;`);
};
@@ -0,0 +1,87 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = function up(knex) {
return knex.schema
.raw('DROP VIEW location_update_log_latest;')
.dropTable('location_update_log')
.createTable('location_update_log', table => {
table.bigIncrements('id').primary(); // instead of uuid, so we can MAX it
table.enum('status', ['success', 'fail']).notNullable();
table.dateTime('created_at').defaultTo(knex.fn.now()).notNullable();
table.string('message');
table
.uuid('location_id')
.references('id')
.inTable('locations')
.onUpdate('CASCADE')
.onDelete('CASCADE');
table.string('entity_name').nullable();
}).raw(`
CREATE VIEW location_update_log_latest AS
SELECT t1.* FROM location_update_log t1
JOIN
(
SELECT location_id, MAX(id) AS MAXID
FROM location_update_log
GROUP BY location_id
) t2
ON t1.location_id = t2.location_id
AND t1.id = t2.MAXID
GROUP BY t1.location_id, t1.id
ORDER BY created_at DESC;
`);
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = function down(knex) {
return knex.schema
.raw('DROP VIEW location_update_log_latest;')
.dropTable('location_update_log')
.createTable('location_update_log', table => {
table.uuid('id').primary();
table.enum('status', ['success', 'fail']).notNullable();
table.dateTime('created_at').defaultTo(knex.fn.now()).notNullable();
table.string('message');
table
.uuid('location_id')
.references('id')
.inTable('locations')
.onUpdate('CASCADE')
.onDelete('CASCADE');
table.string('entity_name').nullable();
}).raw(`
CREATE VIEW location_update_log_latest AS
SELECT t1.* FROM location_update_log t1
JOIN
(
SELECT location_id, MAX(created_at) AS MAXDATE
FROM location_update_log
GROUP BY location_id
) t2
ON t1.location_id = t2.location_id
AND t1.created_at = t2.MAXDATE
GROUP BY t1.location_id, t1.id
ORDER BY created_at DESC;
`);
};
@@ -0,0 +1,41 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
// Sqlite does not support alter column.
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities_search', table => {
table.text('value').nullable().alter();
});
}
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
// Sqlite does not support alter column.
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities_search', table => {
table.string('value').nullable().alter();
});
}
};
@@ -0,0 +1,42 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
// Adds a single 'bootstrap' location that can be used to trigger work in processors.
// This is primarily here to fulfill foreign key constraints.
await knex('locations').insert({
id: require('uuid').v4(),
type: 'bootstrap',
target: 'bootstrap',
});
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
await knex('locations')
.where({
type: 'bootstrap',
target: 'bootstrap',
})
.del();
};
@@ -0,0 +1,32 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
await knex('entities')
.where({ namespace: null })
.update({ namespace: 'default' });
await knex('entities_search').update({
key: knex.raw('LOWER(key)'),
value: knex.raw('LOWER(value)'),
});
};
exports.down = async function down() {};
@@ -0,0 +1,60 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
await knex.schema.alterTable('entities', table => {
table.text('full_name').nullable();
});
await knex('entities').update({
full_name: knex.raw(
"LOWER(kind) || ':' || LOWER(COALESCE(namespace, 'default')) || '/' || LOWER(name)",
),
});
// SQLite does not support alter column
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities', table => {
table.text('full_name').notNullable().alter();
});
}
await knex.schema.alterTable('entities', table => {
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta
table.unique(['full_name'], 'entities_unique_full_name');
table.dropUnique([], 'entities_unique_name');
});
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
await knex.schema.alterTable('entities', table => {
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta
table.dropUnique([], 'entities_unique_full_name');
table.unique(['kind', 'namespace', 'name'], 'entities_unique_name');
});
await knex.schema.alterTable('entities_search', table => {
table.dropColumn('full_name');
});
};
@@ -0,0 +1,66 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
await knex.schema.alterTable('entities', table => {
table
.text('data')
.nullable()
.comment('The entire JSON data blob of the entity');
});
await knex('entities').update({
// apiVersion and kind should not contain any JSON unsafe chars, and both
// metadata and spec are already valid serialized JSON
data: knex.raw(
`'{"apiVersion":"' || api_version || '","kind":"' || kind || '","metadata":' || metadata || COALESCE(',"spec":' || spec, '') || '}'`,
),
});
await knex.schema.alterTable('entities', table => {
table.dropColumn('metadata');
table.dropColumn('spec');
});
// SQLite does not support ALTER COLUMN.
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities', table => {
table.text('data').notNullable().alter();
});
}
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
await knex.schema.alterTable('entities', table => {
table
.text('metadata')
.notNullable()
.comment('The entire metadata JSON blob of the entity');
table
.text('spec')
.nullable()
.comment('The entire spec JSON blob of the entity');
table.dropColumn('data');
});
};
@@ -0,0 +1,50 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
await knex.schema.alterTable('entities', table => {
table.dropColumn('api_version');
table.dropColumn('kind');
table.dropColumn('name');
table.dropColumn('namespace');
});
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
await knex.schema.alterTable('entities', table => {
table
.string('api_version')
.notNullable()
.comment('The apiVersion field of the entity');
table.string('kind').notNullable().comment('The kind field of the entity');
table
.string('name')
.nullable()
.comment('The metadata.name field of the entity');
table
.string('namespace')
.nullable()
.comment('The metadata.namespace field of the entity');
});
};
@@ -0,0 +1,37 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
await knex.schema.alterTable('entities_search', table => {
table.index(['key'], 'entities_search_key');
table.index(['value'], 'entities_search_value');
});
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
await knex.schema.alterTable('entities_search', table => {
table.dropIndex('', 'entities_search_key');
table.dropIndex('', 'entities_search_value');
});
};
@@ -0,0 +1,54 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
await knex.schema.createTable('entities_relations', table => {
table.comment('All relations between entities in the catalog');
table
.uuid('originating_entity_id')
.references('id')
.inTable('entities')
.onDelete('CASCADE')
.notNullable()
.comment('The entity that provided the relation');
table
.string('source_full_name')
.notNullable()
.comment('The full name of the source entity of the relation');
table
.string('type')
.notNullable()
.comment('The type of the relation between the entities');
table
.string('target_full_name')
.notNullable()
.comment('The full name of the target entity of the relation');
table.primary(['source_full_name', 'type', 'target_full_name']);
});
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
await knex.schema.dropTable('entities_relations');
};
@@ -0,0 +1,93 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
if (knex.client.config.client === 'sqlite3') {
// sqlite doesn't support dropPrimary so we recreate it properly instead
await knex.schema.dropTable('entities_relations');
await knex.schema.createTable('entities_relations', table => {
table.comment('All relations between entities in the catalog');
table
.uuid('originating_entity_id')
.references('id')
.inTable('entities')
.onDelete('CASCADE')
.notNullable()
.comment('The entity that provided the relation');
table
.string('source_full_name')
.notNullable()
.comment('The full name of the source entity of the relation');
table
.string('type')
.notNullable()
.comment('The type of the relation between the entities');
table
.string('target_full_name')
.notNullable()
.comment('The full name of the target entity of the relation');
table.index('source_full_name', 'source_full_name_idx');
});
} else {
await knex.schema.alterTable('entities_relations', table => {
table.dropPrimary();
table.index('source_full_name', 'source_full_name_idx');
});
}
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
if (knex.client.config.client === 'sqlite3') {
await knex.schema.dropTable('entities_relations');
await knex.schema.createTable('entities_relations', table => {
table.comment('All relations between entities in the catalog');
table
.uuid('originating_entity_id')
.references('id')
.inTable('entities')
.onDelete('CASCADE')
.notNullable()
.comment('The entity that provided the relation');
table
.string('source_full_name')
.notNullable()
.comment('The full name of the source entity of the relation');
table
.string('type')
.notNullable()
.comment('The type of the relation between the entities');
table
.string('target_full_name')
.notNullable()
.comment('The full name of the target entity of the relation');
table.primary(['source_full_name', 'type', 'target_full_name']);
});
} else {
await knex.schema.alterTable('entities_relations', table => {
table.dropIndex([], 'source_full_name_idx');
table.primary(['source_full_name', 'type', 'target_full_name']);
});
}
};
@@ -0,0 +1,45 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities_relations', table => {
table.index('originating_entity_id', 'originating_entity_id_idx');
});
await knex.schema.alterTable('entities_search', table => {
table.index('entity_id', 'entity_id_idx');
});
}
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities_relations', table => {
table.dropIndex([], 'originating_entity_id_idx');
});
await knex.schema.alterTable('entities_relations', table => {
table.dropIndex([], 'entity_id_idx');
});
}
};
@@ -0,0 +1,73 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
if (knex.client.config.client !== 'sqlite3') {
// We actually just want to widen columns, but can't do that while a
// view is dependent on them - so we just reconstruct it exactly as it was
await knex.schema
.raw('DROP VIEW location_update_log_latest;')
.alterTable('location_update_log', table => {
table.text('message').alter();
table.text('entity_name').nullable().alter();
}).raw(`
CREATE VIEW location_update_log_latest AS
SELECT t1.* FROM location_update_log t1
JOIN
(
SELECT location_id, MAX(id) AS MAXID
FROM location_update_log
GROUP BY location_id
) t2
ON t1.location_id = t2.location_id
AND t1.id = t2.MAXID
GROUP BY t1.location_id, t1.id
ORDER BY created_at DESC;
`);
}
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
if (knex.client.config.client !== 'sqlite3') {
await knex.schema
.raw('DROP VIEW location_update_log_latest;')
.alterTable('location_update_log', table => {
table.string('message').alter();
table.string('entity_name').nullable().alter();
}).raw(`
CREATE VIEW location_update_log_latest AS
SELECT t1.* FROM location_update_log t1
JOIN
(
SELECT location_id, MAX(id) AS MAXID
FROM location_update_log
GROUP BY location_id
) t2
ON t1.location_id = t2.location_id
AND t1.id = t2.MAXID
GROUP BY t1.location_id, t1.id
ORDER BY created_at DESC;
`);
}
};
@@ -0,0 +1,45 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
/**
* @param {import('knex').Knex} knex
*/
exports.up = async function up(knex) {
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities', table => {
table.index('location_id', 'entity_location_id_idx');
});
await knex.schema.alterTable('location_update_log', table => {
table.index('location_id', 'update_log_location_id_idx');
});
}
};
/**
* @param {import('knex').Knex} knex
*/
exports.down = async function down(knex) {
if (knex.client.config.client !== 'sqlite3') {
await knex.schema.alterTable('entities', table => {
table.dropIndex([], 'entity_location_id_idx');
});
await knex.schema.alterTable('location_update_log', table => {
table.dropIndex([], 'update_log_location_id_idx');
});
}
};
@@ -20,7 +20,6 @@ import { v4 as uuidv4 } from 'uuid';
import { Logger } from 'winston';
import { CommonDatabase } from '../../database/CommonDatabase';
import { Database } from '../../database/types';
import fs from 'fs-extra';
export type CreateDatabaseOptions = {
logger: Logger;
@@ -35,16 +34,10 @@ export class DatabaseManager {
knex: Knex,
options: Partial<CreateDatabaseOptions> = {},
): Promise<Database> {
const allMigrations = resolvePackagePath(
'@backstage/plugin-catalog-backend',
'migrations',
);
const migrationsDir = resolvePackagePath(
'@backstage/plugin-catalog-backend',
'migrationsv2',
);
await fs.copy(allMigrations, migrationsDir);
await knex.migrate.latest({
directory: migrationsDir,
@@ -79,14 +72,6 @@ export class DatabaseManager {
public static async createTestDatabaseConnection(): Promise<Knex> {
const config: Knex.Config<any> = {
/*
client: 'pg',
connection: {
host: 'localhost',
user: 'postgres',
password: 'postgres',
},
*/
client: 'sqlite3',
connection: ':memory:',
useNullAsDefault: true,