2

I added Cloud Functions to Firebase project with Firebase CLI. I have started with JavaScript, managed to write working code.

Then I decided to switch to TypeScript. So I decided to delete all Cloud Functions JS related files and start with firebase init cmd from scratch. I copied code from index.js to index.ts, needed only to change how dataMap Map was declared.

So, now whenever I look into console logs on Firebase, everything seems to work fine, everything is logged out, and I'm getting success message on client side.

However nothing happens in Realtime Database, no update, no trace of any data.

I know almost nothing about JS / TS, so every suggestion about code and solution is welcomed.

I'm using node: 14.17.6 and updated firebase-tools to 9.18.0, firebase-admin to 9.11.1 and firebase-functions to 3.15.6.

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();

exports.createItemWithVIP = functions.region("europe-west1").
    https.onCall((data, context) => {
      // Checking that the user is authenticated.
      if (!context.auth) {
        console.log("Unauthenticated request");
        throw new functions.https.HttpsError("permission-denied", "You have" +
          " no permission to perform this operation");
      }

      // item details
      const foo = data.foo;
      const bar = data.bar;
      console.log(`foo: ${foo}, bar: ${bar}`);

      const userUID = context.auth.uid;
      console.log(`userUID: ${userUID}`);

      const db = admin.database();
      // get new item uid
      const somePathTableReference = db.ref("somePath/").push();
      const itemUID = `${somePathTableReference}`
          .split("somePath/")[1];
      console.log(`itemUID: ${itemUID}`);

      const itemPath = `somePath/${itemUID}`;
      const userPath = `users/${userUID}/somePath/${itemUID}`;

      const dataMap = new Map<string, unknown>();
      dataMap.set(`${itemPath}/vip/${userUID}`, true);
      dataMap.set(`${itemPath}/foo`, foo);
      dataMap.set(`${itemPath}/bar`, bar);
      dataMap.set(`${userPath}/role`, "vip");
      dataMap.set(`${userPath}/foo`, foo);
      dataMap.set(`${userPath}bar`, bar);

      dataMap.forEach((value: unknown, key: string) =>
        console.log(key, value));

      return db.ref("/").update(dataMap).then(() => {
        console.log(`Added new item with key: ${itemUID} ` +
          `; added vip role to user ${userUID}`);
        return {"message": "Success"};
      }).catch((e) => {
        console.log(`Error: ${e}`);
        throw new functions.https.HttpsError("unknown", "Unknown error" +
          "occured");
      });
    });


Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
paj-co
  • 118
  • 5
  • Trying to debug all this code if nothing gets written is not a very efficient first pass to debug a problem. If you replace the entire body of the function with `return db.ref("test").set(true);` does that value get written? – Frank van Puffelen Sep 17 '21 at 19:54
  • Are you by any chance using the emulator? – Hydra Sep 17 '21 at 22:59
  • @FrankvanPuffelen I believe, I checked some simple `update` case, but it was still with TS Map, which was the reason for the problem. I also misunderstood the JS/TS syntax as I stated below Dharmaraj answer. But, yes, yours simple `update` case was working :) @Hydra no emulator here :) – paj-co Sep 20 '21 at 09:41

2 Answers2

2

I'm not totally sure about the reason but updating with an object directly instead of new Map() seems to be working (and yes, it didn't work for me with a Map):

const dMap = {
  [`${itemPath}/vip/${userUID}`]: true,
  [`${itemPath}/foo`]: foo,
  [`${itemPath}/bar`]: bar,
  [`${userPath}/role`]: "vip",
  [`${userPath}/foo`]: foo,
  [`${userPath}bar`]: bar
}

try {
  await db.ref("/").update(dMap);
  console.log(`Added new item with key: ${itemUID}; added vip role to user ${userUID}`);

  return {"message": "Success"};
} catch (e) {
  console.log(`Error: ${e}`);
  throw new functions.https.HttpsError("unknown", "Unknown error" +
    "occured");
}
Dharmaraj
  • 47,845
  • 8
  • 52
  • 84
  • However I think that error occurred due to my lack of JS / TS knowledge. Because coming from Dart world where `{}` means map, I previously in my JS code declared dataMap variable as: `const dataMap = {}; dataMap["key"] = "foo";` When setting values for `{}` like this `dataMap[`${itemPath}/foo`] = foo;` was no longer valid, I just found the TS way of declaring a map. But it seems that `{}` was never a classic map? But some kind of `Object` type :) – paj-co Sep 20 '21 at 09:27
  • @paj-co so object and map are somewhat similar as in [this answer](https://stackoverflow.com/questions/18541940/map-vs-object-in-javascript). What do you mean by "no longer valid"? Can you share the error? Also it might be better to ask another question for clarifying that so the question gets more views rather than in comments here. – Dharmaraj Sep 20 '21 at 10:01
  • I just meant that, I could do that `const dataMap = {}; dataMap["key"] = "foo";` in JavaScript, but in TypeScript VS Code got me red underline with error: `Element implicitly has an 'any' type because expression of type '"key"' can't be used to index type '{}'. Property 'key' does not exist on type '{}'.` I don’t really know JS / TS. And I think that my problem occurred due to my lack in language and it syntax, so I don’t think I could ask another, proper question in this subject :) – paj-co Oct 18 '21 at 08:13
0

This works for me.

const dMap: { [key: string]: any; } = {};

dMap[`${itemPath}/vip/${userUID}`]= true;
dMap[`${itemPath}/foo`]= foo;
dMap[`${itemPath}/bar`]= bar;
dMap[`${userPath}/role`]= "vip";
dMap[`${userPath}/foo`]= foo;
dMap[`${userPath}bar`]= bar;

db.ref().update(dMap);
Loscho19
  • 11
  • 2