কাস্টম রিজলভার লেখার মাধ্যমে, আপনি ক্লাউড এসকিউএল ছাড়াও অন্যান্য ডেটা সোর্স সমর্থন করার জন্য Firebase SQL Connect সম্প্রসারিত করতে পারেন। এরপর আপনি একাধিক ডেটা সোর্সকে (ক্লাউড এসকিউএল এবং আপনার কাস্টম রিজলভার দ্বারা প্রদত্ত ডেটা সোর্সগুলো) একটিমাত্র কোয়েরি বা মিউটেশনে একত্রিত করতে পারবেন।
'ডেটা সোর্স'-এর ধারণাটি নমনীয়। এর অন্তর্ভুক্ত বিষয়গুলো হলো:
- ক্লাউড এসকিউএল ছাড়াও অন্যান্য ডেটাবেস, যেমন ক্লাউড ফায়ারস্টোর, মঙ্গোডিবি এবং অন্যান্য।
- ক্লাউড স্টোরেজ, AWS S3 এবং অন্যান্য স্টোরেজ পরিষেবা।
- যেকোনো এপিআই-ভিত্তিক ইন্টিগ্রেশন, যেমন স্ট্রাইপ, সেন্ডগ্রিড, সেলসফোর্স এবং অন্যান্য।
- কাস্টম ব্যবসায়িক যুক্তি।
একবার আপনি আপনার অতিরিক্ত ডেটা উৎসগুলোকে সমর্থন করার জন্য কাস্টম রিজলভার লিখে ফেললে, আপনার SQL Connect কোয়েরি এবং মিউটেশনগুলো সেগুলোকে বিভিন্ন উপায়ে একত্রিত করতে পারে, যা নিম্নলিখিত সুবিধাগুলো প্রদান করে:
- আপনার ডেটা উৎসগুলির জন্য একটি সমন্বিত অনুমোদন স্তর। উদাহরণস্বরূপ, ক্লাউড এসকিউএল-এ সংরক্ষিত ডেটা ব্যবহার করে ক্লাউড স্টোরেজের ফাইলগুলিতে অ্যাক্সেসের অনুমোদন দিন।
- ওয়েব, অ্যান্ড্রয়েড এবং আইওএস-এর জন্য টাইপ-সেফ ক্লায়েন্ট এসডিকে।
- যেসব কোয়েরি একাধিক উৎস থেকে ডেটা ফেরত দেয়।
- আপনার ডাটাবেসের অবস্থার উপর ভিত্তি করে ফাংশন আহ্বান সীমাবদ্ধ।
পূর্বশর্ত
আপনার নিজস্ব কাস্টম রিজলভার লিখতে, আপনার নিম্নলিখিত জিনিসগুলির প্রয়োজন হবে:
- ফায়ারবেস সিএলআই সংস্করণ ১৫.৯.০ বা উচ্চতর
- ফায়ারবেস ফাংশন এসডিকে সংস্করণ ৭.১.০ বা উচ্চতর
এছাড়াও, আপনাকে Firebase-এর জন্য Cloud Functions ব্যবহার করে ফাংশন লিখতে পরিচিত হতে হবে, যেভাবে আপনি আপনার কাস্টম রিজলভারগুলির লজিক প্রয়োগ করবেন।
শুরু করার আগে
SQL Connect ব্যবহার করার জন্য আপনার আগে থেকেই একটি প্রজেক্ট সেট আপ করা থাকা উচিত।
আপনি যদি আগে থেকে প্রস্তুত না থাকেন, তাহলে প্রস্তুত হওয়ার জন্য কুইকস্টার্ট গাইডগুলোর মধ্যে একটি অনুসরণ করতে পারেন:
কাস্টম রিজলভার লিখুন
মোটামুটিভাবে বলতে গেলে, একটি কাস্টম রিজলভার লেখার তিনটি অংশ রয়েছে: প্রথমত, আপনার কাস্টম রিজলভারের জন্য একটি স্কিমা নির্ধারণ করা; দ্বিতীয়ত, ক্লাউড ফাংশন ব্যবহার করে আপনার রিজলভারগুলো ইমপ্লিমেন্ট করা; এবং সবশেষে, কোয়েরি ও মিউটেশনে আপনার কাস্টম রিজলভার ফিল্ডগুলো ব্যবহার করা, যা সম্ভবত ক্লাউড এসকিউএল বা অন্যান্য কাস্টম রিজলভারের সাথে একযোগে করা যেতে পারে।
কীভাবে তা করতে হয় তা শিখতে পরবর্তী কয়েকটি বিভাগের ধাপগুলো অনুসরণ করুন। একটি অনুপ্রেরণামূলক উদাহরণ হিসেবে, ধরুন আপনার ব্যবহারকারীদের পাবলিক প্রোফাইলের তথ্য ক্লাউড এসকিউএল-এর বাইরে সংরক্ষিত আছে। এই উদাহরণগুলোতে নির্দিষ্ট ডেটাস্টোর উল্লেখ করা হয়নি, তবে এটি ক্লাউড স্টোরেজ, একটি মঙ্গোডিবি ইনস্ট্যান্স বা অন্য কিছু হতে পারে।
নিম্নলিখিত বিভাগগুলিতে একটি কাস্টম রিজলভারের প্রাথমিক বাস্তবায়ন দেখানো হবে যা সেই বাহ্যিক প্রোফাইল তথ্যকে SQL Connect এ নিয়ে আসতে পারে।
আপনার কাস্টম রিজলভারের জন্য স্কিমা নির্ধারণ করুন।
আপনার Firebase প্রজেক্ট ডিরেক্টরিতে, চালান:
firebase init dataconnect:resolverFirebase CLI আপনার কাস্টম রিজলভারের জন্য একটি নাম চাইবে এবং টাইপস্ক্রিপ্ট বা জাভাস্ক্রিপ্টে উদাহরণ রিজলভার ইমপ্লিমেন্টেশন তৈরি করবেন কিনা তা জিজ্ঞাসা করবে। আপনি যদি এই নির্দেশিকা অনুসরণ করেন, তবে ডিফল্ট নামটি গ্রহণ করুন এবং টাইপস্ক্রিপ্ট উদাহরণ তৈরি করুন।
এরপর টুলটি একটি খালি
dataconnect/schema_resolver/schema.gqlফাইল তৈরি করবে এবং আপনার নতুন রিজলভার কনফিগারেশনটিdataconnect.yamlফাইলে যোগ করবে।এই
schema.gqlফাইলটিকে এমন একটি GraphQL স্কিমা দিয়ে আপডেট করুন যা আপনার কাস্টম রিজলভার দ্বারা প্রদত্ত কোয়েরি এবং মিউটেশনগুলিকে সংজ্ঞায়িত করে। উদাহরণস্বরূপ, এখানে একটি কাস্টম রিজলভারের জন্য একটি স্কিমা দেওয়া হল যা ক্লাউড SQL ছাড়া অন্য কোনও ডেটাস্টোরে সংরক্ষিত একজন ব্যবহারকারীর পাবলিক প্রোফাইল পুনরুদ্ধার এবং আপডেট করতে পারে:# dataconnect/schema_resolver/schema.gql type PublicProfile { name: String! photoUrl: String! bioLine: String! } type Query { # This field will be backed by your Cloud Function. publicProfile(userId: String!): PublicProfile } type Mutation { # This field will be backed by your Cloud Function. updatePublicProfile( userId: String!, name: String, photoUrl: String, bioLine: String ): PublicProfile }
কাস্টম রিজলভার লজিক প্রয়োগ করুন
এরপর, ক্লাউড ফাংশন ব্যবহার করে আপনার রিজলভারগুলো ইমপ্লিমেন্ট করুন। আড়ালে, আপনাকে একটি GraphQL সার্ভার তৈরি করতে হবে; তবে, ক্লাউড ফাংশনের onGraphRequest একটি হেল্পার মেথড আছে, যা এই কাজটি করার খুঁটিনাটি বিষয়গুলো সামলে নেয়। ফলে, আপনাকে শুধু সেই রিজলভার লজিকটি লিখতে হবে যা আপনার ডেটা সোর্স অ্যাক্সেস করে।
functions/src/index.tsফাইলটি খুলুন।আপনি যখন উপরে
firebase init dataconnect:resolverকমান্ডটি চালিয়েছিলেন, তখন এটি এই ক্লাউড ফাংশনস সোর্স কোড ডিরেক্টরিটি তৈরি করে এবংindex.tsএ থাকা নমুনা কোড দিয়ে এটিকে ইনিশিয়ালাইজ করে।নিম্নলিখিত সংজ্ঞাগুলো যোগ করুন:
import { FirebaseContext, onGraphRequest, } from "firebase-functions/dataconnect/graphql"; const opts = { // Points to the schema you defined earlier, relative to the root of your // Firebase project. schemaFilePath: "dataconnect/schema_resolver/schema.gql", resolvers: { query: { // This resolver function populates the data for the "publicProfile" field // defined in your GraphQL schema located at schemaFilePath. publicProfile( _parent: unknown, args: Record<string, unknown>, _contextValue: FirebaseContext, _info: unknown ) { const userId = args.userId; // Here you would use the user ID to retrieve the user profile from your data // store. In this example, we just return a hard-coded value. return { name: "Ulysses von Userberg", photoUrl: "https://example.com/profiles/12345/photo.jpg", bioLine: "Just a guy on a mountain. Ski fanatic.", }; }, }, mutation: { // This resolver function updates data for the "updatePublicProfile" field // defined in your GraphQL schema located at schemaFilePath. updatePublicProfile( _parent: unknown, args: Record<string, unknown>, _contextValue: FirebaseContext, _info: unknown ) { const { userId, name, photoUrl, bioLine } = args; // Here you would update in your datastore the user's profile using the // arguments that were passed. In this example, we just return the profile // as though the operation had been successful. return { name, photoUrl, bioLine }; }, }, }, }; export const resolver = onGraphRequest(opts);
এই কাঠামোবদ্ধ বাস্তবায়নগুলো একটি রিজলভার ফাংশনের সাধারণ রূপটি দেখায়। একটি সম্পূর্ণ কার্যকরী কাস্টম রিজলভার তৈরি করতে, আপনাকে কমেন্ট করা অংশগুলো আপনার ডেটা সোর্স থেকে ডেটা পড়া ও লেখার কোড দিয়ে পূরণ করতে হবে।
কোয়েরি এবং মিউটেশনে কাস্টম রিজলভার ব্যবহার করুন
এখন যেহেতু আপনি আপনার কাস্টম রিজলভারের স্কিমা নির্ধারণ করেছেন এবং এর পেছনের লজিকটি প্রয়োগ করেছেন, আপনি আপনার SQL Connect কোয়েরি এবং মিউটেশনগুলিতে কাস্টম রিজলভারটি ব্যবহার করতে পারেন। পরবর্তীতে, আপনি এই অপারেশনগুলি ব্যবহার করে স্বয়ংক্রিয়ভাবে একটি কাস্টম ক্লায়েন্ট SDK তৈরি করবেন, যা দিয়ে আপনি আপনার সমস্ত ডেটা অ্যাক্সেস করতে পারবেন; সেই ডেটা Cloud SQL, আপনার কাস্টম রিজলভার বা উভয়ের সমন্বয়ে সমর্থিত হোক না কেন।
dataconnect/example/queries.gqlফাইলে নিম্নলিখিত সংজ্ঞাটি যোগ করুন:query GetPublicProfile($id: String!) @auth(level: PUBLIC, insecureReason: "Anyone can see a public profile.") { publicProfile(userId: $id) { name photoUrl bioLine } }এই কোয়েরিটি আপনার কাস্টম রিজলভার ব্যবহার করে একজন ব্যবহারকারীর পাবলিক প্রোফাইল পুনরুদ্ধার করে।
dataconnect/example/mutations.gqlফাইলে নিম্নলিখিত সংজ্ঞাটি যোগ করুন:mutation SetPublicProfile( $id: String!, $name: String, $photoUrl: String, $bioLine: String ) @auth(expr: "vars.id == auth.uid") { updatePublicProfile(userId: $id, name: $name, photoUrl: $photoUrl, bioLine: $bioLine) { name photoUrl bioLine } }এই মিউটেশনটি আপনার কাস্টম রিজলভার ব্যবহার করে ডেটাস্টোরে প্রোফাইল ডেটার একটি নতুন সেট লিখে দেয়। উল্লেখ্য যে, স্কিমাটি SQL Connect এর
@authডিরেক্টিভ ব্যবহার করে এটি নিশ্চিত করে যে ব্যবহারকারীরা শুধুমাত্র তাদের নিজেদের প্রোফাইলই আপডেট করতে পারবে। যেহেতু আপনি SQL Connect এর মাধ্যমে আপনার ডেটাস্টোর অ্যাক্সেস করছেন, তাই আপনি স্বয়ংক্রিয়ভাবে SQL Connect এর এই ধরনের ফিচারগুলোর সুবিধা নিতে পারবেন।
উপরের উদাহরণগুলিতে, আপনি SQL Connect অপারেশনগুলি সংজ্ঞায়িত করেছেন যা আপনার কাস্টম রিজলভার ব্যবহার করে আপনার ডেটাস্টোর থেকে ডেটা অ্যাক্সেস করে। তবে, আপনার অপারেশনগুলি শুধুমাত্র ক্লাউড SQL বা একটি একক কাস্টম ডেটা উৎস থেকে ডেটা অ্যাক্সেস করার মধ্যে সীমাবদ্ধ নয়। একাধিক উৎস থেকে ডেটা একত্রিত করে এমন কিছু আরও উন্নত ব্যবহারের ক্ষেত্রের জন্য উদাহরণ বিভাগটি দেখুন।
তার আগে, আপনার কাস্টম রিজলভারগুলো বাস্তবে দেখতে পরবর্তী বিভাগে যান।
আপনার কাস্টম রিজলভার এবং অপারেশনগুলি স্থাপন করুন।
আপনার SQL Connect স্কিমাতে যেকোনো পরিবর্তনের মতোই, সেগুলোকে কার্যকর করার জন্য অবশ্যই ডিপ্লয় করতে হবে। তা করার আগে, প্রথমে ক্লাউড ফাংশন ব্যবহার করে আপনার তৈরি করা কাস্টম রিজলভার লজিকটি ডিপ্লয় করুন:
firebase deploy --only functionsএখন আপনি আপডেট করা স্কিমা এবং অপারেশনগুলো স্থাপন করতে পারেন:
firebase deploy --only dataconnectআপনার SQL Connect স্কিমাগুলিতে পরিবর্তন করার পরে, আপনাকে অবশ্যই নতুন ক্লায়েন্ট SDK-গুলিও তৈরি করতে হবে:
firebase dataconnect:sdk:generateউদাহরণ
এই উদাহরণগুলো দেখায় কীভাবে আরও কিছু উন্নত ব্যবহারিক ক্ষেত্র বাস্তবায়ন করতে হয় এবং কীভাবে সাধারণ ভুলগুলো এড়ানো যায়।
ক্লাউড SQL থেকে প্রাপ্ত ডেটা ব্যবহার করে একটি কাস্টম রিজলভারে অ্যাক্সেস অনুমোদন করা হচ্ছে
কাস্টম রিজলভার ব্যবহার করে আপনার ডেটা সোর্সগুলোকে SQL Connect এ একীভূত করার একটি সুবিধা হলো, আপনি এমন অপারেশন লিখতে পারেন যা ডেটা সোর্সগুলোকে একত্রিত করে।
এই উদাহরণে, ধরুন আপনি একটি সোশ্যাল মিডিয়া অ্যাপ তৈরি করছেন, এবং সেখানে একটি কাস্টম রিজলভার হিসেবে একটি মিউটেশন প্রয়োগ করা আছে, যা কোনো ব্যবহারকারীর বন্ধুকে একটি তাগাদা ইমেল পাঠায় যদি সেই বন্ধুটি কিছু সময় ধরে ব্যবহারকারীর সাথে যোগাযোগ না করে।
নাজ ফিচারটি বাস্তবায়ন করতে, নিম্নলিখিতের মতো একটি স্কিমা সহ একটি কাস্টম রিজলভার তৈরি করুন:
# A GraphQL server must define a root query type per the spec.
type Query {
unused: String
}
type Mutation {
sendEmail(id: String!, content: String): Boolean
}
এই সংজ্ঞাটি একটি ক্লাউড ফাংশন দ্বারা সমর্থিত, যেমনটি নিচে দেওয়া হলো:
import {
FirebaseContext,
onGraphRequest,
} from "firebase-functions/dataconnect/graphql";
const opts = {
schemaFilePath: "dataconnect/schema_resolver/schema.gql",
resolvers: {
mutation: {
sendEmail(
_parent: unknown,
args: Record<string, unknown>,
_contextValue: FirebaseContext,
_info: unknown
) {
const { id, content } = args;
// Look up the friend's email address and call the cloud service of your
// choice to send the friend an email with the given content.
return true;
},
},
},
};
export const resolver = onGraphRequest(opts);
যেহেতু ইমেল পাঠানো আপনার জন্য ব্যয়বহুল এবং এর অপব্যবহারের একটি সম্ভাব্য মাধ্যমও রয়েছে, তাই আপনার sendEmail কাস্টম রিজলভার ব্যবহার করার আগে নিশ্চিত হয়ে নিন যে উদ্দিষ্ট প্রাপক ইতিমধ্যেই ব্যবহারকারীর বন্ধু তালিকায় আছেন।
ধরা যাক, আপনার অ্যাপে বন্ধুর তালিকার ডেটা ক্লাউড এসকিউএল-এ সংরক্ষিত আছে:
type User @table {
id: String! @default(expr: "auth.uid")
acceptNudges: Boolean! @default(value: false)
}
type UserFriend @table(key: ["user", "friend"]) {
user: User!
friend: User!
}
আপনি এমন একটি মিউটেশন লিখতে পারেন যা কাস্টম রিজলভার ব্যবহার করে ইমেল পাঠানোর আগে, প্রেরক প্রাপকের বন্ধুদের তালিকায় আছেন কিনা তা নিশ্চিত করতে প্রথমে ক্লাউড এসকিউএল-এ কোয়েরি করে।
# Send a "nudge" to a friend as a reminder. This will only let the user send a
# nudge if $friendId is in the user's friends list.
mutation SendNudge($friendId: String!) @auth(level: USER_EMAIL_VERIFIED) {
# Step 1: Query and check
query @redact {
userFriend(
key: {userId_expr: "auth.uid", friendId: $friendId}
# This checks that $friendId is in the user's friends list.
) @check(expr: "this != null", message: "You must be friends to nudge") {
friend {
# This checks that the friend is accepting nudges.
acceptNudges @check(expr: "this == true", message: "Not accepting nudges")
}
}
}
# Step 2: Act
sendEmail(id: $friendId, content: "You've been nudged!")
}
প্রসঙ্গক্রমে, এই উদাহরণটি এটাও তুলে ধরে যে, কাস্টম রিজলভারের প্রেক্ষাপটে একটি ডেটা সোর্সে ডেটাবেস এবং অনুরূপ সিস্টেম ছাড়াও অন্যান্য রিসোর্স অন্তর্ভুক্ত থাকতে পারে। এই উদাহরণে, ডেটা সোর্সটি হলো একটি ক্লাউড ইমেল পাঠানোর পরিষেবা।
মিউটেশন ব্যবহার করে অনুক্রমিক সম্পাদন নিশ্চিত করা
ডেটা সোর্স একত্রিত করার সময়, আপনাকে প্রায়শই নিশ্চিত করতে হবে যে একটি ডেটা সোর্সে করা অনুরোধ সম্পন্ন হওয়ার পরেই কেবল অন্য একটি ডেটা সোর্সে অনুরোধ করা যায়। উদাহরণস্বরূপ, ধরুন আপনার একটি কোয়েরি আছে যা একটি এআই এপিআই ব্যবহার করে চাহিদা অনুযায়ী একটি ভিডিওকে ডাইনামিকভাবে ট্রান্সক্রাইব করে। এই ধরনের একটি এপিআই কল ব্যয়বহুল হতে পারে, তাই আপনি কিছু শর্তের ভিত্তিতে কলটিকে নিয়ন্ত্রণ করতে চাইবেন, যেমন ব্যবহারকারী ভিডিওটির মালিক, অথবা ব্যবহারকারী আপনার অ্যাপে কোনো ধরনের প্রিমিয়াম ক্রেডিট কিনেছেন।
এটি অর্জনের প্রথম প্রচেষ্টাটি দেখতে অনেকটা এইরকম হতে পারে:
# This won't work as expected.
query BrokenTranscribeVideo($videoId: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
# Step 1: Check quota using SQL.
# Verify the user owns the video and has "pro" status or credits.
checkQuota: query @redact {
video(id: $videoId)
{
user @check(expr: "this.id == auth.uid && this.hasCredits == true", message: "Unauthorized access") {
id
hasCredits
}
}
}
# Step 2: Trigger expensive compute
# Only triggers if Step 1 succeeds? No! This won't work because query field
# execution order is not guaranteed.
triggerTranscription: query {
# For example, might call Vertex AI or Transcoder API.
startVideoTranscription(videoId: $videoId)
}
}
এই পদ্ধতিটি কাজ করবে না, কারণ কোয়েরি ফিল্ডগুলোর এক্সিকিউশন অর্ডার নিশ্চিত নয় ; কনকারেন্সি সর্বোচ্চ করার জন্য GraphQL সার্ভার যেকোনো ক্রমে ফিল্ডগুলো রিজলভ করতে সক্ষম হবে বলে আশা করে। অন্যদিকে, একটি মিউটেশনের ফিল্ডগুলো সর্বদা ক্রমানুসারে রিজলভ করা হয় , কারণ GraphQL সার্ভার মনে করে যে রিজলভ করার সময় মিউটেশনের কিছু ফিল্ডের সাইড এফেক্ট থাকতে পারে।
যদিও উদাহরণ অপারেশনটির প্রথম ধাপে কোনো সাইড এফেক্ট নেই, তবুও আপনি অপারেশনটিকে একটি মিউটেশন হিসেবে সংজ্ঞায়িত করতে পারেন, যাতে মিউটেশন ফিল্ডগুলো ক্রমানুসারে সমাধান হওয়ার সুবিধাটি নেওয়া যায়:
# By using a mutation, we guarantee the SQL check happens FIRST.
mutation TranscribeVideo($videoId: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
# Step 1: Check quota using SQL.
# Verify the user owns the video and has "pro" status or credits.
checkQuota: query @redact {
video(id: $videoId)
{
user @check(expr: "this.id == auth.uid && this.hasCredits == true", message: "Unauthorized access") {
id
hasCredits
}
}
}
# Step 2: Trigger expensive compute
# This Cloud Function will ONLY trigger if Step 1 succeeds.
triggerTranscription: query {
# For example, might call Vertex AI or Transcoder API.
startVideoTranscription(videoId: $videoId)
}
}
সীমাবদ্ধতা
কাস্টম রিজলভার ফিচারটি একটি পরীক্ষামূলক পাবলিক প্রিভিউ হিসেবে প্রকাশ করা হয়েছে। নিম্নলিখিত বর্তমান সীমাবদ্ধতাগুলো লক্ষ্য করুন:
কাস্টম রিজলভার আর্গুমেন্টে কোনো CEL এক্সপ্রেশন নেই
আপনি একটি কাস্টম রিজলভারের আর্গুমেন্টগুলিতে ডায়নামিকভাবে CEL এক্সপ্রেশন ব্যবহার করতে পারবেন না। উদাহরণস্বরূপ, নিম্নলিখিতটি সম্ভব নয়:
mutation UpdateMyProfile($newName: String!) @auth(level: USER) {
updateMongoDocument(
collection: "profiles"
# This isn't supported:
id_expr: "auth.uid"
update: { name: $newName }
)
}
এর পরিবর্তে, স্ট্যান্ডার্ড ভেরিয়েবল (যেমন, $authUid ) পাস করুন এবং নিরাপদে মূল্যায়ন করা @auth(expr: ...) নির্দেশিকা ব্যবহার করে অপারেশন লেভেলে সেগুলোকে ভ্যালিডেট করুন।
mutation UpdateMyProfile(
$newName: String!, $authUid: String!
) @auth(expr: "vars.authUid == auth.uid") {
updateMongoDocument(
collection: "profiles"
id: $authUid
update: { name: $newName }
)
}
এর আরেকটি সমাধান হলো, আপনার সমস্ত লজিক একটি কাস্টম রিজলভারে স্থানান্তর করা এবং ক্লাউড ফাংশন থেকে সমস্ত ডেটা অপারেশন সম্পন্ন করা।
উদাহরণস্বরূপ, এই উদাহরণটি বিবেচনা করুন, যা বর্তমানে কাজ করবে না:
mutation BrokenForwardToEmail($chatMessageId: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
query {
chatMessage(id: $chatMessageId) {
content
}
}
sendEmail(
title: "Forwarded Chat Message"
to_expr: "auth.token.email" # Not supported.
content_expr: "response.query.chatMessage.content" # Not supported.
)
}
এর পরিবর্তে, ক্লাউড এসকিউএল কোয়েরি এবং ইমেল সার্ভিসের কল উভয়কেই একটি ফাংশন দ্বারা সমর্থিত একটি মিউটেশন ফিল্ডে সরিয়ে নিন:
mutation ForwardToEmail($chatMessageId: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
forwardChatToEmail(
chatMessageId: $chatMessageId
)
}
আপনার ডাটাবেসের জন্য একটি অ্যাডমিন SDK তৈরি করুন এবং ক্লাউড SQL কোয়েরিটি সম্পাদন করতে ফাংশনের মধ্যে এটি ব্যবহার করুন:
const opts = {
schemaFilePath: "dataconnect/schema_resolver/schema.gql",
resolvers: {
query: {
async forwardToEmail(
_parent: unknown,
args: Record<string, unknown>,
_contextValue: FirebaseContext,
_info: unknown
) {
const chatMessageId = args.chatMessageId as string;
let decodedToken;
try {
decodedToken = await getAuth().verifyIdToken(_contextValue.auth.token ?? "");
} catch (error) {
return false;
}
const email = decodedToken.email;
if (!email) {
return false;
}
const response = await getChatMessage({chatMessageId});
const messageContent = response.data.chatMessage?.content;
// Here you call the cloud service of your choice to send the email with
// the message content.
return true;
}
},
},
};
export const resolver = onGraphRequest(opts);
কাস্টম রিজলভার প্যারামিটারে কোন ইনপুট অবজেক্ট টাইপ নেই
কাস্টম রিজলভার জটিল GraphQL ইনপুট টাইপ গ্রহণ করে না। প্যারামিটার অবশ্যই সাধারণ স্কেলার টাইপ ( String , Int , Date , Any , ইত্যাদি) এবং Enum হতে হবে।
input PublicProfileInput {
name: String!
photoUrl: String!
bioLine: String!
}
type Mutation {
# Not supported:
updatePublicProfile(userId: String!, profile: PublicProfileInput): PublicProfile
# OK:
updatePublicProfile(userId: String!, name: String, photoUrl: String, bioLine: String): PublicProfile
}
কাস্টম রিজলভার SQL অপারেশনের আগে আসতে পারে না।
মিউটেশনের ক্ষেত্রে, সাধারণ SQL অপারেশনের আগে কাস্টম রিজলভার রাখলে একটি ত্রুটি দেখা দেয়। সমস্ত SQL-ভিত্তিক অপারেশন অবশ্যই যেকোনো কাস্টম রিজলভার আহ্বানের আগে থাকতে হবে।
কোন লেনদেন নেই (@transaction)
কাস্টম রিজলভারগুলোকে স্ট্যান্ডার্ড SQL অপারেশনের সাথে @transaction ব্লকের মধ্যে রাখা যায় না। যদি একটি SQL ইনসার্ট সফল হওয়ার পর রিজলভারটির সহায়ক ক্লাউড ফাংশনটি ব্যর্থ হয়, তবে ডাটাবেস স্বয়ংক্রিয়ভাবে রোল ব্যাক করবে না।
SQL এবং অন্য কোনো ডেটা সোর্সের মধ্যে লেনদেনগত নিরাপত্তা নিশ্চিত করতে, SQL অপারেশন লজিকটি ক্লাউড ফাংশনের ভেতরে নিয়ে যান এবং অ্যাডমিন SDK বা সরাসরি SQL কানেকশন ব্যবহার করে ভ্যালিডেশন ও রোলব্যাক পরিচালনা করুন।