توسيع نطاق SQL Connect باستخدام Cloud Functions

باستخدام Cloud Functions for Firebase، يمكنك التعامل مع الأحداث في Firebase SQL Connect. تتيح لك Cloud Functions تشغيل رمز من جهة الخادم استجابةً للأحداث، مثل تنفيذ عملية تغيير في خدمة SQL Connect. يتيح لك ذلك إضافة منطق مخصّص بدون نشر خوادمك الخاصة.

حالات الاستخدام الشائعة

  • مزامنة البيانات: يمكنك تكرار البيانات أو مزامنتها مع أنظمة أخرى (مثل Cloud Firestore أو BigQuery أو واجهات برمجة التطبيقات الخارجية) بعد حدوث تغيير.

  • مهام سير العمل غير المتزامنة: يمكنك بدء عمليات طويلة الأمد، مثل معالجة الصور أو تجميع البيانات، بعد تغيير قاعدة البيانات.

  • تفاعل المستخدمين: يمكنك إرسال رسائل إلكترونية أو إشعارات Cloud Messaging إلى المستخدمين بعد حدث تغيير معيّن في تطبيقك، مثل إنشاء حساب.

تفعيل دالة عند حدوث تغيير في SQL Connect

يمكنك تشغيل دالة كلما تم تنفيذ عملية تغيير SQL Connect باستخدام معالج الأحداث onMutationExecuted. يحدث هذا المشغّل عند تنفيذ تغيير.

دالة أساسية لحدث تغيير

المثال الأساسي التالي هو دالة تسجّل تفاصيل أي تغيير يتم تنفيذه في خدمة SQL Connect:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

export const logMutation = onMutationExecuted(
  {
    /* Trigger on all mutations, spanning all services and connectors
       in us-central1 */
  },
  (event) => {
    logger.info("A mutation was executed!", {
      data: event.data,
    });
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed()
def log_mutation(event: dataconnect_fn.Event):
  logger.info("A mutation was executed!", event.data)

عند تفعيل جميع التغييرات في مشروعك، يجب عدم إجراء أي تغييرات في معالج المشغّلات وإلا ستتسبّب في حدوث تكرار حلقي لا نهائي. إذا أردت إجراء عمليات تحويل في مشغّل حدث، استخدِم خيارات الفلترة الموضّحة أدناه، واحرص على ألا يؤدي التحويل إلى تشغيل نفسه.

ضبط موقع الدالة

يجب أن يتطابق موقع الدالة الجغرافي مع موقع خدمة SQL Connect الجغرافي لكي تؤدي الأحداث إلى تشغيل الدالة. تكون منطقة الدالة تلقائيًا هي us-central1.

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

export const onMutationRegionOption = onMutationExecuted(
  {
    region: "europe-west1"  // Set if SQL Connect service location is not us-central1
  },
  (event) => { /* ... */ }
);

Python

@dataconnect_fn.on_mutation_executed(
  region="europe-west1"  # Set if SQL Connect service location is not us-central1
)
def mutation_executed_handler_region_option(event: dataconnect_fn.Event):
  pass

فلترة الأحداث

يمكن ضبط معالج onMutationExecuted باستخدام خيارات لفلترة الأحداث استنادًا إلى سمات معيّنة. يكون ذلك مفيدًا عندما تريد تشغيل الدالة لبعض التغييرات فقط.

يمكنك الفلترة حسب service وconnector وoperation:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

// Trigger this function only for the CreateUser mutation
// in the users connector of the myAppService service.
export const onUserCreate = onMutationExecuted(
  {
    service: "myAppService",
    connector: "users",
    operation: "CreateUser",
  },
  (event) => {
    logger.info("A new user was created!", event.data);
    // Add logic here: for example, sending a welcome email.
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  connector="users",
  operation="CreateUser"
):
def on_user_create(event: dataconnect_fn.Event):
  logger.info("A new user was created!", event.data)

أحرف البدل ومجموعات الالتقاط

يمكنك استخدام أحرف البدل ومجموعات الالتقاط لفلترة المشغّلات حسب قيم متعددة. تتوفّر أي مجموعات تم التقاطها في "event.params" لاستخدامها. لمزيد من المعلومات، يمكنك الاطّلاع على فهم أنماط المسارات.

أمثلة:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

// Trigger on all operations that match the pattern `User*`, on any service and
// connector.
export const onMutationWildcards = onMutationExecuted(
  {
    operation: "User*",
  },
  (event) => {}
);

// Trigger on all operations that match the pattern `User*`, on any service and
// connector. Capture the operation name in the variable `op`.
export const onMutationCaptureWildcards = onMutationExecuted(
  {
    operation: "{op=User*}",
  },
  (event) => {
    // `event.params.op` contains the operation name.
  }
);

// Trigger on all operations on the service `myAppService`. Capture the
// operation name in the variable `operation`.
export const onMutationCaptures = onMutationExecuted(
  {
    service: "myAppService",
    operation: "{operation}",
  },
  (event) => {
    // `event.params.operation` contains the operation name.
  }
);

Python

from firebase_functions import dataconnect_fn

# Trigger on all operations that match the pattern `User*`, on any service and
# connector.
@dataconnect_fn.on_mutation_executed(
  operation="User*"
)
def on_mutation_wildcards(event: dataconnect_fn.Event):
  pass

# Trigger on all operations that match the pattern `User*`, on any service and
# connector. Capture the operation name in the variable `op`.
@dataconnect_fn.on_mutation_executed(
  operation="{op=User*}"
)
def on_mutation_capture_wildcards(event: dataconnect_fn.Event):
  # `event.params["op"]` contains the operation name.
  pass

# Trigger on all operations on the service `myAppService`. Capture the
# operation name in the variable `operation`.
@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  operation="{operation}"
)
def on_mutation_captures(event: dataconnect_fn.Event):
  # `event.params["operation"]` contains the operation name.
  pass

الوصول إلى معلومات مصادقة المستخدم

يمكنك الوصول إلى معلومات مصادقة المستخدم حول المستخدم الرئيسي الذي بدأ الحدث. لمزيد من المعلومات حول البيانات المتاحة في سياق المصادقة، يُرجى الاطّلاع على سياق المصادقة.

يوضّح المثال التالي كيفية استرداد معلومات المصادقة:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";

export const onMutation = onMutationExecuted(
  { operation: "MyMutation" },
  (event) => {
    // mutationExecuted event provides authType and authId:
    // event.authType
    // event.authId
  }
);

Python

from firebase_functions import dataconnect_fn

@dataconnect_fn.on_mutation_executed(operation="MyMutation")
def mutation_executed_handler(event: dataconnect_fn.Event):
  # mutationExecuted event provides auth_type and auth_id, which are accessed as follows
  # event.auth_type
  # event.auth_id
  pass

ستتم تعبئة نوع المصادقة ومعرّف المصادقة على النحو التالي:

Mutation initiated by authtype authid
المستخدم النهائي الذي تمت مصادقته app_user رقم تعريف المستخدم لرمز Firebase Auth المميّز
مستخدم نهائي لم تتم مصادقته unauthenticated فارغ
انتحال مدير SDK هوية مستخدم نهائي app_user رقم تعريف المستخدم (UID) للرمز المميّز في Firebase Auth الخاص بالمستخدم الذي تم انتحال هويته
انتحال مدير SDK لطلب غير مصادَق عليه unauthenticated فارغ
‫مدير SDK مع أذونات كاملة admin فارغ

الوصول إلى بيانات الأحداث

يحتوي الكائن CloudEvent الذي تم تمريره إلى الدالة على معلومات حول الحدث الذي أدى إلى تشغيلها.

سمات الأحداث

السمة النوع الوصف
id string معرّف فريد للحدث
source string مورد الموصّل الذي أنتج الحدث (على سبيل المثال، //firebasedataconnect.googleapis.com/projects/*/locations/*/services/*/connectors/*).
specversion string إصدار مواصفات CloudEvents (مثل "1.0")
type string نوع الحدث: google.firebase.dataconnect.connector.v1.mutationExecuted
time string الطابع الزمني (بتنسيق ISO 8601) لوقت إنشاء الحدث
subject string اختياريّ. معلومات إضافية حول سياق الحدث، مثل اسم العملية
params object خريطة لأنماط المسارات التي تم تسجيلها
authType string قيمة تعداد تمثّل نوع المستخدم الرئيسي الذي بدأ الحدث
authId string معرّف فريد للمستخدم الرئيسي الذي بدأ الحدث
data MutationEventData حمولة الحدث SQL Connect يُرجى الاطّلاع على القسم التالي.

حمولة البيانات

يحتوي الكائن MutationEventData على حمولة الحدث SQL Connect:

{
  // ...
  "authType": // ...
  "data": {
    "payload": {
      "variables": {
        "userId": "user123",
        "updateData": {
          "displayName": "New Name"
        }
      },
      "data": {
        "updateUser": {
          "id": "user123",
          "displayName": "New Name",
          "email": "user@example.com"
        }
      },
      "errors": []
    }
  }
}
  • ‫payload.variables: عنصر يحتوي على المتغيّرات التي تم تمريرها إلى التغيير.
  • ‫payload.data: عنصر يحتوي على البيانات التي تم عرضها من خلال التعديل.
  • ‫payload.errors: مصفوفة من أي أخطاء حدثت أثناء تنفيذ التغيير. إذا نجحت عملية التغيير، ستكون هذه المصفوفة فارغة.

مثال

في ما يلي كيفية الوصول إلى متغيّرات التعديل والبيانات التي يتم عرضها:

Node.js

import { onMutationExecuted } from "firebase-functions/dataconnect";
import { logger } from "firebase-functions";

export const processNewUserData = onMutationExecuted(
  {
    "service": "myAppService",
    "connector": "users",
    "operation": "CreateUser",
  },
  (event) => {
    // The variables passed to the mutation
    const mutationVariables = event.data.payload.variables;

    // The data returned by the mutation
    const returnedData = event.data.payload.data;

    logger.info("Processing mutation with variables:", mutationVariables);
    logger.info("Mutation returned:", returnedData);

    // ... your custom logic here
  }
);

Python

from firebase_functions import dataconnect_fn, logger

@dataconnect_fn.on_mutation_executed(
  service="myAppService",
  connector="users",
  operation="CreateUser"
):
def process_new_user_data(event: dataconnect_fn.Event):
  # The variables passed to the mutation
  mutation_vars = event.data.payload.variables
  # The data returned by the mutation
  returned_data = event.data.payload.data

  logger.info("Processing mutation with variables:", mutationVariables)
  logger.info("Mutation returned", returnedData)

  # ... your custom logic here

يُرجى العِلم أنّه على عكس بعض مشغّلات قواعد البيانات الأخرى، مثل Cloud Firestore أو Realtime Database، لا يوفّر الحدث SQL Connect لقطة "قبل" للبيانات. بما أنّ SQL Connect يرسل طلبات بالوكالة إلى قاعدة البيانات الأساسية، لا يمكن الحصول على لقطة "قبل" للبيانات من خلال المعاملات. بدلاً من ذلك، يمكنك الوصول إلى الوسيطات المرسَلة إلى التعديل والبيانات التي تم عرضها من خلاله.

ومن نتائج ذلك أنّه لا يمكنك استخدام استراتيجية مقارنة اللقطات "قبل" و "بعد" لتجنُّب التكرار الحلقي اللانهائي، حيث يؤدي عامل تشغيل الحدث إلى تشغيل الحدث نفسه. إذا كان عليك إجراء تغيير من دالة يتم تشغيلها بواسطة حدث تغيير، فاستخدم فلاتر الأحداث واحرص على التأكد من عدم إمكانية تشغيل أي تغيير لنفسه، حتى بشكل غير مباشر.