Firebase Data Connect আপনার ক্লাউড এসকিউএল ডাটাবেসের সাথে ইন্টারঅ্যাক্ট করার একাধিক উপায় অফার করে:
- নেটিভ গ্রাফকিউএল : আপনার
schema.gqlএ টাইপ নির্ধারণ করুন এবং Data Connect আপনার গ্রাফকিউএল অপারেশনগুলিকে SQL-তে অনুবাদ করে। এটি একটি স্ট্যান্ডার্ড পদ্ধতি, যা শক্তিশালী টাইপিং এবং স্কিমা-প্রয়োগকৃত কাঠামো প্রদান করে। এই পৃষ্ঠার বাইরের বেশিরভাগ Data Connect ডকুমেন্টেশন এই বিকল্পটি নিয়ে আলোচনা করে। যখন সম্ভব হয়, পূর্ণ ধরণের নিরাপত্তা এবং টুলিং সহায়তার সুবিধা নিতে আপনার এই পদ্ধতিটি ব্যবহার করা উচিত। -
@viewনির্দেশিকা :schema.gqlএ একটি GraphQL টাইপ সংজ্ঞায়িত করুন যা একটি কাস্টমSELECTSQL স্টেটমেন্ট দ্বারা সমর্থিত। এটি জটিল SQL লজিকের উপর ভিত্তি করে কেবল-পঠনযোগ্য, দৃঢ়ভাবে টাইপ করা ভিউ তৈরি করার জন্য কার্যকর। এই টাইপগুলি নিয়মিত টাইপের মতোই জিজ্ঞাসাযোগ্য।@viewদেখুন। - নেটিভ এসকিউএল : বিশেষ রুট ফিল্ড ব্যবহার করে .
gqlফাইলে সরাসরি নামযুক্ত অপারেশনে এসকিউএল স্টেটমেন্ট এম্বেড করুন। এটি সর্বাধিক নমনীয়তা এবং সরাসরি নিয়ন্ত্রণ প্রদান করে, বিশেষ করে স্ট্যান্ডার্ড গ্রাফকিউএলে সহজে প্রকাশ না করা অপারেশনগুলির জন্য, ডাটাবেস-নির্দিষ্ট বৈশিষ্ট্যগুলি ব্যবহার করে, অথবা পোস্টগ্রেএসকিউএল এক্সটেনশন ব্যবহার করে।
এই নির্দেশিকাটি নেটিভ এসকিউএল বিকল্পের উপর আলোকপাত করে।
নেটিভ SQL-এর জন্য সাধারণ ব্যবহারের উদাহরণ
যদিও নেটিভ গ্রাফকিউএল সম্পূর্ণ ধরণের সুরক্ষা প্রদান করে এবং @view নির্দেশিকা কেবল পঠনযোগ্য SQL রিপোর্টের জন্য দৃঢ়ভাবে টাইপ করা ফলাফল প্রদান করে, নেটিভ SQL নিম্নলিখিতগুলির জন্য প্রয়োজনীয় নমনীয়তা প্রদান করে:
- PostgreSQL এক্সটেনশন : আপনার GraphQL স্কিমায় জটিল ধরণের ম্যাপিং না করেই সরাসরি যেকোনো ইনস্টল করা PostgreSQL এক্সটেনশন (যেমন ভূ-স্থানিক ডেটার জন্য
PostGIS) অনুসন্ধান করুন এবং ব্যবহার করুন। - জটিল প্রশ্ন : জয়েন, সাবকুয়েরি, অ্যাগ্রিগেশন, উইন্ডো ফাংশন এবং সঞ্চিত পদ্ধতি সহ জটিল SQL কার্যকর করুন।
- ডেটা ম্যানিপুলেশন (DML) : সরাসরি
INSERT, UPDATE, DELETEঅপারেশন সম্পাদন করুন। (তবে, ডেটা ডেফিনিশন ল্যাঙ্গুয়েজ (DDL) কমান্ডের জন্য নেটিভ SQL ব্যবহার করবেন না। আপনার ব্যাকএন্ড এবং জেনারেটেড SDK গুলিকে সিঙ্কে রাখতে আপনাকে GraphQL ব্যবহার করে স্কিমা-স্তরের পরিবর্তনগুলি চালিয়ে যেতে হবে।) - ডাটাবেস-নির্দিষ্ট বৈশিষ্ট্য : PostgreSQL-এর জন্য অনন্য ফাংশন, অপারেটর বা ডেটা টাইপ ব্যবহার করুন।
- পারফরম্যান্স অপ্টিমাইজেশন : গুরুত্বপূর্ণ পাথের জন্য SQL স্টেটমেন্টগুলি হ্যান্ড-টিউন করুন।
নেটিভ SQL রুট ফিল্ড
SQL দিয়ে অপারেশন লেখার জন্য, query বা mutation ধরণগুলির নিম্নলিখিত রুট ফিল্ডগুলির মধ্যে একটি ব্যবহার করুন:
query ক্ষেত্র
| মাঠ | বিবরণ |
|---|---|
_select | শূন্য বা তার বেশি সারি প্রদানকারী একটি SQL কোয়েরি কার্যকর করে। যুক্তি :
রিটার্ন করে : একটি JSON অ্যারে ( |
_selectFirst | শূন্য অথবা এক সারি ফেরত দেবে বলে প্রত্যাশিত একটি SQL কোয়েরি কার্যকর করে। যুক্তি :
রিটার্ন করে : একটি JSON অবজেক্ট ( |
mutation ক্ষেত্র
| মাঠ | বিবরণ |
|---|---|
_execute | একটি DML স্টেটমেন্ট ( যুক্তি :
রিটার্ন করে : একটি ফলাফলে |
_executeReturning | একটি যুক্তি :
রিটার্ন করে : একটি JSON অ্যারে ( |
_executeReturningFirst | একটি যুক্তি :
রিটার্ন করে : একটি JSON অবজেক্ট ( |
নোট:
ডেটা কানেক্ট পরিষেবা অ্যাকাউন্টে প্রদত্ত অনুমতি ব্যবহার করে ক্রিয়াকলাপগুলি সম্পাদন করা হয়।
যদি আপনি
@tableনির্দেশিকা (@table(name: "ExampleTable")) ব্যবহার করে স্পষ্টভাবে টেবিলের নাম সেট করেন, তাহলে আপনাকে অবশ্যই আপনার SQL স্টেটমেন্টে (SELECT field FROM "ExampleTable" ...) উদ্ধৃতি চিহ্নে টেবিলের নামটি আবদ্ধ করতে হবে।উদ্ধৃতি চিহ্ন ছাড়া, Data Connect টেবিলের নামটিকে snake case (
example_table) এ রূপান্তর করবে।
বাক্য গঠনের নিয়ম এবং সীমাবদ্ধতা
নেটিভ SQL নিরাপত্তা নিশ্চিত করতে এবং SQL ইনজেকশন প্রতিরোধ করতে কঠোর পার্সিং নিয়ম প্রয়োগ করে। নিম্নলিখিত সীমাবদ্ধতাগুলি সম্পর্কে সচেতন থাকুন:
- মন্তব্য : ব্লক মন্তব্য (
/* ... */) ব্যবহার করুন। লাইন মন্তব্য (--) নিষিদ্ধ কারণ তারা কোয়েরি কনক্যাটেনেশনের সময় পরবর্তী ধারাগুলি (যেমন নিরাপত্তা ফিল্টার) কেটে ফেলতে পারে। - প্যারামিটার :
paramsঅ্যারের ক্রমের সাথে মেলে এমন পজিশনাল প্যারামিটার ($1,$2) ব্যবহার করুন। নামযুক্ত প্যারামিটার ($id,:name) সমর্থিত নয়। - স্ট্রিং : এক্সটেন্ডেড স্ট্রিং লিটারেলস (
E'...') এবং ডলার-উদ্ধৃত স্ট্রিং ($$...$$) সমর্থিত। PostgreSQL ইউনিকোড এস্কেপ (U&'...') সমর্থিত নয়।
মন্তব্যে পরামিতি
পার্সার একটি ব্লক মন্তব্যের ভিতরের সবকিছু উপেক্ষা করে। যদি আপনি একটি প্যারামিটার সম্বলিত একটি লাইন মন্তব্য করেন (উদাহরণস্বরূপ, /* WHERE id = $1 */ ), তাহলে আপনাকে params তালিকা থেকে সেই প্যারামিটারটিও সরিয়ে ফেলতে হবে, অন্যথায় ত্রুটি unused parameter: $1 ।
উদাহরণ
উদাহরণ ১: ফিল্ড অ্যালিয়াসিং সহ বেসিক SELECT
ক্লায়েন্ট রেসপন্সকে আরও পরিষ্কার করার জন্য আপনি রুট ফিল্ড (যেমন, movies: _select ) নামটি ( data._select এর পরিবর্তে data.movies ) নামকরণ করতে পারেন।
queries.gql :
query GetMoviesByGenre($genre: String!, $limit:Int!) @auth(level: PUBLIC) {
movies: _select(
sql: """
SELECT id, title, release_year, rating
FROM movie
WHERE genre = $1
ORDER BY release_year DESC
LIMIT $2
""",
params: [$genre, $limit]
)
}
ক্লায়েন্ট SDK ব্যবহার করে কোয়েরি চালানোর পরে, ফলাফলটি data.movies এ আসবে।
উদাহরণ ২: মৌলিক আপডেট
mutations.gql :
mutation UpdateMovieRating($movieId: UUID!, $newRating: Float!) @auth(level: NO_ACCESS) {
_execute(
sql: """
UPDATE movie
SET rating = $2
WHERE id = $1
""",
params: [$movieId, $newRating]
)
}
ক্লায়েন্ট SDK ব্যবহার করে মিউটেশন চালানোর পরে, প্রভাবিত সারির সংখ্যা data._execute এ থাকবে।
উদাহরণ ৩: মৌলিক সমষ্টি
queries.gql :
query GetTotalReviewCount @auth(level: PUBLIC) {
stats: _selectFirst(
sql: "SELECT COUNT(*) as total_reviews FROM \"Reviews\""
)
}
ক্লায়েন্ট SDK ব্যবহার করে কোয়েরি চালানোর পরে, ফলাফলটি data.stats.total_reviews এ আসবে।
উদাহরণ ৪: RANK এর সাথে উন্নত সমষ্টি
queries.gql :
query GetMoviesRankedByRating @auth(level: PUBLIC) {
_select(
sql: """
SELECT
id,
title,
rating,
RANK() OVER (ORDER BY rating DESC) as rank
FROM movie
WHERE rating IS NOT NULL
LIMIT 20
""",
params: []
)
}
ক্লায়েন্ট SDK ব্যবহার করে কোয়েরি চালানোর পরে, ফলাফলটি data._select এ আসবে।
উদাহরণ ৫: রিটার্নিং এবং প্রমাণীকরণ প্রসঙ্গ সহ আপডেট
mutations.gql :
mutation UpdateMyReviewText($movieId: UUID!, $newText: String!) @auth(level: USER) {
updatedReview: _executeReturningFirst(
sql: """
UPDATE "Reviews"
SET review_text = $2
WHERE movie_id = $1 AND user_id = $3
RETURNING movie_id, user_id, rating, review_text
""",
params: [$movieId,$newText,{_expr: "auth.uid" }]
)
}
ক্লায়েন্ট SDK ব্যবহার করে মিউটেশন চালানোর পরে, আপডেট করা পোস্ট ডেটা data.updatedReview এ থাকবে।
উদাহরণ ৬: আপসার্ট সহ উন্নত CTE (পারমাণবিক গেট-অর-ক্রিয়েট)
এই প্যাটার্নটি একটি চাইল্ড রেকর্ড (যেমন একটি পর্যালোচনা) সন্নিবেশ করার আগে নির্ভরশীল রেকর্ড (যেমন ব্যবহারকারী বা চলচ্চিত্র) বিদ্যমান থাকার বিষয়টি নিশ্চিত করার জন্য কার্যকর, যা সমস্ত একটি একক ডাটাবেস লেনদেনে থাকে।
mutations.gql :
mutation CreateMovieCTE($movieId: UUID!, $userId: UUID!, $reviewId: UUID!) {
_execute(
sql: """
WITH
new_user AS (
INSERT INTO "user" (id, username)
VALUES ($2, 'Auto-Generated User')
ON CONFLICT (id) DO NOTHING
RETURNING id
),
movie AS (
INSERT INTO movie (id, title, image_url, release_year, genre)
VALUES ($1, 'Auto-Generated Movie', 'https://placeholder.com', 2025, 'Sci-Fi')
ON CONFLICT (id) DO NOTHING
RETURNING id
)
INSERT INTO "Reviews" (id, movie_id, user_id, rating, review_text, review_date)
VALUES (
$3,
$1,
$2,
5,
'Good!',
NOW()
)
""",
params: [$movieId, $userId, $reviewId]
)
}
উদাহরণ ৭: পোস্টগ্রেস এক্সটেনশন ব্যবহার করা
নেটিভ এসকিউএল আপনাকে আপনার গ্রাফকিউএল স্কিমায় জটিল জ্যামিতির ধরণ ম্যাপ না করে বা আপনার অন্তর্নিহিত টেবিল পরিবর্তন না করেই পোস্টগ্রেস এক্সটেনশন, যেমন পোস্টজিআইএস ব্যবহার করতে দেয়।
এই উদাহরণে, ধরুন আপনার রেস্তোরাঁ অ্যাপে একটি টেবিল আছে যা একটি মেটাডেটা JSON কলামে অবস্থানের ডেটা সংরক্ষণ করে (উদাহরণস্বরূপ, {"latitude": 37.3688, "longitude": -122.0363} )। যদি আপনি PostGIS এক্সটেনশন সক্ষম করে থাকেন, তাহলে আপনি স্ট্যান্ডার্ড Postgres JSON অপারেটর ( ->> ) ব্যবহার করে এই মানগুলি তাৎক্ষণিকভাবে বের করে PostGIS ST_MakePoint ফাংশনে পাস করতে পারেন।
query GetNearbyActiveRestaurants($userLong: Float!, $userLat: Float!, $maxDistanceMeters: Float!) @auth(level: USER) {
nearby: _select(
sql: """
SELECT
id,
name,
tags,
ST_Distance(
ST_MakePoint((metadata->>'longitude')::float, (metadata->>'latitude')::float)::geography,
ST_MakePoint($1, $2)::geography
) as distance_meters
FROM restaurant
WHERE active = true
AND metadata ? 'longitude' AND metadata ? 'latitude'
AND ST_DWithin(
ST_MakePoint((metadata->>'longitude')::float, (metadata->>'latitude')::float)::geography,
ST_MakePoint($1, $2)::geography,
$3
)
ORDER BY distance_meters ASC
LIMIT 10
""",
params: [$userLong, $userLat, $maxDistanceMeters]
)
}
ক্লায়েন্ট SDK ব্যবহার করে কোয়েরি চালানোর পরে, ফলাফলটি data.nearby এ আসবে।
নিরাপত্তার সর্বোত্তম অনুশীলন: গতিশীল SQL এবং সঞ্চিত পদ্ধতি
Data Connect গ্রাফকিউএল-টু-ডাটাবেস সীমানায় সমস্ত ইনপুটকে নিরাপদে প্যারামিটারাইজ করে, আপনার স্ট্যান্ডার্ড এসকিউএল কোয়েরিগুলিকে প্রথম-ক্রমের এসকিউএল ইনজেকশন থেকে সম্পূর্ণরূপে সুরক্ষিত করে। তবে, যদি আপনি কাস্টম পোস্টগ্রেস সঞ্চিত পদ্ধতি বা গতিশীল এসকিউএল কার্যকর করে এমন ফাংশনগুলিকে কল করার জন্য এসকিউএল ব্যবহার করেন, তাহলে আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনার অভ্যন্তরীণ পিএল/পিজিএসকিউএল কোড এই প্যারামিটারগুলিকে নিরাপদে পরিচালনা করে।
যদি আপনার সঞ্চিত পদ্ধতিটি ব্যবহারকারীর ইনপুটগুলিকে সরাসরি একটি EXECUTE স্ট্রিং-এ সংযুক্ত করে, তাহলে এটি প্যারামিটারাইজেশনকে বাইপাস করে এবং একটি দ্বিতীয়-ক্রমের SQL ইনজেকশন দুর্বলতা তৈরি করে:
-- INSECURE: Do not concatenate parameters into dynamic strings!
CREATE OR REPLACE PROCEDURE unsafe_update(user_input TEXT)
LANGUAGE plpgsql AS $$
BEGIN
-- A malicious user_input (e.g., "val'; DROP TABLE users; --") will execute as code.
EXECUTE 'UPDATE target_table SET status = ''' || user_input || '''';
END;
$$;
এটি এড়াতে, এই সেরা অনুশীলনগুলি অনুসরণ করুন:
-
USINGধারাটি ব্যবহার করুন: আপনার সঞ্চিত পদ্ধতিতে গতিশীল SQL লেখার সময়, ডেটা প্যারামিটারগুলি নিরাপদে আবদ্ধ করতে সর্বদাUSINGধারাটি ব্যবহার করুন। - শনাক্তকারীর জন্য
format()ব্যবহার করুন: নিরাপদ ডাটাবেস শনাক্তকারী ইনজেকশনের জন্য (যেমন টেবিলের নাম)%Iফ্ল্যাগ সহformat()ব্যবহার করুন। - কঠোরভাবে শনাক্তকারীকে অনুমতি দিন: ক্লায়েন্ট অ্যাপ্লিকেশনগুলিকে ইচ্ছামত ডাটাবেস শনাক্তকারী বেছে নিতে দেবেন না। যদি আপনার পদ্ধতিতে গতিশীল শনাক্তকারীর প্রয়োজন হয়, তাহলে কার্যকর করার আগে আপনার PL/pgSQL লজিকের ভিতরে একটি হার্ডকোডেড অ্যালোলিস্টের বিরুদ্ধে ইনপুট যাচাই করুন।
-- SECURE: Use format() for identifiers and USING for data values
CREATE OR REPLACE PROCEDURE secure_update(target_table TEXT, new_value TEXT, row_id INT)
LANGUAGE plpgsql AS $$
BEGIN
-- Validate the dynamic table name against an allowlist
IF target_table NOT IN ('orders', 'users', 'inventory') THEN
RAISE EXCEPTION 'Invalid table name';
END IF;
-- Execute securely
EXECUTE format('UPDATE %I SET status = $1 WHERE id = $2', target_table)
USING new_value, row_id;
END;
$$;