নেটিভ SQL ব্যবহার করে Firebase Data Connect অপারেশন বাস্তবায়ন করুন

Firebase Data Connect আপনার ক্লাউড এসকিউএল ডাটাবেসের সাথে ইন্টারঅ্যাক্ট করার একাধিক উপায় অফার করে:

  • নেটিভ গ্রাফকিউএল : আপনার schema.gql এ টাইপ নির্ধারণ করুন এবং Data Connect আপনার গ্রাফকিউএল অপারেশনগুলিকে SQL-তে অনুবাদ করে। এটি একটি স্ট্যান্ডার্ড পদ্ধতি, যা শক্তিশালী টাইপিং এবং স্কিমা-প্রয়োগকৃত কাঠামো প্রদান করে। এই পৃষ্ঠার বাইরের বেশিরভাগ Data Connect ডকুমেন্টেশন এই বিকল্পটি নিয়ে আলোচনা করে। যখন সম্ভব হয়, পূর্ণ ধরণের নিরাপত্তা এবং টুলিং সহায়তার সুবিধা নিতে আপনার এই পদ্ধতিটি ব্যবহার করা উচিত।
  • @view নির্দেশিকা : schema.gql এ একটি GraphQL টাইপ সংজ্ঞায়িত করুন যা একটি কাস্টম SELECT SQL স্টেটমেন্ট দ্বারা সমর্থিত। এটি জটিল 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 কোয়েরি কার্যকর করে।

যুক্তি :

  • sql : SQL স্টেটমেন্ট স্ট্রিং আক্ষরিক। SQL ইনজেকশন প্রতিরোধ করতে, প্যারামিটার মানের জন্য অবস্থানগত স্থানধারক ( $1 , $2 , ইত্যাদি) ব্যবহার করুন।
  • params : স্থানধারকদের সাথে সংযুক্ত করার জন্য মানগুলির একটি ক্রমযুক্ত তালিকা। এর মধ্যে লিটারেলস, গ্রাফকিউএল ভেরিয়েবল এবং বিশেষ সার্ভার-ইনজেক্টেড প্রসঙ্গ মানচিত্র যেমন {_expr: "auth.uid"} (প্রমাণিত ব্যবহারকারীর আইডি) অন্তর্ভুক্ত থাকতে পারে।

রিটার্ন করে : একটি JSON অ্যারে ( [Any] )।

_selectFirst

শূন্য অথবা এক সারি ফেরত দেবে বলে প্রত্যাশিত একটি SQL কোয়েরি কার্যকর করে।

যুক্তি :

  • sql : SQL স্টেটমেন্ট স্ট্রিং আক্ষরিক। SQL ইনজেকশন প্রতিরোধ করতে, প্যারামিটার মানের জন্য অবস্থানগত স্থানধারক ( $1 , $2 , ইত্যাদি) ব্যবহার করুন।
  • params : স্থানধারকদের সাথে সংযুক্ত করার জন্য মানগুলির একটি ক্রমযুক্ত তালিকা। এর মধ্যে লিটারেলস, গ্রাফকিউএল ভেরিয়েবল এবং বিশেষ সার্ভার-ইনজেক্টেড প্রসঙ্গ মানচিত্র যেমন {_expr: "auth.uid"} (প্রমাণিত ব্যবহারকারীর আইডি) অন্তর্ভুক্ত থাকতে পারে।

রিটার্ন করে : একটি JSON অবজেক্ট ( Any ) অথবা null

mutation ক্ষেত্র

মাঠ বিবরণ
_execute

একটি DML স্টেটমেন্ট ( INSERT, UPDATE, DELETE ) কার্যকর করে।

যুক্তি :

  • sql : SQL স্টেটমেন্ট স্ট্রিং আক্ষরিক। SQL ইনজেকশন প্রতিরোধ করতে, প্যারামিটার মানের জন্য অবস্থানগত স্থানধারক ( $1 , $2 , ইত্যাদি) ব্যবহার করুন।

    আপনি এখানে ডেটা-মডিফাইং কমন টেবিল এক্সপ্রেশন (উদাহরণস্বরূপ, WITH new_row AS (INSERT...) ) ব্যবহার করতে পারেন কারণ এই ক্ষেত্রটি শুধুমাত্র সারি গণনা প্রদান করে। শুধুমাত্র _execute CTE সমর্থন করে।

  • params : স্থানধারকদের সাথে সংযুক্ত করার জন্য মানগুলির একটি ক্রমযুক্ত তালিকা। এর মধ্যে লিটারেলস, গ্রাফকিউএল ভেরিয়েবল এবং বিশেষ সার্ভার-ইনজেক্টেড প্রসঙ্গ মানচিত্র যেমন {_expr: "auth.uid"} (প্রমাণিত ব্যবহারকারীর আইডি) অন্তর্ভুক্ত থাকতে পারে।

রিটার্ন করে : একটি Int (প্রভাবিত সারির সংখ্যা)।

ফলাফলে RETURNING ধারাগুলি উপেক্ষা করা হয়েছে।

_executeReturning

একটি RETURNING ক্লজ সহ একটি DML স্টেটমেন্ট কার্যকর করে, শূন্য বা তার বেশি সারি প্রদান করে।

যুক্তি :

  • sql : SQL স্টেটমেন্ট স্ট্রিং আক্ষরিক। SQL ইনজেকশন প্রতিরোধ করতে, প্যারামিটার মানের জন্য অবস্থানগত স্থানধারক ( $1 , $2 , ইত্যাদি) ব্যবহার করুন। ডেটা-সংশোধনকারী সাধারণ টেবিল এক্সপ্রেশন সমর্থিত নয়।
  • params : স্থানধারকদের সাথে সংযুক্ত করার জন্য মানগুলির একটি ক্রমযুক্ত তালিকা। এর মধ্যে লিটারেলস, গ্রাফকিউএল ভেরিয়েবল এবং বিশেষ সার্ভার-ইনজেক্টেড প্রসঙ্গ মানচিত্র যেমন {_expr: "auth.uid"} (প্রমাণিত ব্যবহারকারীর আইডি) অন্তর্ভুক্ত থাকতে পারে।

রিটার্ন করে : একটি JSON অ্যারে ( [Any] )।

_executeReturningFirst

একটি RETURNING ক্লজ সহ একটি DML স্টেটমেন্ট কার্যকর করে, যা শূন্য বা একটি সারি ফেরত দেবে বলে আশা করা হচ্ছে।

যুক্তি :

  • sql : SQL স্টেটমেন্ট স্ট্রিং আক্ষরিক। SQL ইনজেকশন প্রতিরোধ করতে, প্যারামিটার মানের জন্য অবস্থানগত স্থানধারক ( $1 , $2 , ইত্যাদি) ব্যবহার করুন। ডেটা-সংশোধনকারী সাধারণ টেবিল এক্সপ্রেশন সমর্থিত নয়।
  • params : স্থানধারকদের সাথে সংযুক্ত করার জন্য মানগুলির একটি ক্রমযুক্ত তালিকা। এর মধ্যে লিটারেলস, গ্রাফকিউএল ভেরিয়েবল এবং বিশেষ সার্ভার-ইনজেক্টেড প্রসঙ্গ মানচিত্র যেমন {_expr: "auth.uid"} (প্রমাণিত ব্যবহারকারীর আইডি) অন্তর্ভুক্ত থাকতে পারে।

রিটার্ন করে : একটি JSON অবজেক্ট ( Any ) অথবা null

নোট:

  • ডেটা কানেক্ট পরিষেবা অ্যাকাউন্টে প্রদত্ত অনুমতি ব্যবহার করে ক্রিয়াকলাপগুলি সম্পাদন করা হয়।

  • যদি আপনি @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;
$$;