Updates
This commit is contained in:
@@ -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 };
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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(*)"]
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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}`, "_");
|
||||
}
|
||||
|
||||
@@ -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`;
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export default function normalizeText(txt: string) {
|
||||
return txt
|
||||
.replace(/\n|\r|\n\r/g, " ")
|
||||
.replace(/ {2,}/g, " ")
|
||||
.trim();
|
||||
}
|
||||
@@ -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(" ");
|
||||
}
|
||||
@@ -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 "=";
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
Reference in New Issue
Block a user