Migrate to a monorepo structure (#2909)
This commit is contained in:
4
packages/twenty-server/scripts/render-run.sh
Executable file
4
packages/twenty-server/scripts/render-run.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
export PG_DATABASE_URL=postgres://twenty:twenty@$PG_DATABASE_HOST:$PG_DATABASE_PORT/default
|
||||
yarn database:setup
|
||||
node dist/src/main
|
||||
8
packages/twenty-server/scripts/run-integration.sh
Executable file
8
packages/twenty-server/scripts/run-integration.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# scripts/run-integration.sh
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source $DIR/set-env-test.sh
|
||||
|
||||
yarn database:init
|
||||
yarn jest --config ./test/jest-e2e.json
|
||||
25
packages/twenty-server/scripts/set-env-test.sh
Executable file
25
packages/twenty-server/scripts/set-env-test.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# scripts/set-env-test.sh
|
||||
|
||||
# Get script's directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Construct the absolute path of .env file in the project root directory
|
||||
ENV_PATH="${SCRIPT_DIR}/../.env.test"
|
||||
|
||||
# Check if the file exists
|
||||
if [ -f "${ENV_PATH}" ]; then
|
||||
echo "🔵 - Loading environment variables from "${ENV_PATH}"..."
|
||||
# Export env vars
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
if echo "$line" | grep -F = &>/dev/null
|
||||
then
|
||||
varname=$(echo "$line" | cut -d '=' -f 1)
|
||||
varvalue=$(echo "$line" | cut -d '=' -f 2- | cut -d '#' -f 1)
|
||||
export "$varname"="$varvalue"
|
||||
fi
|
||||
done < <(grep -v '^#' "${ENV_PATH}")
|
||||
else
|
||||
echo "Error: ${ENV_PATH} does not exist."
|
||||
exit 1
|
||||
fi
|
||||
93
packages/twenty-server/scripts/setup-db.ts
Normal file
93
packages/twenty-server/scripts/setup-db.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import console from 'console';
|
||||
|
||||
import { camelToSnakeCase, connectionSource, performQuery } from './utils';
|
||||
|
||||
connectionSource
|
||||
.initialize()
|
||||
.then(async () => {
|
||||
await performQuery(
|
||||
'CREATE SCHEMA IF NOT EXISTS "public"',
|
||||
'create schema "public"',
|
||||
);
|
||||
await performQuery(
|
||||
'CREATE SCHEMA IF NOT EXISTS "metadata"',
|
||||
'create schema "metadata"',
|
||||
);
|
||||
await performQuery(
|
||||
'CREATE SCHEMA IF NOT EXISTS "core"',
|
||||
'create schema "core"',
|
||||
);
|
||||
await performQuery(
|
||||
'CREATE EXTENSION IF NOT EXISTS "pg_graphql"',
|
||||
'create extension pg_graphql',
|
||||
);
|
||||
|
||||
await performQuery(
|
||||
'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"',
|
||||
'create extension "uuid-ossp"',
|
||||
);
|
||||
|
||||
await performQuery(
|
||||
'CREATE EXTENSION IF NOT EXISTS "postgres_fdw"',
|
||||
'create extension "postgres_fdw"',
|
||||
);
|
||||
|
||||
await performQuery(
|
||||
'CREATE EXTENSION IF NOT EXISTS "wrappers"',
|
||||
'create extension "wrappers"',
|
||||
);
|
||||
|
||||
const supabaseWrappers = [
|
||||
'airtable',
|
||||
'bigQuery',
|
||||
'clickHouse',
|
||||
'firebase',
|
||||
'logflare',
|
||||
's3',
|
||||
'stripe',
|
||||
]; // See https://supabase.github.io/wrappers/
|
||||
|
||||
for (const wrapper of supabaseWrappers) {
|
||||
await performQuery(
|
||||
`
|
||||
CREATE FOREIGN DATA WRAPPER "${wrapper.toLowerCase()}_fdw"
|
||||
HANDLER "${camelToSnakeCase(wrapper)}_fdw_handler"
|
||||
VALIDATOR "${camelToSnakeCase(wrapper)}_fdw_validator";
|
||||
`,
|
||||
`create ${wrapper} "wrappers"`,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
await performQuery(
|
||||
`COMMENT ON SCHEMA "core" IS '@graphql({"inflect_names": true})';`,
|
||||
'inflect names for graphql',
|
||||
);
|
||||
|
||||
await performQuery(
|
||||
`
|
||||
DROP FUNCTION IF EXISTS graphql;
|
||||
CREATE FUNCTION graphql(
|
||||
"operationName" text default null,
|
||||
query text default null,
|
||||
variables jsonb default null,
|
||||
extensions jsonb default null
|
||||
)
|
||||
returns jsonb
|
||||
language sql
|
||||
as $$
|
||||
select graphql.resolve(
|
||||
query := query,
|
||||
variables := coalesce(variables, '{}'),
|
||||
"operationName" := "operationName",
|
||||
extensions := extensions
|
||||
);
|
||||
$$;
|
||||
`,
|
||||
'create function graphql',
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error during Data Source initialization:', err);
|
||||
});
|
||||
32
packages/twenty-server/scripts/truncate-db.ts
Normal file
32
packages/twenty-server/scripts/truncate-db.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import console from 'console';
|
||||
|
||||
import { connectionSource, performQuery } from './utils';
|
||||
|
||||
connectionSource
|
||||
.initialize()
|
||||
.then(async () => {
|
||||
await performQuery(
|
||||
`
|
||||
CREATE OR REPLACE FUNCTION drop_all() RETURNS VOID AS $$
|
||||
DECLARE schema_item RECORD;
|
||||
BEGIN
|
||||
FOR schema_item IN
|
||||
SELECT subrequest."name" as schema_name
|
||||
FROM (SELECT n.nspname AS "name"
|
||||
FROM pg_catalog.pg_namespace n
|
||||
WHERE n.nspname !~ '^pg_' AND n.nspname <> 'information_schema') as subrequest
|
||||
LOOP
|
||||
EXECUTE 'DROP SCHEMA ' || schema_item.schema_name || ' CASCADE';
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
SELECT drop_all ();
|
||||
`,
|
||||
'Dropping all schemas...',
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error during Data Source initialization:', err);
|
||||
});
|
||||
42
packages/twenty-server/scripts/utils.ts
Normal file
42
packages/twenty-server/scripts/utils.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import console from 'console';
|
||||
|
||||
import { config } from 'dotenv';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
config();
|
||||
const configService = new ConfigService();
|
||||
|
||||
export const connectionSource = new DataSource({
|
||||
type: 'postgres',
|
||||
logging: false,
|
||||
url: configService.get<string>('PG_DATABASE_URL'),
|
||||
});
|
||||
|
||||
export const camelToSnakeCase = (str) =>
|
||||
str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
||||
|
||||
export const performQuery = async (
|
||||
query: string,
|
||||
consoleDescription: string,
|
||||
withLog = true,
|
||||
ignoreAlreadyExistsError = false,
|
||||
) => {
|
||||
try {
|
||||
const result = await connectionSource.query(query);
|
||||
|
||||
withLog && console.log(`Performed '${consoleDescription}' successfully`);
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
let message = '';
|
||||
|
||||
if (ignoreAlreadyExistsError && `${err}`.includes('already exists')) {
|
||||
message = `Performed '${consoleDescription}' successfully`;
|
||||
} else {
|
||||
message = `Failed to perform '${consoleDescription}': ${err}`;
|
||||
}
|
||||
withLog && console.error(message);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user