2023-12-18 17:38:25 +01:00
|
|
|
import { DataSource, QueryRunner } from 'typeorm';
|
2023-03-30 21:38:55 +02:00
|
|
|
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
|
2022-02-03 17:06:44 +01:00
|
|
|
|
2023-01-27 03:52:13 +01:00
|
|
|
const url = process.env.DB_URL;
|
|
|
|
const urlOrParts = url
|
|
|
|
? { url }
|
|
|
|
: {
|
2023-01-27 21:50:07 +01:00
|
|
|
host: process.env.DB_HOSTNAME || 'localhost',
|
2023-01-27 03:52:13 +01:00
|
|
|
port: parseInt(process.env.DB_PORT || '5432'),
|
2023-01-27 21:50:07 +01:00
|
|
|
username: process.env.DB_USERNAME || 'postgres',
|
|
|
|
password: process.env.DB_PASSWORD || 'postgres',
|
|
|
|
database: process.env.DB_DATABASE_NAME || 'immich',
|
2023-01-27 03:52:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
export const databaseConfig: PostgresConnectionOptions = {
|
2022-02-03 17:06:44 +01:00
|
|
|
type: 'postgres',
|
2023-03-30 21:38:55 +02:00
|
|
|
entities: [__dirname + '/entities/*.entity.{js,ts}'],
|
2022-02-20 05:42:10 +01:00
|
|
|
synchronize: false,
|
2023-03-30 21:38:55 +02:00
|
|
|
migrations: [__dirname + '/migrations/*.{js,ts}'],
|
2023-08-24 21:28:50 +02:00
|
|
|
subscribers: [__dirname + '/subscribers/*.{js,ts}'],
|
2022-02-20 05:42:10 +01:00
|
|
|
migrationsRun: true,
|
2023-01-14 16:06:59 +01:00
|
|
|
connectTimeoutMS: 10000, // 10 seconds
|
2023-01-27 03:52:13 +01:00
|
|
|
...urlOrParts,
|
2022-02-03 17:06:44 +01:00
|
|
|
};
|
2022-06-06 18:16:03 +02:00
|
|
|
|
2023-03-30 21:38:55 +02:00
|
|
|
// this export is used by TypeORM commands in package.json#scripts
|
2022-07-04 21:20:43 +02:00
|
|
|
export const dataSource = new DataSource(databaseConfig);
|
2023-12-08 17:15:46 +01:00
|
|
|
|
2023-12-18 17:38:25 +01:00
|
|
|
export async function databaseChecks() {
|
2023-12-08 17:15:46 +01:00
|
|
|
if (!dataSource.isInitialized) {
|
|
|
|
await dataSource.initialize();
|
|
|
|
}
|
2023-12-18 17:38:25 +01:00
|
|
|
|
|
|
|
await assertVectors(dataSource);
|
|
|
|
await enablePrefilter(dataSource);
|
|
|
|
await dataSource.runMigrations();
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function enablePrefilter(runner: DataSource | QueryRunner) {
|
|
|
|
await runner.query(`SET vectors.enable_prefilter = on`);
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function getExtensionVersion(extName: string, runner: DataSource | QueryRunner): Promise<string | null> {
|
|
|
|
const res = await runner.query(`SELECT extversion FROM pg_extension WHERE extname = $1`, [extName]);
|
|
|
|
return res[0]?.['extversion'] ?? null;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function getPostgresVersion(runner: DataSource | QueryRunner): Promise<string> {
|
|
|
|
const res = await runner.query(`SHOW server_version`);
|
|
|
|
return res[0]['server_version'].split('.')[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function assertVectors(runner: DataSource | QueryRunner) {
|
|
|
|
const postgresVersion = await getPostgresVersion(runner);
|
|
|
|
const expected = ['0.1.1', '0.1.11'];
|
|
|
|
const image = `tensorchord/pgvecto-rs:pg${postgresVersion}-v${expected[expected.length - 1]}`;
|
|
|
|
|
|
|
|
await runner.query('CREATE EXTENSION IF NOT EXISTS vectors').catch((err) => {
|
|
|
|
console.error(
|
|
|
|
'Failed to create pgvecto.rs extension. ' +
|
|
|
|
`If you have not updated your Postgres instance to an image that supports pgvecto.rs (such as '${image}'), please do so. ` +
|
|
|
|
'See the v1.91.0 release notes for more info: https://github.com/immich-app/immich/releases/tag/v1.91.0',
|
|
|
|
);
|
|
|
|
throw err;
|
|
|
|
});
|
|
|
|
|
|
|
|
const version = await getExtensionVersion('vectors', runner);
|
|
|
|
if (version != null && !expected.includes(version)) {
|
|
|
|
throw new Error(
|
|
|
|
`The pgvecto.rs extension version is ${version} instead of the expected version ${
|
|
|
|
expected[expected.length - 1]
|
|
|
|
}.` + `If you're using the 'latest' tag, please switch to '${image}'.`,
|
|
|
|
);
|
|
|
|
}
|
2023-12-08 17:15:46 +01:00
|
|
|
}
|