Skip to content

Commit 8c2f49a

Browse files
authored
Merge pull request #22 from rowyio/develop
Develop
2 parents 0fd1374 + 41db2d1 commit 8c2f49a

File tree

12 files changed

+149
-13
lines changed

12 files changed

+149
-13
lines changed

deploy.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ while test $# -gt 0; do
1919
return 1;
2020
;;
2121
esac
22-
done
22+
done
2323

2424
if [[ -z "$project_id" ]];
2525
then

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "rowy-backend",
33
"description": "cloud run instance for running Rowy's backend functionality",
4-
"version": "1.6.4",
4+
"version": "1.7.0",
55
"private": true,
66
"main": "build/index.js",
77
"scripts": {

src/functionBuilder/compiler/loader/index.ts

+5
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export const getConfigFromTableSchema = async (
5555
fieldTypes,
5656
extensions,
5757
runtimeOptions,
58+
tableSchema: schemaData,
5859
};
5960
if (schemaData.searchIndex) {
6061
config.searchIndex = {
@@ -86,6 +87,7 @@ export const combineConfigs = (configs: any[]) =>
8687
extensions,
8788
searchIndex,
8889
runtimeOptions,
90+
tableSchema,
8991
} = cur;
9092
return {
9193
derivativeColumns: [...acc.derivativeColumns, ...derivativeColumns],
@@ -105,6 +107,7 @@ export const combineConfigs = (configs: any[]) =>
105107
? [...acc.searchIndices, searchIndex]
106108
: acc.searchIndices,
107109
runtimeOptions,
110+
tableSchema,
108111
};
109112
},
110113
{
@@ -131,6 +134,7 @@ export const generateFile = async (configData, buildFolderTimestamp) => {
131134
region,
132135
searchHost,
133136
runtimeOptions,
137+
tableSchema,
134138
} = configData;
135139
const serializedConfigData = {
136140
fieldTypes: JSON.stringify(fieldTypes),
@@ -144,6 +148,7 @@ export const generateFile = async (configData, buildFolderTimestamp) => {
144148
serviceAccount: `rowy-functions@${projectId}.iam.gserviceaccount.com`,
145149
...runtimeOptions,
146150
}),
151+
tableSchema: JSON.stringify(tableSchema),
147152
region: JSON.stringify(region),
148153
searchHost: JSON.stringify(searchHost),
149154
searchIndices: JSON.stringify(searchIndices),

src/functionBuilder/compiler/loader/serialisers.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { IExtension } from "./types";
22
import { getRequiredPackages } from "../../../utils";
33

4-
const removeInlineVersioning = (code) =>
4+
const removeInlineVersioning = (code: string) =>
55
code.replace(
66
/(?:require\(.*)@\d+\.\d+\.\d+/g,
77
(capture) => capture.split("@")[0]
88
);
99

10+
const removeTrailingColon = (code: string) => {
11+
return code.replace(/\s*;\s*$/, "");
12+
};
13+
1014
/* Convert extension objects into a single readable string */
1115
export const serialiseExtension = (extensions: IExtension[]): string =>
1216
"[" +
@@ -31,9 +35,12 @@ export const serialiseExtension = (extensions: IExtension[]): string =>
3135
requiredPackages:${JSON.stringify(
3236
getRequiredPackages(extension.extensionBody)
3337
)},
34-
extensionBody: ${removeInlineVersioning(extension.extensionBody)
35-
.replace(/^.*:\s*\w*Body\s*=/, "")
36-
.replace(/\s*;\s*$/, "")}
38+
extensionBody: ${removeTrailingColon(
39+
removeInlineVersioning(extension.extensionBody).replace(
40+
/^.*:\s*\w*Body\s*=/,
41+
""
42+
)
43+
)}
3744
}`
3845
)
3946
.join(",") +
@@ -53,7 +60,7 @@ export const serialiseDerivativeColumns = (derivativeColumns: any[]): string =>
5360
return `${acc}{\nfieldName:'${currColumn.key}'
5461
,requiredPackages:${JSON.stringify(getRequiredPackages(functionBody))}
5562
,evaluate:async ({row,ref,db,auth,storage,utilFns}) =>
56-
${removeInlineVersioning(functionBody)}
63+
${removeTrailingColon(removeInlineVersioning(functionBody))}
5764
,\nlistenerFields:[${listenerFields
5865
.map((fieldKey: string) => `"${fieldKey}"`)
5966
.join(",\n")}]},\n`;
@@ -77,7 +84,7 @@ export const serialiseDefaultValueColumns = (
7784
type:"${type}",
7885
requiredPackages:${JSON.stringify(getRequiredPackages(functionBody))},
7986
script:async ({row,ref,db,auth,utilFns}) => {
80-
${removeInlineVersioning(functionBody)}
87+
${removeTrailingColon(removeInlineVersioning(functionBody))}
8188
},
8289
},\n`;
8390
} else {

src/functionBuilder/compiler/loader/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ export interface TableConfig {
5050
fields: string[];
5151
};
5252
runtimeOptions: IRuntimeOptions;
53+
tableSchema: any;
5354
}

src/functionBuilder/functions/src/extensions/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import utilFns, { hasRequiredFields, getTriggerType } from "../utils";
33
import { db, auth, storage } from "../firebaseConfig";
44

55
const extension =
6-
(extensionConfig, fieldTypes) =>
6+
(extensionConfig, fieldTypes, tableSchema) =>
77
async (
88
change: functions.Change<functions.firestore.DocumentSnapshot>,
99
context: functions.EventContext
@@ -33,6 +33,7 @@ const extension =
3333
utilFns,
3434
fieldTypes,
3535
storage,
36+
tableSchema,
3637
};
3738
if (!triggers.includes(triggerType)) return false; //check if trigger type is included in the extension
3839
if (

src/functionBuilder/functions/src/index.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ export const R = {
2020
extensionConfig.triggers.includes(triggerType)
2121
)
2222
.map((extensionConfig) =>
23-
extension(extensionConfig, functionConfig.fieldTypes)(change, context)
23+
extension(
24+
extensionConfig,
25+
functionConfig.fieldTypes,
26+
functionConfig.tableSchema
27+
)(change, context)
2428
);
2529
console.log(
2630
`#${

src/logging/LoggingFactory.ts

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Logging } from "@google-cloud/logging";
2+
import { getProjectId } from "../metadataService";
3+
4+
type FunctionType = "action" | "connector" | "derivative";
5+
6+
interface RowyLogging {
7+
log: (payload: any) => void;
8+
warn: (payload: any) => void;
9+
error: (payload: any) => void;
10+
}
11+
12+
class LoggingFactory {
13+
public static async createActionLogging(fieldName: string, rowId: string) {
14+
const projectId = await getProjectId();
15+
return new LoggingFieldAndRow(projectId, fieldName, rowId, "action");
16+
}
17+
18+
public static async createConnectorLogging(fieldName: string, rowId: string) {
19+
const projectId = await getProjectId();
20+
return new LoggingFieldAndRow(projectId, fieldName, rowId, "connector");
21+
}
22+
23+
public static async createDerivativeLogging(
24+
fieldName: string,
25+
rowId: string
26+
) {
27+
const projectId = await getProjectId();
28+
return new LoggingFieldAndRow(projectId, fieldName, rowId, "derivative");
29+
}
30+
}
31+
32+
class LoggingAbstract implements RowyLogging {
33+
protected readonly functionType;
34+
protected readonly logging: Logging;
35+
36+
constructor(projectId: string, functionType: FunctionType) {
37+
this.functionType = functionType;
38+
this.logging = new Logging({ projectId });
39+
}
40+
41+
protected async logWithSeverity(payload: any, severity: string) {
42+
throw new Error("logWithSeverity must be implemented");
43+
}
44+
45+
async log(payload: any) {
46+
await this.logWithSeverity(payload, "DEFAULT");
47+
}
48+
49+
async warn(payload: any) {
50+
await this.logWithSeverity(payload, "WARNING");
51+
}
52+
53+
async error(payload: any) {
54+
await this.logWithSeverity(payload, "ERROR");
55+
}
56+
}
57+
58+
class LoggingFieldAndRow extends LoggingAbstract implements RowyLogging {
59+
private readonly fieldName: string;
60+
private readonly rowId: string;
61+
62+
constructor(
63+
projectId: string,
64+
fieldName: string,
65+
rowId: string,
66+
functionType: FunctionType
67+
) {
68+
super(projectId, functionType);
69+
this.fieldName = fieldName;
70+
this.rowId = rowId;
71+
}
72+
73+
async logWithSeverity(payload: any, severity: string) {
74+
const log = this.logging.log(`rowy-logging`);
75+
const metadata = {
76+
severity,
77+
};
78+
const payloadSize = JSON.stringify(payload).length;
79+
const entry = log.entry(metadata, {
80+
loggingSource: "backend-scripts",
81+
functionType: this.functionType,
82+
fieldName: this.fieldName,
83+
rowId: this.rowId,
84+
payload: payloadSize > 250000 ? { v: "payload too large" } : payload,
85+
});
86+
await log.write(entry);
87+
}
88+
}
89+
90+
export { LoggingFactory, RowyLogging };

src/logging/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,5 @@ export async function getLogs(req: Request) {
6161
return entry.toJSON();
6262
});
6363
}
64+
65+
export { LoggingFactory, RowyLogging } from "./LoggingFactory";

src/scripts/action.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { FieldValue } from "firebase-admin/firestore";
77
import rowy from "./rowy";
88
import { installDependenciesIfMissing } from "../utils";
99
import { telemetryRuntimeDependencyPerformance } from "../rowyService";
10+
import { LoggingFactory } from "../logging";
1011

1112
type Ref = {
1213
id: string;
@@ -87,8 +88,13 @@ export const actionScript = async (req: Request, res: Response) => {
8788
`action ${column.key} in ${ref.path}`
8889
);
8990

91+
const logging = await LoggingFactory.createActionLogging(
92+
column.key,
93+
ref.id
94+
);
95+
9096
const _actionScript = eval(
91-
`async ({ row, db, ref, auth, utilFns, actionParams, user, fetch, rowy }) => ${codeToRun}`
97+
`async ({ row, db, ref, auth, utilFns, actionParams, user, fetch, rowy, tableSchema, logging }) => ${codeToRun}`
9298
);
9399
const getRows = refs
94100
? refs.map(async (r) => db.doc(r.path).get())
@@ -118,6 +124,8 @@ export const actionScript = async (req: Request, res: Response) => {
118124
user: { ...authUser2rowyUser(user), roles: userRoles },
119125
fetch,
120126
rowy,
127+
logging,
128+
tableSchema: schemaDocData,
121129
});
122130
if (result.success || result.status) {
123131
const cellValue = {

src/scripts/connector.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Auth } from "firebase-admin/auth";
88
import * as admin from "firebase-admin";
99
import { installDependenciesIfMissing } from "../utils";
1010
import { telemetryRuntimeDependencyPerformance } from "../rowyService";
11+
import { LoggingFactory, RowyLogging } from "../logging";
1112

1213
type ConnectorRequest = {
1314
rowDocPath: string;
@@ -25,6 +26,8 @@ type ConnectorArgs = {
2526
rowy: Rowy;
2627
fetch: any;
2728
storage: admin.storage.Storage;
29+
logging: RowyLogging;
30+
tableSchema: any;
2831
};
2932

3033
type Connector = (args: ConnectorArgs) => Promise<any[]> | any[];
@@ -69,8 +72,13 @@ export const connector = async (req: Request, res: Response) => {
6972
`connector ${columnKey} in ${rowDocPath}`
7073
);
7174

75+
const logging = await LoggingFactory.createConnectorLogging(
76+
columnKey,
77+
schemaDoc.ref.id
78+
);
79+
7280
const connectorScript = eval(
73-
`async ({ row, db, ref, auth, fetch, rowy, storage }) =>` +
81+
`async ({ row, db, ref, auth, fetch, rowy, storage, logging, tableSchema }) =>` +
7482
connectorFnBody
7583
) as Connector;
7684
const pattern = /row(?!y)/;
@@ -88,6 +96,8 @@ export const connector = async (req: Request, res: Response) => {
8896
user,
8997
storage,
9098
rowy,
99+
logging,
100+
tableSchema: schemaDocData,
91101
});
92102

93103
const functionEndTime = Date.now();

src/scripts/derivative.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { DocumentReference } from "firebase-admin/firestore";
66
import rowy from "./rowy";
77
import { installDependenciesIfMissing } from "../utils";
88
import { telemetryRuntimeDependencyPerformance } from "../rowyService";
9+
import { LoggingFactory } from "../logging";
910

1011
type RequestData = {
1112
refs?: DocumentReference[]; // used in bulkAction
@@ -62,8 +63,13 @@ export const evaluateDerivative = async (req: Request, res: Response) => {
6263
`derivative ${columnKey} in ${collectionPath}`
6364
);
6465

66+
const logging = await LoggingFactory.createDerivativeLogging(
67+
columnKey,
68+
schemaDoc.ref.id
69+
);
70+
6571
const derivativeFunction = eval(
66-
`async ({ row, db, ref, auth, fetch, rowy }) =>` +
72+
`async ({ row, db, ref, auth, fetch, rowy, logging, tableSchema }) =>` +
6773
code.replace(/^.*=>/, "")
6874
);
6975
let rowSnapshots: FirebaseFirestore.DocumentSnapshot<FirebaseFirestore.DocumentData>[] =
@@ -90,6 +96,8 @@ export const evaluateDerivative = async (req: Request, res: Response) => {
9096
ref: doc.ref,
9197
fetch,
9298
rowy,
99+
logging,
100+
tableSchema: schemaDocData,
93101
});
94102
const update = { [columnKey]: result };
95103
if (schemaDocData?.audit !== false) {

0 commit comments

Comments
 (0)