This commit is contained in:
Benjamin Toby
2025-07-05 14:59:30 +01:00
parent 6e334c2525
commit 7e8bb37c09
526 changed files with 17560 additions and 11386 deletions
@@ -0,0 +1,47 @@
import fs from "fs";
import { SiteConfig } from "../../../types";
import grabDirNames from "../names/grab-dir-names";
import EJSON from "../../ejson";
import envsub from "../../envsub";
type Params = {
userId?: string | number;
};
type Return = {
appConfig: SiteConfig;
userConfig: SiteConfig | null;
};
export default function grabConfig(params?: Params): Return {
const { appConfigJSONFile, userConfigJSONFilePath } = grabDirNames({
userId: params?.userId,
});
const appConfigJSON = envsub(fs.readFileSync(appConfigJSONFile, "utf-8"));
const appConfig = EJSON.parse(appConfigJSON) as SiteConfig;
if (!userConfigJSONFilePath) {
return { appConfig, userConfig: null };
}
if (!fs.existsSync(userConfigJSONFilePath)) {
fs.writeFileSync(
userConfigJSONFilePath,
JSON.stringify({
main: {},
}),
"utf-8"
);
}
const userConfigJSON = envsub(
fs.readFileSync(userConfigJSONFilePath, "utf-8")
);
const userConfig = (EJSON.parse(userConfigJSON) || {
main: {},
}) as SiteConfig;
return { appConfig, userConfig };
}
@@ -0,0 +1,18 @@
import { SiteConfigMain } from "../../../types";
import grabConfig from "./grab-config";
type Params = {
userId?: string | number;
};
type Return = {
appMainConfig: SiteConfigMain;
userMainConfig?: SiteConfigMain;
};
export default function grabMainConfig(params?: Params): Return {
const { appConfig } = grabConfig();
const { userConfig } = grabConfig({ userId: params?.userId });
return { appMainConfig: appConfig.main, userMainConfig: userConfig?.main };
}
@@ -0,0 +1,50 @@
import fs from "fs";
import grabDirNames from "../names/grab-dir-names";
import grabConfig from "./grab-config";
import _ from "lodash";
import { SiteConfig } from "../../../types";
type Params = {
userId?: string | number;
newConfig?: SiteConfig;
};
type Return = {
success?: boolean;
msg?: string;
};
export default function updateUserConfig({
newConfig,
userId,
}: Params): Return {
if (!userId || !newConfig) {
return {
success: false,
msg: `UserID or newConfig not provided`,
};
}
const { userConfigJSONFilePath } = grabDirNames({
userId,
});
if (!userConfigJSONFilePath || !fs.existsSync(userConfigJSONFilePath)) {
return {
success: false,
msg: `userConfigJSONFilePath not found!`,
};
}
const { userConfig: existingUserConfig } = grabConfig({ userId });
const updateConfig = _.merge(existingUserConfig, newConfig);
fs.writeFileSync(
userConfigJSONFilePath,
JSON.stringify(updateConfig),
"utf-8"
);
return { success: true };
}
@@ -1,22 +0,0 @@
import { DATASQUIREL_LoggedInUser, UserType } from "../../../types";
type Param = {
user?: DATASQUIREL_LoggedInUser | UserType;
userId?: string | number | null;
dbSlug?: string;
};
export default function grabUserDbFullName({ dbSlug, user, userId }: Param) {
const finalUserId = user?.id || userId;
if (!finalUserId || !dbSlug)
throw new Error(
`Couldn't grab full DB name. Missing parameters finalUserId || dbSlug`
);
if (dbSlug.match(/[^a-zA-Z0-9-_]/)) {
throw new Error(`Invalid Database slug`);
}
return `datasquirel_user_${finalUserId}_${dbSlug}`;
}
@@ -5,24 +5,69 @@ type Param = {
user?: DATASQUIREL_LoggedInUser | UserType;
userId?: string | number | null;
appDir?: string;
dataDir?: string;
};
export default function grabDirNames(param?: Param) {
const appDir = param?.appDir || process.env.DSQL_APP_DIR;
const STATIC_ROOT = process.env.DSQL_STATIC_SERVER_DIR || "/static";
const DATA_DIR = param?.dataDir || process.env.DSQL_DATA_DIR || "/data";
const finalUserId = param?.user?.id || param?.userId;
const publicImagesDir = path.join(STATIC_ROOT, `images`);
if (!appDir)
throw new Error("Please provide the `DSQL_APP_DIR` env variable.");
const schemasDir =
process.env.DSQL_DB_SCHEMA_DIR ||
path.join(appDir, "jsonData", "dbSchemas");
if (!DATA_DIR)
throw new Error("Please provide the `DATA_DIR` env variable.");
const STATIC_ROOT = path.join(DATA_DIR, "static");
const publicImagesDir = path.join(STATIC_ROOT, `images`);
const publicDir = path.join(appDir, "public");
const publicSSLDir = path.join(publicDir, "documents", "ssl");
const appSSLDir = path.join(appDir, "ssl");
const mainSSLDir = path.join(DATA_DIR, "ssl");
const privateDataDir = path.join(DATA_DIR, "private");
/**
* # DB Dir names
* @description Database related Directories
*/
const mainDbDataDir = path.join(DATA_DIR, "db");
const mainDbGrastateDatFile = path.join(mainDbDataDir, "grastate.dat");
const replica1DbDataDir = path.join(DATA_DIR, "replica-1");
const mariadbMainConfigDir = path.join(DATA_DIR, "db-config", "main");
const mariadbReplicaConfigDir = path.join(DATA_DIR, "db-config", "replica");
const maxscaleConfigDir = path.join(DATA_DIR, "db-config", "maxscale");
const mariadbMainConfigFile = path.join(
mariadbMainConfigDir,
"default.cnf"
);
const mariadbReplicaConfigFile = path.join(
mariadbReplicaConfigDir,
"default.cnf"
);
const galeraConfigFile = path.join(mariadbMainConfigDir, "galera.cnf");
const galeraReplicaConfigFile = path.join(
mariadbReplicaConfigDir,
"galera.cnf"
);
const maxscaleConfigFile = path.join(maxscaleConfigDir, "maxscale.cnf");
/**
* # Schema Dir names
* @description
*/
const oldSchemasDir = path.join(appDir, "jsonData", "dbSchemas");
const appSchemaJSONFile = path.join(oldSchemasDir, "1.json");
const tempDirName = ".tmp";
if (!schemasDir)
const appConfigDir = path.join(appDir, "jsonData", "config");
const appConfigJSONFile = path.join(appConfigDir, "app-config.json");
if (!privateDataDir)
throw new Error(
"Please provide the `DSQL_DB_SCHEMA_DIR` env variable."
);
@@ -30,31 +75,35 @@ export default function grabDirNames(param?: Param) {
const pakageSharedDir = path.join(appDir, `package-shared`);
const mainDbTypeDefFile = path.join(pakageSharedDir, `types/dsql.ts`);
const mainShemaJSONFilePath = path.join(schemasDir, `main.json`);
const mainShemaJSONFilePath = path.join(oldSchemasDir, `main.json`);
const defaultTableFieldsJSONFilePath = path.join(
pakageSharedDir,
`data/defaultFields.json`
);
const usersSchemaDir = path.join(schemasDir, `users`);
const targetUserSchemaDir = finalUserId
const usersSchemaDir = path.join(privateDataDir, `users`);
const targetUserPrivateDir = finalUserId
? path.join(usersSchemaDir, `user-${finalUserId}`)
: undefined;
const userTempSQLFilePath = targetUserSchemaDir
? path.join(targetUserSchemaDir, `tmp.sql`)
const userTempSQLFilePath = targetUserPrivateDir
? path.join(targetUserPrivateDir, `tmp.sql`)
: undefined;
const userMainShemaJSONFilePath = targetUserPrivateDir
? path.join(targetUserPrivateDir, `main.json`)
: undefined;
const userDirPath = finalUserId
? path.join(usersSchemaDir, `user-${finalUserId}`)
const userConfigJSONFilePath = targetUserPrivateDir
? path.join(targetUserPrivateDir, `config.json`)
: undefined;
const userSchemaMainJSONFilePath = userDirPath
? path.join(userDirPath, `main.json`)
const userSchemaMainJSONFilePath = targetUserPrivateDir
? path.join(targetUserPrivateDir, `main.json`)
: undefined;
const userPrivateMediaDir = userDirPath
? path.join(userDirPath, `media`)
const userPrivateMediaDir = targetUserPrivateDir
? path.join(targetUserPrivateDir, `media`)
: undefined;
const userPrivateExportsDir = userDirPath
? path.join(userDirPath, `export`)
const userPrivateExportsDir = targetUserPrivateDir
? path.join(targetUserPrivateDir, `export`)
: undefined;
const userPrivateSQLExportsDir = userPrivateExportsDir
? path.join(userPrivateExportsDir, `sql`)
@@ -91,6 +140,8 @@ export default function grabDirNames(param?: Param) {
appDir,
"test.docker-compose.yaml"
);
const dbDockerComposeFile = path.join(appDir, "db.docker-compose.yml");
const dbDockerComposeFileAlt = path.join(appDir, "db.docker-compose.yaml");
const extraDockerComposeFile = path.join(
appDir,
"extra.docker-compose.yml"
@@ -105,16 +156,29 @@ export default function grabDirNames(param?: Param) {
const envFile = path.join(appDir, ".env");
const testEnvFile = path.join(appDir, "test.env");
/**
* # Backup Dir names
* @description
*/
const mainBackupDir = path.join(DATA_DIR, "backups");
const userBackupDir = targetUserPrivateDir
? path.join(targetUserPrivateDir, `backups`)
: undefined;
const sqlBackupDirName = `sql`;
const schemasBackupDirName = `schema`;
return {
appDir,
schemasDir,
userDirPath,
privateDataDir,
oldSchemasDir,
userConfigJSONFilePath,
mainShemaJSONFilePath,
mainDbTypeDefFile,
tempDirName,
defaultTableFieldsJSONFilePath,
usersSchemaDir,
targetUserSchemaDir,
targetUserPrivateDir,
userSchemaMainJSONFilePath,
userPrivateMediaDir,
userPrivateExportsDir,
@@ -137,5 +201,32 @@ export default function grabDirNames(param?: Param) {
testEnvFile,
userPublicMediaDir,
userTempSQLFilePath,
STATIC_ROOT,
appConfigJSONFile,
appConfigDir,
mariadbMainConfigDir,
mariadbMainConfigFile,
maxscaleConfigDir,
mariadbReplicaConfigDir,
DATA_DIR,
publicDir,
publicSSLDir,
appSSLDir,
maxscaleConfigFile,
mariadbReplicaConfigFile,
mainSSLDir,
mainDbDataDir,
replica1DbDataDir,
galeraConfigFile,
galeraReplicaConfigFile,
dbDockerComposeFile,
dbDockerComposeFileAlt,
mainDbGrastateDatFile,
appSchemaJSONFile,
mainBackupDir,
userBackupDir,
sqlBackupDirName,
schemasBackupDirName,
userMainShemaJSONFilePath,
};
}
@@ -0,0 +1,13 @@
import grabDockerResourceIPNumbers from "../../grab-docker-resource-ip-numbers";
export default function grabIPAddresses() {
const globalIPPrefix = process.env.DSQL_NETWORK_IP_PREFIX || "172.72.0";
const { cron, db, maxscale, postDbSetup, web } =
grabDockerResourceIPNumbers();
const webAppIP = `${globalIPPrefix}.${web}`;
const appCronIP = `${globalIPPrefix}.${cron}`;
const maxScaleIP = `${globalIPPrefix}.${maxscale}`;
return { webAppIP, appCronIP, maxScaleIP, globalIPPrefix };
}
+74
View File
@@ -0,0 +1,74 @@
import * as http from "http";
import { CookieOptions } from "../types";
import { CookieNames } from "../dict/cookie-names";
export function setCookie(
res: http.ServerResponse,
name: (typeof CookieNames)[keyof typeof CookieNames],
value: string,
options: CookieOptions = {}
): void {
const cookieParts: string[] = [
`${encodeURIComponent(name)}=${encodeURIComponent(value)}`,
];
if (options.expires) {
cookieParts.push(`Expires=${options.expires.toUTCString()}`);
}
if (options.maxAge !== undefined) {
cookieParts.push(`Max-Age=${options.maxAge}`);
}
if (options.path) {
cookieParts.push(`Path=${options.path}`);
}
if (options.domain) {
cookieParts.push(`Domain=${options.domain}`);
}
if (options.secure) {
cookieParts.push("Secure");
}
if (options.httpOnly) {
cookieParts.push("HttpOnly");
}
res.setHeader("Set-Cookie", cookieParts.join("; "));
}
export function getCookie(
req: http.IncomingMessage,
name: (typeof CookieNames)[keyof typeof CookieNames]
): string | null {
const cookieHeader = req.headers.cookie;
if (!cookieHeader) return null;
const cookies = cookieHeader
.split(";")
.reduce((acc: { [key: string]: string }, cookie: string) => {
const [key, val] = cookie.trim().split("=").map(decodeURIComponent);
acc[key] = val;
return acc;
}, {});
return cookies[name] || null;
}
export function updateCookie(
res: http.ServerResponse,
name: (typeof CookieNames)[keyof typeof CookieNames],
value: string,
options: CookieOptions = {}
): void {
setCookie(res, name, value, options);
}
export function deleteCookie(
res: http.ServerResponse,
name: (typeof CookieNames)[keyof typeof CookieNames],
options: CookieOptions = {}
): void {
setCookie(res, name, "", {
...options,
expires: new Date(0),
maxAge: 0,
});
}
@@ -0,0 +1,72 @@
import { generate } from "generate-password";
import dbHandler from "../functions/backend/dbHandler";
import dsqlCrud from "./data-fetching/crud";
import { DSQL_DATASQUIREL_USERS, DsqlTables } from "../types/dsql";
import encrypt from "../functions/dsql/encrypt";
import { UserType } from "../types";
import grabUserMainSqlUserName from "./grab-user-main-sql-user-name";
import grabDbNames from "./grab-db-names";
import { createNewSQLUser } from "../functions/web-app/mariadb-user/handle-mariadb-user-creation";
type Params = {
user: UserType;
};
type Return = {
fullName?: string;
host?: string;
username?: string;
password?: string;
};
export default async function createUserSQLUser(user: UserType) {
const {
fullName,
host,
username: mariaDBUsername,
webHost,
} = grabUserMainSqlUserName({ user });
const { userDbPrefix } = grabDbNames({ user });
await dbHandler({
query: `DROP USER IF EXISTS '${mariaDBUsername}'@'${webHost}'`,
noErrorLogs: true,
});
const newPassword = generate({ length: 32 });
await createNewSQLUser({
host: webHost,
password: newPassword,
username: mariaDBUsername,
});
const updateWebHostGrants = (await dbHandler({
query: `GRANT ALL PRIVILEGES ON \`${userDbPrefix.replace(
/\_/g,
"\\_"
)}%\`.* TO '${mariaDBUsername}'@'${webHost}'`,
})) as any[];
const updateUser = await dsqlCrud<
DSQL_DATASQUIREL_USERS,
(typeof DsqlTables)[number]
>({
action: "update",
table: "users",
targetField: "id",
targetValue: user.id,
data: {
mariadb_host: webHost,
mariadb_pass: encrypt({ data: newPassword }) || undefined,
mariadb_user: mariaDBUsername,
},
});
return {
fullName,
host,
username: mariaDBUsername,
password: newPassword,
};
}
+17 -5
View File
@@ -1,19 +1,25 @@
import sqlGenerator from "../../functions/dsql/sql/sql-generator";
import { DsqlCrudParam } from "../../types";
import { APIResponseObject, DsqlCrudParam } from "../../types";
import connDbHandler, { ConnDBHandlerQueryObject } from "../db/conn-db-handler";
import { DsqlCrudReturn } from "./crud";
export default async function dsqlCrudGet({
export default async function <
T extends { [key: string]: any } = { [key: string]: any }
>({
table,
query,
count,
countOnly,
}: DsqlCrudParam<any>): Promise<DsqlCrudReturn> {
dbFullName,
}: Omit<
DsqlCrudParam<T>,
"action" | "data" | "sanitize"
>): Promise<APIResponseObject> {
let queryObject: ReturnType<Awaited<typeof sqlGenerator>> | undefined;
queryObject = sqlGenerator({
tableName: table,
genObject: query,
dbFullName,
});
const DB_CONN = global.DSQL_READ_ONLY_DB_CONN || global.DSQL_DB_CONN;
@@ -31,6 +37,7 @@ export default async function dsqlCrudGet({
tableName: table,
genObject: query,
count: true,
dbFullName,
})
: undefined;
@@ -55,8 +62,13 @@ export default async function dsqlCrudGet({
return {
success: isSuccess,
payload: isSuccess ? (countOnly ? null : res[0]) : null,
batchPayload: isSuccess ? (countOnly ? null : res) : null,
error: isSuccess ? undefined : res?.error,
queryObject,
errors: res?.errors,
queryObject: {
sql: queryObject?.string,
params: queryObject?.values,
},
count: isSuccess
? res[1]?.[0]?.["COUNT(*)"]
? res[1][0]["COUNT(*)"]
+67 -39
View File
@@ -1,20 +1,21 @@
import post from "../../actions/post";
import sqlDeleteGenerator from "../../functions/dsql/sql/sql-delete-generator";
import sqlGenerator from "../../functions/dsql/sql/sql-generator";
import { DsqlCrudParam, PostReturn } from "../../types";
// import dsqlCrudBatchGet from "./crud-batch-get";
import {
APIResponseObject,
DsqlCrudParam,
DSQLErrorObject,
PostInsertReturn,
PostReturn,
} from "../../types";
import dsqlCrudGet from "./crud-get";
export type DsqlCrudReturn =
| (PostReturn & {
queryObject?: ReturnType<Awaited<typeof sqlGenerator>>;
count?: number;
batchPayload?: any[][] | null;
})
| null;
import connDbHandler from "../db/conn-db-handler";
import addDbEntry from "../../functions/backend/db/addDbEntry";
import updateDbEntry from "../../functions/backend/db/updateDbEntry";
export default async function dsqlCrud<
T extends { [key: string]: any } = { [key: string]: any }
>(params: DsqlCrudParam<T>): Promise<DsqlCrudReturn> {
T extends { [key: string]: any } = { [key: string]: any },
K extends string = string
>(params: DsqlCrudParam<T, K>): Promise<APIResponseObject> {
const {
action,
data,
@@ -23,8 +24,17 @@ export default async function dsqlCrud<
sanitize,
targetField,
targetId,
dbFullName,
deleteData,
batchData,
deleteKeyValues,
} = params;
const finalData = sanitize ? sanitize(data) : data;
const finalData = (sanitize ? sanitize({ data }) : data) as T;
const finalBatchData = (
sanitize ? sanitize({ batchData }) : batchData
) as T[];
const DB_CONN = global.DSQL_READ_ONLY_DB_CONN || global.DSQL_DB_CONN;
switch (action) {
case "get":
@@ -34,41 +44,59 @@ export default async function dsqlCrud<
// return await dsqlCrudBatchGet(params);
case "insert":
return await post({
query: {
action: "insert",
table,
data: finalData,
},
forceLocal: true,
const INSERT_RESULT = await addDbEntry({
data: finalData,
batchData: finalBatchData,
tableName: table,
dbFullName,
});
return INSERT_RESULT;
case "update":
delete data?.id;
return await post({
query: {
action: "update",
table,
identifierColumnName: targetField || "id",
identifierValue: String(targetValue || targetId),
data: finalData,
},
forceLocal: true,
const UPDATE_RESULT = await updateDbEntry({
data: finalData,
tableName: table,
dbFullName,
identifierColumnName: (targetField || "id") as string,
identifierValue: String(targetValue || targetId),
});
return UPDATE_RESULT;
case "delete":
return await post({
query: {
action: "delete",
table,
identifierColumnName: targetField || "id",
identifierValue: String(targetValue || targetId),
},
forceLocal: true,
const deleteQuery = sqlDeleteGenerator({
data: targetId
? { id: targetId }
: targetField && targetValue
? { [targetField]: targetValue }
: deleteData,
tableName: table,
dbFullName,
deleteKeyValues,
});
const res = (await connDbHandler(
DB_CONN,
deleteQuery?.query,
deleteQuery?.values
)) as PostInsertReturn;
return {
success: Boolean(res.affectedRows),
payload: res,
queryObject: {
sql: deleteQuery?.query || "",
params: deleteQuery?.values || [],
},
};
default:
return null;
return {
success: false,
payload: undefined,
msg: "Invalid action",
};
}
}
@@ -150,7 +150,10 @@ export default async function dsqlMethodCrud<
payload: GET_RESULT?.payload,
msg: GET_RESULT?.msg,
error: GET_RESULT?.error,
queryObject: GET_RESULT?.queryObject,
queryObject: {
string: GET_RESULT?.queryObject?.sql || "",
values: GET_RESULT?.queryObject?.params || [],
},
};
break;
+21 -1
View File
@@ -1,12 +1,16 @@
import { ServerlessMysql } from "serverless-mysql";
import debugLog from "../logging/debug-log";
import { DSQLErrorObject } from "../../types";
export type ConnDBHandlerQueryObject = {
query: string;
values?: (string | number | undefined)[];
};
type Return<ReturnType = any> = ReturnType | null | { error: string };
type Return<ReturnType = any> =
| ReturnType
| null
| { error?: string; errors?: DSQLErrorObject[] };
/**
* # Run Query From MySQL Connection
@@ -32,6 +36,8 @@ export default async function connDbHandler<ReturnType = any>(
if (!conn) throw new Error("No Connection Found!");
if (!query) throw new Error("Query String Required!");
let queryErrorArray: DSQLErrorObject[] = [];
if (typeof query == "string") {
const res = await conn.query(trimQuery(query), values);
@@ -48,8 +54,14 @@ export default async function connDbHandler<ReturnType = any>(
const resArray = [];
for (let i = 0; i < query.length; i++) {
let currentQueryError: DSQLErrorObject = {};
try {
const queryObj = query[i];
currentQueryError.sql = queryObj.query;
currentQueryError.sqlValues = queryObj.values;
const queryObjRes = await conn.query(
trimQuery(queryObj.query),
queryObj.values
@@ -70,6 +82,8 @@ export default async function connDbHandler<ReturnType = any>(
error as Error
);
resArray.push(null);
currentQueryError["error"] = error.message;
queryErrorArray.push(currentQueryError);
}
}
@@ -81,6 +95,12 @@ export default async function connDbHandler<ReturnType = any>(
});
}
if (queryErrorArray[0]) {
return {
errors: queryErrorArray,
};
}
return resArray as any;
} else {
return null;
@@ -0,0 +1,29 @@
import dataTypeParser, { DataTypesWithNumbers } from "./data-type-parser";
export default function dataTypeConstructor(
dataType: string,
limit?: number,
decimal?: number
) {
let finalType = dataTypeParser(dataType).type;
if (!DataTypesWithNumbers.includes(finalType)) {
return finalType;
}
if (finalType == "VARCHAR") {
return (finalType += `(${limit || 250})`);
}
if (
finalType == "DECIMAL" ||
finalType == "FLOAT" ||
finalType == "DOUBLE"
) {
return (finalType += `(${limit || 10},${decimal || 2})`);
}
if (limit && !decimal) finalType += `(${limit})`;
if (limit && decimal) finalType += `(${limit},${decimal})`;
return finalType;
}
@@ -0,0 +1,54 @@
import DataTypes from "../../../data/data-types";
import numberfy from "../../numberfy";
export const DataTypesWithNumbers: (typeof DataTypes)[number]["name"][] = [
"DECIMAL",
"DOUBLE",
"FLOAT",
"VARCHAR",
];
export const DataTypesWithTwoNumbers: (typeof DataTypes)[number]["name"][] = [
"DECIMAL",
"DOUBLE",
"FLOAT",
];
type Return = {
type: (typeof DataTypes)[number]["name"];
limit?: number;
decimal?: number;
};
export default function dataTypeParser(dataType?: string): Return {
if (!dataType) {
return {
type: "VARCHAR",
limit: 250,
};
}
const dataTypeArray = dataType.split("(");
const type = dataTypeArray[0] as (typeof DataTypes)[number]["name"];
const number = dataTypeArray[1] as string | undefined;
if (!DataTypesWithNumbers.includes(type)) {
return {
type,
};
}
if (number?.match(/,/)) {
const numberArr = number.split(",");
return {
type,
limit: numberfy(numberArr[0]),
decimal: numberArr[1] ? numberfy(numberArr[1]) : undefined,
};
}
return {
type,
limit: number ? numberfy(number) : undefined,
};
}
@@ -0,0 +1,36 @@
import {
DSQL_ChildrenDatabaseObject,
DSQL_ChildrenTablesType,
DSQL_DatabaseSchemaType,
} from "../../../types";
type Params = {
dbs?: DSQL_DatabaseSchemaType[];
dbSchema?: DSQL_DatabaseSchemaType;
childDbSchema?: DSQL_ChildrenDatabaseObject;
childTableSchema?: DSQL_ChildrenTablesType;
dbSlug?: string;
dbFullName?: string;
};
export default function grabTargetDatabaseSchemaIndex({
dbs,
dbFullName,
dbSlug,
dbSchema,
childDbSchema,
childTableSchema,
}: Params): number | undefined {
if (!dbs) return undefined;
const targetDbIndex = dbs.findIndex(
(db) =>
(dbSlug && dbSlug == db.dbSlug) ||
(dbFullName && dbFullName == db.dbFullName) ||
(dbSchema && dbSchema.dbSlug && dbSchema.dbSlug == db.dbSlug)
);
if (targetDbIndex < 0) return undefined;
return targetDbIndex;
}
@@ -0,0 +1,29 @@
import { DSQL_ChildrenTablesType, DSQL_TableSchemaType } from "../../../types";
type Params = {
tables?: DSQL_TableSchemaType[];
tableSchema?: DSQL_TableSchemaType;
childTableSchema?: DSQL_ChildrenTablesType;
tableName?: string;
};
export default function grabTargetTableSchemaIndex({
tables,
tableName,
tableSchema,
childTableSchema,
}: Params): number | undefined {
if (!tables) return undefined;
const targetTableIndex = tables.findIndex(
(tbl) =>
(tableName && tableName == tbl.tableName) ||
(tableSchema &&
tableSchema.tableName &&
tableSchema.tableName == tbl.tableName)
);
if (targetTableIndex < 0) return undefined;
return targetTableIndex;
}
@@ -0,0 +1,16 @@
import { DSQL_TableSchemaType } from "../../../types";
type Params = {
tables: DSQL_TableSchemaType[];
tableName?: string;
};
export default function grabTargetTableSchema({
tables,
tableName,
}: Params): DSQL_TableSchemaType | undefined {
const targetTable = tables.find(
(tbl) => tableName && tableName == tbl.tableName
);
return targetTable;
}
@@ -0,0 +1,16 @@
import { DSQL_FieldSchemaType, TextFieldTypesArray } from "../../../types";
export default function grabTextFieldType(
field: DSQL_FieldSchemaType,
nullReturn?: boolean
): (typeof TextFieldTypesArray)[number]["value"] | undefined {
if (field.richText) return "richText";
if (field.json) return "json";
if (field.yaml) return "yaml";
if (field.html) return "html";
if (field.css) return "css";
if (field.javascript) return "javascript";
if (field.shell) return "shell";
if (nullReturn) return undefined;
return "plain";
}
@@ -0,0 +1,132 @@
import {
grabPrimaryRequiredDbSchema,
writeUpdatedDbSchema,
} from "../../../shell/createDbFromSchema/grab-required-database-schemas";
import {
DSQL_ChildrenDatabaseObject,
DSQL_DatabaseSchemaType,
} from "../../../types";
import _ from "lodash";
import uniqueByKey from "../../unique-by-key";
type Params = {
currentDbSchema: DSQL_DatabaseSchemaType;
userId: string | number;
};
export default function ({ currentDbSchema, userId }: Params) {
const newCurrentDbSchema = _.cloneDeep(currentDbSchema);
if (newCurrentDbSchema.childrenDatabases) {
for (
let ch = 0;
ch < newCurrentDbSchema.childrenDatabases.length;
ch++
) {
const dbChildDb = newCurrentDbSchema.childrenDatabases[ch];
if (!dbChildDb.dbId) {
newCurrentDbSchema.childrenDatabases.splice(ch, 1, {});
continue;
}
const targetChildDatabase = grabPrimaryRequiredDbSchema({
dbId: dbChildDb.dbId,
userId,
});
/**
* Delete child database from array if said database
* doesn't exist
*/
if (targetChildDatabase?.id && targetChildDatabase.childDatabase) {
targetChildDatabase.tables = [...newCurrentDbSchema.tables];
writeUpdatedDbSchema({
dbSchema: targetChildDatabase,
userId,
});
} else {
newCurrentDbSchema.childrenDatabases?.splice(ch, 1, {});
}
}
newCurrentDbSchema.childrenDatabases =
uniqueByKey<DSQL_ChildrenDatabaseObject>(
newCurrentDbSchema.childrenDatabases.filter((db) =>
Boolean(db.dbId)
),
"dbId"
);
}
/**
* Handle scenario where this database is a child of another
*/
if (currentDbSchema.childDatabase && currentDbSchema.childDatabaseDbId) {
const targetParentDatabase = grabPrimaryRequiredDbSchema({
dbId: currentDbSchema.childDatabaseDbId,
userId,
});
if (!targetParentDatabase) {
return newCurrentDbSchema;
}
/**
* Delete child Database key/values from current database if
* the parent database doesn't esit
*/
if (!targetParentDatabase?.id) {
delete newCurrentDbSchema.childDatabase;
delete newCurrentDbSchema.childDatabaseDbId;
return newCurrentDbSchema;
}
/**
* New Child Database Object to be appended
*/
const newChildDatabaseObject: DSQL_ChildrenDatabaseObject = {
dbId: currentDbSchema.id,
};
/**
* Add a new Children array in the target Database if this is the
* first child to be added to said database. Else append to array
* if it exists
*/
if (
targetParentDatabase?.id &&
!targetParentDatabase.childrenDatabases?.[0]
) {
targetParentDatabase.childrenDatabases = [newChildDatabaseObject];
} else if (
targetParentDatabase?.id &&
targetParentDatabase.childrenDatabases?.[0]
) {
const existingChildDb = targetParentDatabase.childrenDatabases.find(
(db) => db.dbId == currentDbSchema.id
);
if (!existingChildDb?.dbId) {
targetParentDatabase.childrenDatabases.push(
newChildDatabaseObject
);
}
targetParentDatabase.childrenDatabases = uniqueByKey(
targetParentDatabase.childrenDatabases,
"dbId"
);
}
/**
* Update tables for child database, which is the current database
*/
if (targetParentDatabase?.id) {
newCurrentDbSchema.tables = targetParentDatabase.tables;
writeUpdatedDbSchema({ dbSchema: targetParentDatabase, userId });
}
}
return newCurrentDbSchema;
}
@@ -0,0 +1,229 @@
import {
grabPrimaryRequiredDbSchema,
writeUpdatedDbSchema,
} from "../../../shell/createDbFromSchema/grab-required-database-schemas";
import {
DSQL_ChildrenTablesType,
DSQL_DatabaseSchemaType,
DSQL_TableSchemaType,
} from "../../../types";
import _ from "lodash";
import uniqueByKey from "../../unique-by-key";
type Params = {
currentDbSchema: DSQL_DatabaseSchemaType;
currentTableSchema: DSQL_TableSchemaType;
currentTableSchemaIndex: number;
userId: string | number;
};
export default function ({
currentDbSchema,
currentTableSchema,
currentTableSchemaIndex,
userId,
}: Params): DSQL_DatabaseSchemaType {
if (!currentDbSchema.dbFullName) {
throw new Error(
`Resolve Children tables ERROR => currentDbSchema.dbFullName not found!`
);
}
const newCurrentDbSchema = _.cloneDeep(currentDbSchema);
if (newCurrentDbSchema.tables[currentTableSchemaIndex].childrenTables) {
for (
let ch = 0;
ch <
newCurrentDbSchema.tables[currentTableSchemaIndex].childrenTables
.length;
ch++
) {
const childTable =
newCurrentDbSchema.tables[currentTableSchemaIndex]
.childrenTables[ch];
if (!childTable.dbId || !childTable.tableId) {
newCurrentDbSchema.tables[
currentTableSchemaIndex
].childrenTables?.splice(ch, 1, {});
continue;
}
const targetChildTableParentDatabase = grabPrimaryRequiredDbSchema({
dbId: childTable.dbId,
userId,
});
/**
* Delete child table from array if the parent database
* of said child table has been deleted or doesn't exist
*/
if (!targetChildTableParentDatabase?.dbFullName) {
newCurrentDbSchema.tables[
currentTableSchemaIndex
].childrenTables?.splice(ch, 1, {});
} else {
/**
* Delete child table from array if the parent database
* exists but the target tabled has been deleted or doesn't
* exist
*/
const targetChildTableParentDatabaseTableIndex =
targetChildTableParentDatabase.tables.findIndex(
(tbl) => tbl.id == childTable.tableId
);
const targetChildTableParentDatabaseTable =
targetChildTableParentDatabase.tables[
targetChildTableParentDatabaseTableIndex
];
if (targetChildTableParentDatabaseTable?.childTable) {
targetChildTableParentDatabase.tables[
targetChildTableParentDatabaseTableIndex
].fields = [...currentTableSchema.fields];
targetChildTableParentDatabase.tables[
targetChildTableParentDatabaseTableIndex
].indexes = [...(currentTableSchema.indexes || [])];
writeUpdatedDbSchema({
dbSchema: targetChildTableParentDatabase,
userId,
});
} else {
newCurrentDbSchema.tables[
currentTableSchemaIndex
].childrenTables?.splice(ch, 1, {});
}
}
}
if (
newCurrentDbSchema.tables[currentTableSchemaIndex]
.childrenTables?.[0]
) {
newCurrentDbSchema.tables[currentTableSchemaIndex].childrenTables =
uniqueByKey<DSQL_ChildrenTablesType>(
newCurrentDbSchema.tables[
currentTableSchemaIndex
].childrenTables.filter(
(tbl) => Boolean(tbl.dbId) && Boolean(tbl.tableId)
),
"dbId"
);
} else {
delete newCurrentDbSchema.tables[currentTableSchemaIndex]
.childrenTables;
}
}
/**
* Handle scenario where this table is a child of another
*/
if (
currentTableSchema.childTable &&
currentTableSchema.childTableDbId &&
currentTableSchema.childTableDbId
) {
const targetParentDatabase = grabPrimaryRequiredDbSchema({
dbId: currentTableSchema.childTableDbId,
userId,
});
const targetParentDatabaseTableIndex =
targetParentDatabase?.tables.findIndex(
(tbl) => tbl.id == currentTableSchema.childTableId
);
const targetParentDatabaseTable =
typeof targetParentDatabaseTableIndex == "number"
? targetParentDatabaseTableIndex < 0
? undefined
: targetParentDatabase?.tables[
targetParentDatabaseTableIndex
]
: undefined;
/**
* Delete child Table key/values from current database if
* the parent database doesn't esit
*/
if (
!targetParentDatabase?.dbFullName ||
!targetParentDatabaseTable?.tableName
) {
delete newCurrentDbSchema.tables[currentTableSchemaIndex]
.childTable;
delete newCurrentDbSchema.tables[currentTableSchemaIndex]
.childTableDbId;
delete newCurrentDbSchema.tables[currentTableSchemaIndex]
.childTableId;
delete newCurrentDbSchema.tables[currentTableSchemaIndex]
.childTableDbId;
return newCurrentDbSchema;
}
/**
* New Child Database Table Object to be appended
*/
const newChildDatabaseTableObject: DSQL_ChildrenTablesType = {
tableId: currentTableSchema.id,
dbId: newCurrentDbSchema.id,
};
/**
* Add a new Children array in the target table schema if this is the
* first child to be added to said table schema. Else append to array
* if it exists
*/
if (
typeof targetParentDatabaseTableIndex == "number" &&
!targetParentDatabaseTable.childrenTables?.[0]
) {
targetParentDatabase.tables[
targetParentDatabaseTableIndex
].childrenTables = [newChildDatabaseTableObject];
} else if (
typeof targetParentDatabaseTableIndex == "number" &&
targetParentDatabaseTable.childrenTables?.[0]
) {
const existingChildDbTable =
targetParentDatabaseTable.childrenTables.find(
(tbl) =>
tbl.dbId == newCurrentDbSchema.id &&
tbl.tableId == currentTableSchema.id
);
if (!existingChildDbTable?.tableId) {
targetParentDatabase.tables[
targetParentDatabaseTableIndex
].childrenTables?.push(newChildDatabaseTableObject);
}
targetParentDatabase.tables[
targetParentDatabaseTableIndex
].childrenTables = uniqueByKey(
targetParentDatabase.tables[targetParentDatabaseTableIndex]
.childrenTables || [],
["dbId", "tableId"]
);
}
/**
* Update fields and indexes for child table, which is the
* current table
*/
if (targetParentDatabaseTable?.tableName) {
newCurrentDbSchema.tables[currentTableSchemaIndex].fields =
targetParentDatabaseTable.fields;
newCurrentDbSchema.tables[currentTableSchemaIndex].indexes =
targetParentDatabaseTable.indexes;
writeUpdatedDbSchema({ dbSchema: targetParentDatabase, userId });
}
}
return newCurrentDbSchema;
}
@@ -0,0 +1,32 @@
import fs from "fs";
import { DSQL_DatabaseSchemaType } from "../../../types";
import _ from "lodash";
import resolveSchemaChildrenHandleChildrenDatabases from "./resolve-schema-children-handle-children-databases";
import resolveSchemaChildrenHandleChildrenTables from "./resolve-schema-children-handle-children-tables";
type Params = {
dbSchema: DSQL_DatabaseSchemaType;
userId: string | number;
};
export default function resolveSchemaChildren({ dbSchema, userId }: Params) {
let newDbSchema = _.cloneDeep(dbSchema);
newDbSchema = resolveSchemaChildrenHandleChildrenDatabases({
currentDbSchema: newDbSchema,
userId,
});
for (let t = 0; t < newDbSchema.tables.length; t++) {
const tableSchema = newDbSchema.tables[t];
newDbSchema = resolveSchemaChildrenHandleChildrenTables({
currentDbSchema: newDbSchema,
currentTableSchema: tableSchema,
currentTableSchemaIndex: t,
userId,
});
}
return newDbSchema;
}
@@ -0,0 +1,38 @@
import { DSQL_DatabaseSchemaType } from "../../../types";
import _ from "lodash";
type Params = {
dbSchema: DSQL_DatabaseSchemaType;
userId: string | number;
};
export default function resolveSchemaForeignKeys({ dbSchema, userId }: Params) {
let newDbSchema = _.cloneDeep(dbSchema);
for (let t = 0; t < newDbSchema.tables.length; t++) {
const tableSchema = newDbSchema.tables[t];
for (let f = 0; f < tableSchema.fields.length; f++) {
const fieldSchema = tableSchema.fields[f];
if (fieldSchema.foreignKey?.destinationTableColumnName) {
const fkDestinationTableIndex = newDbSchema.tables.findIndex(
(tbl) =>
tbl.tableName ==
fieldSchema.foreignKey?.destinationTableName
);
/**
* Delete current Foreign Key if related table doesn't exist
* or has been deleted
*/
if (fkDestinationTableIndex < 0) {
delete newDbSchema.tables[t].fields[f].foreignKey;
continue;
}
}
}
}
return newDbSchema;
}
@@ -0,0 +1,78 @@
import fs from "fs";
import grabDirNames from "../../backend/names/grab-dir-names";
import _n from "../../numberfy";
import path from "path";
import { DSQL_DatabaseSchemaType } from "../../../types";
import _ from "lodash";
import EJSON from "../../ejson";
import { writeUpdatedDbSchema } from "../../../shell/createDbFromSchema/grab-required-database-schemas";
type Params = {
userId: string | number;
dbId?: string | number;
};
export default function resolveUsersSchemaIDs({ userId, dbId }: Params) {
const { targetUserPrivateDir, tempDirName } = grabDirNames({ userId });
if (!targetUserPrivateDir) return false;
const schemaDirFilesFolders = fs.readdirSync(targetUserPrivateDir);
for (let i = 0; i < schemaDirFilesFolders.length; i++) {
const fileOrFolderName = schemaDirFilesFolders[i];
if (!fileOrFolderName.match(/^\d+.json/)) continue;
const fileDbId = _n(fileOrFolderName.split(".").shift());
if (!fileDbId) continue;
if (dbId && _n(dbId) !== fileDbId) {
continue;
}
const schemaFullPath = path.join(
targetUserPrivateDir,
fileOrFolderName
);
if (!fs.existsSync(schemaFullPath)) continue;
const dbSchema = EJSON.parse(
fs.readFileSync(schemaFullPath, "utf-8")
) as DSQL_DatabaseSchemaType | undefined;
if (!dbSchema) continue;
let newDbSchema = resolveUserDatabaseSchemaIDs({ dbSchema });
writeUpdatedDbSchema({ dbSchema: newDbSchema, userId });
}
}
export function resolveUserDatabaseSchemaIDs({
dbSchema,
}: {
dbSchema: DSQL_DatabaseSchemaType;
}) {
let newDbSchema = _.cloneDeep(dbSchema);
if (!newDbSchema.id) newDbSchema.id = dbSchema.id;
newDbSchema.tables.forEach((tbl, index) => {
if (!tbl.id) {
newDbSchema.tables[index].id = index + 1;
}
tbl.fields.forEach((fld, flIndx) => {
if (!fld.id) {
newDbSchema.tables[index].fields[flIndx].id = flIndx + 1;
}
});
tbl.indexes?.forEach((indx, indIndx) => {
if (!indx.id && newDbSchema.tables[index].indexes) {
newDbSchema.tables[index].indexes[indIndx].id = indIndx + 1;
}
});
});
return newDbSchema;
}
@@ -0,0 +1,31 @@
import { DSQL_FieldSchemaType, TextFieldTypesArray } from "../../../types";
import _ from "lodash";
export default function setTextFieldType(
field: DSQL_FieldSchemaType,
type?: (typeof TextFieldTypesArray)[number]["value"]
): DSQL_FieldSchemaType {
const newField = _.cloneDeep(field);
delete newField.css;
delete newField.richText;
delete newField.json;
delete newField.shell;
delete newField.html;
delete newField.javascript;
delete newField.yaml;
delete newField.code;
delete newField.defaultValueLiteral;
if (type == "css") return { ...newField, css: true };
if (type == "richText") return { ...newField, richText: true };
if (type == "json") return { ...newField, json: true };
if (type == "shell") return { ...newField, shell: true };
if (type == "html") return { ...newField, html: true };
if (type == "yaml") return { ...newField, yaml: true };
if (type == "javascript") return { ...newField, javascript: true };
if (type == "code") return { ...newField, code: true };
return { ...newField };
}
+37
View File
@@ -0,0 +1,37 @@
import _ from "lodash";
/**
* # Delete all matches in an Array
*/
export default function deleteByKey<T extends { [k: string]: any } = any>(
arr: T[],
key: keyof T | (keyof T)[]
) {
let newArray = _.cloneDeep(arr);
for (let i = 0; i < newArray.length; i++) {
const item = newArray[i];
if (Array.isArray(key)) {
const targetMatches: boolean[] = [];
for (let k = 0; k < key.length; k++) {
const ky = key[k];
const targetValue = item[ky];
const targetOriginValue = item[ky];
targetMatches.push(targetValue == targetOriginValue);
}
if (!targetMatches.find((mtch) => !mtch)) {
newArray.splice(i, 1);
}
} else {
let existingValue = newArray.find((v) => v[key] == item[key]);
if (existingValue) {
newArray.splice(i, 1);
}
}
}
return newArray;
}
+6
View File
@@ -0,0 +1,6 @@
export default function envsub(str: string) {
return str.replace(/\$([A-Z_]+)|\${([A-Z_]+)}/g, (match, var1, var2) => {
const varName = var1 || var2;
return process.env[varName] || match;
});
}
@@ -0,0 +1,16 @@
const APIParadigms = ["crud", "media", "schema"] as const;
type Params = {
version?: string;
paradigm?: (typeof APIParadigms)[number];
};
export default function grabAPIBasePath({ version, paradigm }: Params): string {
let basePath = `/api/v${version || "1"}`;
if (paradigm) {
basePath += `/${paradigm}`;
}
return basePath;
}
@@ -0,0 +1,18 @@
import fs from "fs";
import grabDirNames from "./backend/names/grab-dir-names";
import EJSON from "./ejson";
import { DSQL_DatabaseSchemaType } from "../types";
export default function grabAppMainDbSchema() {
const { appSchemaJSONFile } = grabDirNames();
if (!fs.existsSync(appSchemaJSONFile)) {
return undefined;
}
const parsedAppSchema = EJSON.parse(
fs.readFileSync(appSchemaJSONFile, "utf-8")
) as DSQL_DatabaseSchemaType | undefined;
return parsedAppSchema;
}
+17
View File
@@ -0,0 +1,17 @@
import { AppVersions } from "../types";
export default function grabAppVersion(): (typeof AppVersions)[number] {
const appVersionEnv = process.env.NEXT_PUBLIC_VERSION;
const finalAppVersion = (appVersionEnv ||
"community") as (typeof AppVersions)[number]["value"];
const targetAppVersion = AppVersions.find(
(version) => version.value === finalAppVersion
);
if (!targetAppVersion) {
throw new Error(`Invalid App Version: ${finalAppVersion}`);
}
return targetAppVersion;
}
+31 -11
View File
@@ -1,23 +1,43 @@
import { UserType } from "../types";
import slugify from "./slugify";
type Param = {
/**
* Database full name or slug
*/
dbName?: string;
userId?: string | number;
user?: UserType | null;
};
/**
* # Grab Database Full Name
* # Grab full database name
* @description Grab full database name from slug or full name
* @param param0
* @returns
*/
export default function grabDbFullName({ dbName, userId }: Param): string {
if (!dbName)
throw new Error(
`Database name not provided to db name parser funciton`
);
export default function grabDbFullName({
dbName,
userId,
user,
}: Param): string | undefined {
const finalUserId = user?.id || userId;
const sanitizedName = dbName.replace(/[^a-z0-9\_]/g, "");
const cleanedDbName = sanitizedName.replace(/datasquirel_user_\d+_/, "");
if (!finalUserId) {
return dbName;
}
if (!dbName) {
return;
}
if (!userId) return cleanedDbName;
const dbNamePrefix = process.env.DSQL_USER_DB_PREFIX;
const dbNamePrefix = `datasquirel_user_${userId}_`;
const parsedDbName = slugify(dbName, "_");
return dbNamePrefix + cleanedDbName;
const dbSlug = parsedDbName.replace(
new RegExp(`${dbNamePrefix}_?\\d+_`),
""
);
return slugify(`${dbNamePrefix}_${finalUserId}_${dbSlug}`, "_");
}
+27
View File
@@ -0,0 +1,27 @@
import { UserType } from "../types";
import grabDbFullName from "./grab-db-full-name";
type Param = {
/**
* Database full name or slug
*/
dbName?: string;
userId?: string | number;
user?: UserType | null;
};
/**
* # Grab full database name
* @description Grab full database name from slug or full name
* @param param0
* @returns
*/
export default function grabDbNames({ dbName, userId, user }: Param) {
const dbNamePrefix = process.env.DSQL_USER_DB_PREFIX;
const finalUserId = user?.id || userId;
const userDbPrefix = `${dbNamePrefix}${finalUserId}_`;
const dbFullName = grabDbFullName({ dbName, user, userId });
return { userDbPrefix, dbFullName, dbNamePrefix };
}
@@ -0,0 +1,15 @@
export default function grabDockerResourceIPNumbers() {
return {
db: 32,
maxscale: 24,
postDbSetup: 43,
reverse_proxy: 34,
web: 35,
websocket: 36,
cron: 27,
db_cron: 20,
replica_1: 37,
replica_2: 38,
web_app_post_db_setup: 71,
} as const;
}
@@ -0,0 +1,7 @@
import _ from "lodash";
import grabIPAddresses from "./backend/names/grab-ip-addresses";
export default function grabInstanceGlobalNetWorkName() {
const deploymentName = process.env.DSQL_DEPLOYMENT_NAME || "dsql";
return `${deploymentName}_dsql_global_network`;
}
+24
View File
@@ -0,0 +1,24 @@
type Param = {
type: "foreign_key" | "index" | "user";
userId?: string | number;
addDate?: boolean;
};
/**
* # Grab Key Names
* @description Grab key names for foreign keys and indexes
*/
export default function grabSQLKeyName({ type, userId, addDate }: Param) {
let prefixParadigm = (() => {
if (type == "foreign_key") return "fk";
if (type == "index") return "indx";
if (type == "user") return "user";
return null;
})();
let key = `dsql`;
if (prefixParadigm) key += `_${prefixParadigm}`;
if (userId) key += `_${userId}`;
if (addDate) key += `_${Date.now()}`;
return key;
}
@@ -0,0 +1,5 @@
export default function grabSQLUserNameForUser(
userId?: string | number
): string {
return `dsql_user_${userId || 0}`;
}
@@ -0,0 +1,42 @@
import { UserType } from "../types";
import grabSQLUserNameForUser from "./grab-sql-user-name-for-user";
type Params = {
user?: UserType | null;
name?: string;
};
type Return = {
sqlUsername?: string;
name?: string;
nameWithoutPrefix?: string;
};
export default function grabSQLUserName({
user,
name: passedName,
}: Params): Return {
if (!user) {
console.log("No User Found");
return {};
}
const sqlUsername = grabSQLUserNameForUser(user.id);
const parsedPassedName = passedName
? passedName.replace(sqlUsername, "").replace(/^_+|_+$/, "")
: undefined;
const name = parsedPassedName
? `${sqlUsername}_${parsedPassedName}`
: undefined;
if (user.isSuperUser) {
return {
sqlUsername: undefined,
name: passedName,
nameWithoutPrefix: passedName,
};
}
return { sqlUsername, name, nameWithoutPrefix: parsedPassedName };
}
@@ -0,0 +1,30 @@
import { UserType } from "../types";
import grabSQLUserNameForUser from "./grab-sql-user-name-for-user";
import grabIPAddresses from "../utils/backend/names/grab-ip-addresses";
type Params = {
user?: UserType | null;
HOST?: string;
username?: string;
};
export default function grabUserMainSqlUserName({
HOST,
user,
username,
}: Params) {
const sqlUsername = grabSQLUserNameForUser(user?.id);
const { webAppIP, maxScaleIP } = grabIPAddresses();
const finalUsername = username || sqlUsername;
const finalHost = HOST || maxScaleIP || "127.0.0.1";
const fullName = `${finalUsername}@${webAppIP}`;
return {
username: finalUsername,
host: finalHost,
webHost: webAppIP,
fullName,
sqlUsername,
};
}
+6
View File
@@ -0,0 +1,6 @@
export default function normalizeText(txt: string) {
return txt
.replace(/\n|\r|\n\r/g, " ")
.replace(/ {2,}/g, " ")
.trim();
}
+6 -2
View File
@@ -1,7 +1,11 @@
import fs from "fs";
import { EnvKeys } from "../types";
export default function parseEnv(envFile: string) {
export default function parseEnv(
/** The file path to the env. Eg. /app/.env */ envFile: string
) {
if (!fs.existsSync(envFile)) return undefined;
const envTextContent = fs.readFileSync(envFile, "utf-8");
const envLines = envTextContent
.split("\n")
@@ -32,5 +36,5 @@ export default function parseEnv(envFile: string) {
}
}
return newEnvObj;
return newEnvObj as { [k in (typeof EnvKeys)[number]]: string | undefined };
}
@@ -0,0 +1,35 @@
import _ from "lodash";
import { DefaultEntryType } from "../types";
import defaultFieldsRegexp from "../functions/dsql/default-fields-regexp";
export default function purgeDefaultFields<
T extends { [k: string]: any } = DefaultEntryType & { [k: string]: any }
>(entry: T | T[]): T | T[] {
const newEntry = _.cloneDeep(entry);
if (Array.isArray(newEntry)) {
const entryKeys = Object.keys(newEntry[0]);
for (let i = 0; i < newEntry.length; i++) {
for (let j = 0; j < entryKeys.length; j++) {
const entryKey = entryKeys[j];
if (defaultFieldsRegexp.test(entryKey)) {
delete newEntry[i][entryKey];
}
}
}
return newEntry;
} else {
const entryKeys = Object.keys(newEntry);
for (let i = 0; i < entryKeys.length; i++) {
const entryKey = entryKeys[i];
if (defaultFieldsRegexp.test(entryKey)) {
delete newEntry[entryKey];
}
}
return newEntry;
}
}
@@ -0,0 +1,20 @@
import { execSync } from "child_process";
import grabInstanceGlobalNetWorkName from "./grab-instance-global-network-name";
import grabIPAddresses from "./backend/names/grab-ip-addresses";
export default function setupGlobalNetwork() {
const globalNetworkName = grabInstanceGlobalNetWorkName();
const { globalIPPrefix } = grabIPAddresses();
try {
execSync(`docker network rm ${globalNetworkName}`, {});
} catch (error) {}
let newNtwkCmd = `docker network create`;
newNtwkCmd += ` --driver bridge`;
newNtwkCmd += ` --subnet ${globalIPPrefix}.0/24`;
newNtwkCmd += ` --gateway ${globalIPPrefix}.1`;
newNtwkCmd += ` ${globalNetworkName}`;
execSync(newNtwkCmd);
}
@@ -0,0 +1,15 @@
export default function slugToNormalText(str?: string) {
if (!str) return "";
return str
.toLowerCase()
.replace(/ /g, "-")
.replace(/[^a-z0-9\-]/g, "-")
.replace(/-{2,}/g, "-")
.replace(/[-]/g, " ")
.split(" ")
.map(
(word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
)
.join(" ");
}
+18 -9
View File
@@ -1,5 +1,3 @@
// @ts-check
/**
* # Return the slug of a string
*
@@ -8,19 +6,30 @@
* slugify("Yes!") // "yes"
* slugify("Hello!!! World!") // "hello-world"
*/
export default function slugify(str?: string): string {
export default function slugify(
str?: string,
divider?: "-" | "_" | null,
allowTrailingDash?: boolean | null
): string {
const finalSlugDivider = divider || "-";
try {
if (!str) return "";
return String(str)
let finalStr = String(str)
.trim()
.toLowerCase()
.replace(/ {2,}/g, " ")
.replace(/ /g, "-")
.replace(/[^a-z0-9]/g, "-")
.replace(/-{2,}/g, "-")
.replace(/^-/, "")
.replace(/-$/, "");
.replace(/ /g, finalSlugDivider)
.replace(/[^a-z0-9]/g, finalSlugDivider)
.replace(/-{2,}|_{2,}/g, finalSlugDivider)
.replace(/^-/, "");
if (allowTrailingDash) {
return finalStr;
}
return finalStr.replace(/-$/, "");
} catch (error: any) {
console.log(`Slugify ERROR: ${error.message}`);
return "";
@@ -0,0 +1,42 @@
import { ServerQueryEqualities } from "../types";
export default function sqlEqualityParser(
eq: (typeof ServerQueryEqualities)[number]
): string {
switch (eq) {
case "EQUAL":
return "=";
case "LIKE":
return "LIKE";
case "NOT LIKE":
return "NOT LIKE";
case "NOT EQUAL":
return "<>";
case "IN":
return "IN";
case "NOT IN":
return "NOT IN";
case "BETWEEN":
return "BETWEEN";
case "NOT BETWEEN":
return "NOT BETWEEN";
case "IS NULL":
return "IS NULL";
case "IS NOT NULL":
return "IS NOT NULL";
case "EXISTS":
return "EXISTS";
case "NOT EXISTS":
return "NOT EXISTS";
case "GREATER THAN":
return ">";
case "GREATER THAN OR EQUAL":
return ">=";
case "LESS THAN":
return "<";
case "LESS THAN OR EQUAL":
return "<=";
default:
return "=";
}
}
+36
View File
@@ -0,0 +1,36 @@
import slugify from "./slugify";
export default function uniqueByKey<T extends { [k: string]: any } = any>(
arr: T[],
key: keyof T | (keyof T)[]
) {
let newArray = [] as T[];
let uniqueValues = [] as string[];
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
let targetValue: string | undefined;
if (Array.isArray(key)) {
const targetVals: string[] = [];
for (let k = 0; k < key.length; k++) {
const ky = key[k];
const targetValuek = slugify(String(item[ky]));
targetVals.push(targetValuek);
}
targetValue = slugify(targetVals.join(","));
} else {
targetValue = slugify(String(item[key]));
}
if (!targetValue) continue;
if (uniqueValues.includes(targetValue)) continue;
newArray.push(item);
uniqueValues.push(targetValue);
}
return newArray;
}
@@ -0,0 +1,18 @@
import fs from "fs";
import grabDirNames from "./backend/names/grab-dir-names";
export default function updateGrastateToLatest() {
const { mainDbGrastateDatFile } = grabDirNames();
const existingGrastateDatFile = fs.readFileSync(
mainDbGrastateDatFile,
"utf-8"
);
const newGrastateDatFile = existingGrastateDatFile.replace(
/safe_to_bootstrap: .*/,
`safe_to_bootstrap: 1`
);
fs.writeFileSync(mainDbGrastateDatFile, newGrastateDatFile, "utf-8");
}