Облачные функции Firebase с Typescript, как привести сложный интерфейс - PullRequest
0 голосов
/ 27 января 2019

На стороне приложения я могу запросить коллекцию и автоматически привести результат в качестве интерфейса.Positions имеет конструктор, который принимает интерфейс IPosition.

Похоже, что то же самое в облачных функциях не позволяет развертывать функции.Трудно отладить код, так как он должен быть развернут и работает только тогда, когда код работает (локальное обслуживание требует некоторых разрешений).

Мне удалось сузить его, удалив большую часть кода и добавляя его построчно, пока я не наткнулся на это.

Я предполагаю, что это связано с интерфейсом, имеющим свойства типа enum.Приведение position в качестве IPosition также не работает.

Также интерфейс импортируется из другого модуля (модуля родительского приложения)

import { Position } from '../../src/app/models/position';
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { UserRecord } from 'firebase-functions/lib/providers/auth';

admin.initializeApp();
const promisePool = require('es6-promise-pool');
const PromisePool = promisePool.PromisePool;
// const secureCompare = require('secure-compare');
const MAX_CONCURRENT = 3;

const store = admin.firestore();

exports.updateMetrics = functions.https.onRequest((req, res) => {
  // const key = req.query.key;

  // // Exit if the keys don't match.
  // if (!secureCompare(key, functions.config().cron.key)) {
  //   console.log(
  //     'The key provided in the request does not match the key set in the environment. Check that',
  //     key,
  //     'matches the cron.key attribute in `firebase env:get`'
  //   );
  //   res
  //     .status(403)
  //     .send(
  //       'Security key does not match. Make sure your "key" URL query parameter matches the ' +
  //         'cron.key environment variable.'
  //     );
  //   return null;
  // }

  // Fetch all user.
  return getUsers()
    .then(users => {
      // Use a pool so that we delete maximum `MAX_CONCURRENT` users in parallel.
      const pool = new PromisePool(
        () => runMetricsAnalysis(users),
        MAX_CONCURRENT
      );
      return pool.start();
    })
    .then(() => {
      console.log('metrics updated');
      res.send('metrics updated');
      return null;
    });
});

/**
 * Returns the list of all users.
 */
function getUsers(users: UserRecord[] = [], nextPageToken?: string) {
  let tempUsers: UserRecord[] = users;
  return admin
    .auth()
    .listUsers(1000, nextPageToken)
    .then(result => {
      // Concat with list of previously found users if there was more than 1000 users.
      tempUsers = tempUsers.concat(result.users);

      // If there are more users to fetch we fetch them.
      if (result.pageToken) {
        return getUsers(tempUsers, result.pageToken);
      }

      return tempUsers;
    });
}

function runMetricsAnalysis(users: UserRecord[]) {
  if (users.length > 0) {
    const user = users.pop();
    if (user != null) {
      return getPositions(user)
        .then(positions => {
          const metrics = generateMetrics(positions);
          console.log('metrics', metrics);
          return null;
          // return writeMetrics(user.uid, metrics).catch(function(err) {
          //   console.error(err);
          //   return null;
          // });
        })
        .catch(function(err) {
          console.error(err);
          return null;
        });
    }
    return null;
  }
  return null;
}

/**
 * Returns the list of positions for the previous month.
 */
function getPositions(user: UserRecord) {
  return store
    .collection(`users/${user.uid}/positions`)
    .orderBy('postedDate', 'desc')
    .get()
    .then(querySnapshot => querySnapshot.docs.map(doc => doc.data()));
}

interface IMetrics {
  portfolioValue: number;
  profitLoss: number;
  fees: number;
}

/**
 * Generate metrics from positions
 */
function generateMetrics(positions: Array<any>): IMetrics {
  let portfolioValue = 0;
  let profitLoss = 0;
  let fees = 0;
  if (positions.length > 0) {
    console.log('positions 5', positions);
    positions
      .map(position => new Position(position))
      .map(position => {
        portfolioValue += position.positionValue;
        profitLoss += position.profitLossClosedQuantity;
        fees += position.fees;
      });
  }

  const IMetric = {
    portfolioValue: portfolioValue,
    profitLoss: profitLoss,
    fees: fees
  };
  return IMetric;
}

Позиция

export interface IPosition {
  ...
}

export class Position implements IPosition {
  ...

  constructor(position: IPosition) {
  ...
  }
}

Обновление:

Мне не удалось ранее увидеть ошибку по какой-то причине (возможно, потому, что она просто развернула кешированную версию работающей функции.

Here is the error: 

Error: Error occurred while parsing your function triggers.

TypeError: Cannot read property 'Timestamp' of undefined
    at Object.<anonymous> (/Users/AceGreen/Library/Mobile Documents/com~apple~CloudDocs/Dev/Web/TradingTracker/functions/lib/src/app/models/position.js:5:33)
    at Module._compile (internal/modules/cjs/loader.js:736:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:747:10)
    at Module.load (internal/modules/cjs/loader.js:628:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:568:12)
    at Function.Module._load (internal/modules/cjs/loader.js:560:3)
    at Module.require (internal/modules/cjs/loader.js:665:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/Users/AceGreen/Library/Mobile Documents/com~apple~CloudDocs/Dev/Web/TradingTracker/functions/lib/index.js:3:20)
    at Module._compile (internal/modules/cjs/loader.js:736:30)

перевод позиции.js

const app_1 = require("firebase/app");
var Timestamp = app_1.firestore.Timestamp;

1 Ответ

0 голосов
/ 28 января 2019

Мне удалось решить эту проблему.Кажется, проблема заключалась в том, как я импортировал метку времени.

const app_1 = require("firebase/app");
var Timestamp = app_1.firestore.Timestamp;

Правильный путь:

const app_1 = require("firebase");
var Timestamp = app_1.firestore.Timestamp;

ВАЖНО Примечание:

  • Кажется, что firebase deploy - только функции будут использовать кэшированную версию вашей функции, если она не сможет разрешить текущую функцию.Я говорю это потому, что запуск lint, когда в моей функции была ссылка на метку времени, не привел к ошибке, и похоже, что развертывание прошло успешно.Поскольку у меня уже была развернута та же функция, она, похоже, использовала кэшированную версию.

  • Мне удалось уловить проблему, только когда я переключил компьютеры и мне пришлось переустановить firebase-cli и заново развернуть, тогда он указал на неправильную ссылку на метку времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...