Firebase, как разорвать транзакцию базы данных в реальном времени с другим состоянием / сообщением, если другое условие истинно? - PullRequest
0 голосов
/ 30 августа 2018

Я знаю, что уже задавал много разных вопросов о моем случае, но я не нахожу в Google примеров, похожих на мой случай: (* ​​1001 *

И это моя первая попытка использовать firebase (и вообще базы данных javascript и nosql), так что на данный момент транзакция представляет для меня большую боль.

Итак, мой вопрос:

это хорошая практика вообще и если да каков правильный разрыв транзакции с различными состояниями ошибок / сообщениями для разных ситуаций?

У меня транзакция, проходящая через запись «предложение» с резервированием «мест»:

Я хочу прервать его, если выполняется одно из следующих 3 условий и вернуть состояние / сообщение функции вызывающей стороны .

  1. если запрашивающий пользователь уже зарезервировал места для этого предложения.
  2. если мест не хватает.
  3. если это предложение не существует.

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

Я не уверен, как прервать транзакцию в случае выполнения одного из условий.

  • если я использую , генерируем новую ошибку ('описание проблемы.') , тогда это будет Исключение , и оно не обрабатывается обработчиком catch () транзакции Promise и я не уверен, как обработать это исключение, потому что это асинхронная функция здесь. так что я думаю, что я не должен использовать исключение.

Вот что я имею в виду:

dealSeats = function(entryRef, data) {
    const TAG = '[dealSeats]: ';
    return entryRef.transaction((entry)=>{
        if (entry) {
            if ((entry.deals) && (entry.deals[data.uid])) {
                **? how to break the transaction with state/message 'You already have a deal.' ? and how to handle it below ?**
            } else if (entry.details.seatsCount >= data.details.seatsCount) {
                entry.details.seatsCount -= data.details.seatsCount;
                var deal = [];
                deal.status = 'asked';
                deal.details = data.details;
                if (!entry.deals) {
                    entry.deals = {};
                }
                entry.deals[data.uid] = deal;
            } else {
                **? how to break the transaction with state/message 'Not enought seats.' ? and how to handle it below ?**
            }
        }
        return entry;
        **? how to check if 'entry' is really null ? i.e. offer does not exists ?** and break and handle it.
    })
    .then((success)=>{
        return success.snapshot.val();
    })
    .catch((error)=>{
        return Promise.reject(error);
    });
}

вот мои данные в базе данных в реальном времени:

activeOffers
 -LKohyZ58cnzn0vCnt9p
    details
        direction: "city"
        seatsCount: 2
        timeToGo: 5
    uid: "-ABSIFJ0vCnt9p8387a"    ---- offering user

вот мои тестовые данные, отправленные почтальоном:

{
 "data": 
  {
     "uid": "-FGKKSDFGK12387sddd",    ---- the requesting/asking user
     "id": "-LKpCACQlL25XTWJ0OV_",
     "details":
     {
         "direction": "city",
         "seatsCount": 1,
         "timeToGo": 5
     }
  }
}

==== обновлено с окончательным источником ====

большое спасибо Renaud Tarnec!

Итак, вот мой последний источник, который работает нормально. Если кто-то видит потенциальную проблему, пожалуйста, дайте мне знать. Спасибо.

dealSeats = function(entryRef, data) {
    const TAG = '[dealSeats]: ';
    var abortReason;

    return entryRef.transaction((entry)=>{
        if (entry) {
            if ((entry.deals) && (entry.deals[data.uid])) {
                abortReason = 'You already made a reservation';
                return; // abort transaction
            } else if (entry.details.seatsCount >= data.details.seatsCount) {
                entry.details.seatsCount -= data.details.seatsCount;
                var deal = [];
                deal.status = 'asked';
                deal.details = data.details;
                if (!entry.deals) {
                    entry.deals = {};
                }
                entry.deals[data.uid] = deal;
                // Reservation is made
            } else {
                abortReason = 'Not enought seats';
                return; // abort transaction
            }
        }
        return entry;
    })
    .then((result)=>{ // resolved
        if (!result.committed) { // aborted
            return abortReason;
        } else {
            let value = result.snapshot.val();
            if (value) {
                return value;
            } else {
                return 'Offer does not exists';
            }
        }
    })
    .catch((reason)=>{ // rejected
        return Promise.reject(reason);
    });
}

Единственная проблема - предупреждение во время развертывания в терминале VSCode об этом прерывании, не возвращая значения:

warning  Arrow function expected no return value  consistent-return

В настоящее время я не уверен, что смогу что-нибудь с этим сделать.

1 Ответ

0 голосов
/ 30 августа 2018

Посмотрите на этот документ в Справочной документации по API Firebase: https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction

Ниже приведен код из этого документа. Посмотрите, как return; используется для прерывания транзакции (в документе также сказано: «вы прерываете транзакцию, не возвращая значение из функции обновления»). И обратите внимание, как этот конкретный случай обрабатывается в функции обратного вызова onComplete(), которая вызывается по завершении транзакции (в пределах else if (!committed) {}).

// Try to create a user for ada, but only if the user id 'ada' isn't
// already taken
var adaRef = firebase.database().ref('users/ada');
adaRef.transaction(function(currentData) {
  if (currentData === null) {
    return { name: { first: 'Ada', last: 'Lovelace' } };
  } else {
    console.log('User ada already exists.');
    return; // Abort the transaction.
  }
}, function(error, committed, snapshot) {
  if (error) {
    console.log('Transaction failed abnormally!', error);
  } else if (!committed) {
    console.log('We aborted the transaction (because ada already exists).');
  } else {
    console.log('User ada added!');
  }
  console.log("Ada's data: ", snapshot.val());
});

Итак, ИМХО, вы должны использовать тот же шаблон и в тех местах кода, где вы спрашиваете «**? Как прервать транзакцию», которую вы делаете return;.

Обновление: Вы можете дифференцировать случаи аборта с помощью переменной следующим образом. Если вы добавите через консоль Firebase узел age со значением> 20 до users.ada.name, первая причина прерывания беременности будет вызвана.

var adaRef = firebase.database().ref('users/ada');
var transactionAbortionCause;  //new variable
adaRef.transaction(function(currentData) {
  if (currentData === null) {
    return { name: { first: 'Ada', last: 'Lovelace' } };
  } else if (currentData.name.age > 20) {
    transactionAbortionCause = 'User ada is older than 20'; //update the variable
    console.log('User ada is older than 20');
    return; // Abort the transaction.
  } else {
    transactionAbortionCause = 'User ada already exists'; //update the variable
    console.log('User ada already exists');
    return; // Abort the transaction.
  }
}, function(error, committed, snapshot) {
  if (error) {
    console.log('Transaction failed abnormally!', error);
  } else if (!committed) {
    console.log('We aborted the transaction because ' + transactionAbortionCause);  //use the variable
  } else {
    console.log('User ada added!');
  }
  console.log("Ada's data: ", snapshot.val());
});

Если я не ошибаюсь, вы, облако, также делаете это с обещаниями, как вы делаете в своем коде. В документе говорится, что транзакция возвращает ненулевое значение firebase.Promise, содержащее {committed: boolean, snapshot: nullable firebase.database.DataSnapshot}, и поясняется, что это обещание "может дополнительно использоваться вместо обратного вызова onComplete для обработки успеха и неудачи".

Итак:

  1. Выполнение return; для ваших двух случаев аборта и
  2. Чтение значения committed логического

вы должны иметь возможность обрабатывать случаи абортов в вашем коде, выполнив

.then((result)=>{
    if (result.commited) {... } else { /*abortion!*/}
}) 

Я не проверял этот подход, однако

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