المخططات وطلبات البحث وعمليات التغيير في Data Connect

Firebase Data Connect يتيح لك إنشاء أدوات ربط لمثيل PostgreSQL المُدار باستخدام Google Cloud SQL. هذه الوصلات هي مجموعات من مخطّط وطلبات بحث وعمليات تحويل لاستخدام بياناتك.

قدّم دليل البدء مخطّط قاعدة بيانات تطبيق مراجعات الأفلام في PostgreSQL، ويتناول هذا الدليل بالتفصيل كيفية تصميم مخطّطات Data Connect لقاعدة بيانات PostgreSQL.

يجمع هذا الدليل بين Data Connect طلبات البحث والطفرات مع نماذج المخطط. لماذا نناقش طلبات البحثعمليات التحويل) في دليل عن Data Connect المخططات؟ مثل المنصات الأخرى المستندة إلى GraphQL، Firebase Data Connect هي منصة تطوير تركز على طلبات البحث، لذا بصفتك أحد المطوّرين، عليك التفكير في البيانات التي يحتاجها العميل عند وضع نماذج للبيانات، ما سيؤثّر بشكل كبير في مخطّط البيانات الذي تُطوّره لمشروعك.

يبدأ هذا الدليل بمخطّط جديد لمراجعات الأفلام، ثم يتناول الاستعلامات وعمليات التحويل المشتقة من هذا المخطّط، ويقدّم أخيرًا قائمة SQL مكافئة للمخطّط الأساسي Data Connect.

مخطّط تطبيق لمراجعة الأفلام

لنفترض أنّك تريد إنشاء خدمة تتيح للمستخدمين إرسال مراجعات الأفلام والاطّلاع عليها.

تحتاج إلى مخطّط أوّلي لتطبيق كهذا. ويمكنك توسيع هذا المخطّط لاحقًا لإنشاء طلبات بحث علاقاتية معقّدة.

جدول الأفلام

يحتوي مخطّط الأفلام على توجيهات أساسية، مثل:

  • @table، التي تسمح لنا بضبط أسماء العمليات باستخدام وسيطات singular وplural
  • @col لضبط أسماء الأعمدة بشكل صريح
  • @default للسماح بضبط الإعدادات التلقائية.
# Movies
type Movie
  @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int @col(name: "release_year")
  genre: String
  rating: Int @col(name: "rating")
  description: String @col(name: "description")
}

قيم الخادم والمتغيّرات السلعية الرئيسية

قبل الاطّلاع على تطبيق مراجعة الأفلام، لنلقِ نظرة على Data Connect قيم الخادم والمقاييس الرئيسية.

باستخدام قيم الخادم، يمكنك السماح للخادم بتعبئة الحقول في الجداول بشكل ديناميكي باستخدام قيم مخزّنة أو قابلة للحساب بسهولة وفقًا لتعبيرات معيّنة من جهة الخادم. على سبيل المثال، يمكنك تحديد حقل تم تطبيق علامة زمنية عليه عند الوصول إلى الحقل باستخدام التعبير updatedAt: Timestamp! @default(expr: "request.time").

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

جدول البيانات الوصفية للفيلم

لنتتبّع الآن مخرجي الأفلام، وننشئ أيضًا علاقة شخصية مع Movie.

أضِف التوجيه @ref لتحديد العلاقات.

# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata
  @table(
    name: "MovieMetadata"
  ) {
  # @ref creates a field in the current table (MovieMetadata) that holds the
  # primary key of the referenced type
  # In this case, @ref(fields: "id") is implied
  movie: Movie! @ref
  # movieId: UUID <- this is created by the above @ref
  director: String @col(name: "director")
}

Actor وMovieActor

بعد ذلك، تريد أن يشارك ممثلون في أفلامك، وبما أنّ لديك علاقة بين الأفلام والممثلين تتعلّق بالعديد من القيم لكلّ منهما، عليك إنشاء جدول ربط.

# Actors
# Suppose an actor can participate in multiple movies and movies can have multiple actors
# Movie - Actors (or vice versa) is a many to many relationship
type Actor @table(name: "Actors", singular: "actor", plural: "actors") {
  id: UUID! @col(name: "actor_id") @default(expr: "uuidV4()")
  name: String! @col(name: "name", dataType: "varchar(30)")
}
# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary key(s) of this table
# In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  # @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
  # In this case, @ref(fields: "id") is implied
  movie: Movie! @ref
  # movieId: UUID! <- this is created by the above @ref, see: implicit.gql
  actor: Actor! @ref
  # actorId: UUID! <- this is created by the above @ref, see: implicit.gql
  role: String! @col(name: "role") # "main" or "supporting"
  # optional other fields
}

المستخدِم

أخيرًا، المستخدمون الذين يستخدمون تطبيقك.

# Users
# Suppose a user can leave reviews for movies
# user:reviews is a one to many relationship, movie:reviews is a one to many relationship, movie:user is a many to many relationship
type User
  @table(name: "Users", singular: "user", plural: "users", key: ["id"]) {
  id: UUID! @col(name: "user_id") @default(expr: "uuidV4()")
  auth: String @col(name: "user_auth") @default(expr: "auth.uid")
  username: String! @col(name: "username", dataType: "varchar(30)")
  # The following are generated from the @ref in the Review table
  # reviews_on_user
  # movies_via_Review
}

أنواع البيانات المتوافقة

يتيح Data Connect أنواع البيانات السلاسل التالية، مع عمليات الربط بأنواع PostgreSQL باستخدام @col(dataType:).

نوع Data Connect نوع مضمّن في GraphQL أو
Data Connect نوع مخصّص
نوع PostgreSQL التلقائي أنواع PostgreSQL المتوافقة
(الاسم المعرِّف بين قوسين)
سلسلة GraphQL text نص
bit(n)، varbit(n)
char(n)، varchar(n)
Int GraphQL int Int2 (smallint, smallserial)،
int4 (integer, int, serial)
عائم GraphQL float8 float4 (عدد حقيقي)
float8 (دقة مزدوجة)
numeric (عدد عشري)
منطقي GraphQL قيمة منطقية قيمة منطقية
معرِّف فريد عالمي (UUID) مخصَّص uuid uuid
Int64 مخصَّص bigint int8 (bigint, bigserial)
numeric (decimal)
التاريخ مخصَّص date التاريخ
الطابع الزمني مخصَّص timestamptz

timestamptz

ملاحظة: لا يتم تخزين معلومات المنطقة الزمنية المحلية.
تحوِّل PostgreSQL هذه الطوابع الزمنية وتخزّنها بالتوقيت العالمي المنسَّق.

المتّجه مخصَّص vector

المتّجه

اطّلِع على مقالة تنفيذ بحث التشابه بين المتجهات باستخدام Vertex AI.

  • يتم ربط List في GraphQL بصفيف أحادي الأبعاد.
    • على سبيل المثال، يتم ربط [Int] بـ int5[]، و[Any] بـ jsonb[].
    • لا تتيح Data Connect استخدام الصفائف المُدمَجة.

طلبات البحث والتغييرات الضمنية والمحدّدة مسبقًا

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

في عملية التطوير، ستنفِّذ طلبات بحث محدّدة مسبقًا و عمليات تحويل محدّدة مسبقًا استنادًا إلى هذه العمليات الضمنية.

التسمية الضمنية لطلبات البحث والطفرات

Data Connect تستنتج أسماء مناسبة لطلبات البحث والطفرات الضمنية من تعريفات أنواع المخططات. على سبيل المثال، عند استخدام مصدر PostgreSQL ، إذا حدّدت جدولاً باسم Movie، سيُنشئ الخادم بشكل ضمني:

  • طلبات البحث لحالات استخدام جدول واحد بالأسماء السهلة movie (مفرد، لاسترداد نتائج فردية من خلال تمرير الوسيطات مثل eq) وmovies (جمع، لاسترداد قوائم النتائج من خلال تمرير الوسيطات مثل gt والعمليات مثل orderby). ينشئ Data Connect أيضًا طلبات بحث لعمليات ترابطية لعدة جداول بأسماء صريحة مثل actors_on_movies أو actors_via_actormovie.
  • الطفرات التي تحمل الاسم movie_insert وmovie_upsert...

تسمح لك لغة تعريف المخطط أيضًا بتحديد أسماء للعمليات بشكل صريح باستخدام وسيطات التوجيه singular وplural.

توجيهات لطلبات البحث والطفرات

بالإضافة إلى التوجيهات التي تستخدمها في تحديد الأنواع والجداول، يقدّم Data Connect توجيهات @auth و@check و@redact و @transaction لتحسين سلوك طلبات البحث والطفرات.

توجيه تنطبق على الوصف
@auth طلبات البحث والطفرات تحدِّد سياسة المصادقة لطلب بحث أو عملية تعديل. راجِع دليل التفويض والإقرار.
@check طلبات البحث عن بيانات التفويض للتحقّق من توفّر حقول محدّدة في نتائج طلب البحث يتم استخدام تعبير لغة التعبير الشائعة (CEL) لاختبار قيم الحقول. راجِع دليل التفويض والإقرار.
@redact طلبات البحث تم إخفاء جزء من ردّ العميل. راجِع دليل التفويض والإقرار.
@transaction الطفرات يفرض هذا الخيار تنفيذ عملية التعديل دائمًا في معاملة قاعدة بيانات. اطّلِع على أمثلة على تطبيقات الأفلام التي تمّت إزالة بياناتها.

طلبات البحث في قاعدة بيانات مراجعات الأفلام

يمكنك تحديد طلب بحث Data Connect باستخدام بيان نوع عملية طلب البحث واسم العملية، ووسائط عملية صفرية أو أكثر، وتوجيهات صفرية أو أكثر مع وسيطات.

في الدليل السريع، لم يستخدم مثال طلب البحث listEmails أيّ مَعلمات. بطبيعة الحال، في كثير من الحالات، ستكون البيانات التي يتم تمريرها إلى حقول طلبات البحث ديناميكية. يمكنك استخدام بنية $variableName للعمل مع المتغيّرات كأحد مكوّنات تعريف الطلب.

وبالتالي، يحتوي الاستعلام التالي على:

  • تعريف نوع query
  • اسم عملية (طلب بحث) ListMoviesByGenre
  • وسيطة عملية $genre لمتغيّر واحد
  • توجيه واحد، @auth
query ListMoviesByGenre($genre: String!) @auth(level: USER)

تتطلّب كل وسيطة طلب بحث بيان نوع أو عنصر مضمّن مثل String أو نوع مخصّص محدّد من المخطّط مثل Movie.

لنلقِ نظرة على توقيع الاستعلامات الأكثر تعقيدًا. ستنتهي من خلال تقديم تعبيرات قوية وموجزة للعلاقات متاحة في طلبات البحث الضمنية التي يمكنك الاستفادة منها في طلبات البحث المحدّدة مسبقًا.

القيم السلاسل الرئيسية في طلبات البحث

أولاً، ملاحظة حول السلاسل الرئيسية.

تحدّد Data Connect نوعًا خاصًا للمتغيّرات السلعية الرئيسية، والتي يتم تحديدها باستخدام _Key. على سبيل المثال، نوع متغيّر قياسي للمفتاح في جدول Movie هو Movie_Key.

يمكنك استرداد القيم السلاسل الرئيسية كاستجابة تعرضها معظم عمليات التحويل الضمنية، أو بالطبع من طلبات البحث التي استرددت فيها جميع الحقول اللازمة لإنشاء المفتاح السلاسل.

تتيح طلبات البحث التلقائية المفردة، مثل movie في المثال الجاري، استخدام مَعلمة مفتاح تقبل مقياسًا لمفتاح.

يمكنك تمرير مقياس مفتاح كقيمة ثابتة. ولكن يمكنك تحديد متغيّرات لتمرير المقاييس الرئيسية كإدخال.

query GetMovie($myKey: Movie_Key!) {
  movie(key: $myKey) { title }
}

ويمكن تقديم هذه البيانات في طلب JSON على النحو التالي (أو بتنسيقات رمزة أخرى):

{
  # 
  "variables": {
    "myKey": {"foo": "some-string-value", "bar": 42}
  }
}

بفضل التحليل المخصّص للمقاييس، يمكن أيضًا إنشاء Movie_Key باستخدام بنية العنصر التي قد تحتوي على متغيّرات. يكون ذلك مفيدًا في أغلب الأحيان عندما تريد تقسيم المكوّنات الفردية إلى متغيّرات مختلفة لسبب ما.

استخدام الأسماء البديلة في طلبات البحث

Data Connect يتيح استخدام الأسماء البديلة في GraphQL في طلبات البحث. باستخدام الأسماء البديلة، يمكنك إعادة تسمية البيانات التي يتم عرضها في نتائج طلب البحث. يمكن أن يطبّق طلب بحث واحد Data Connect فلاتر متعددة أو عمليات بحث أخرى في طلب واحد فعّال إلى الخادم، ما يؤدي إلى إصدار عدة "طلبات بحث فرعية" في آنٍ واحد. لتجنُّب تعارض الأسماء في مجموعة البيانات المعروضة، يمكنك استخدام الأسماء البديلة للتمييز بين طلبات البحث الفرعية.

في ما يلي طلب بحث يستخدم فيه التعبير الاسم المعرِّف mostPopular.

query ReviewTopPopularity($genre: String) {
  mostPopular: review(first: {
    where: {genre: {eq: $genre}},
    orderBy: {popularity: DESC}
  }) {  }
}

طلبات بحث بسيطة باستخدام الفلاتر

يتم ربط طلبات بحث Data Connect بجميع فلاتر SQL الشائعة وعمليات ترتيب .

عاملا التشغيل where وorderBy (طلبات البحث المفردة والمتعدّدة)

تعرض جميع الصفوف المطابقة من الجدول (والعمليات المرتبطة المتداخلة). تعرِض مصفوفة فارغة إذا لم تتطابق أي سجلّات مع الفلتر.

query MovieByTopRating($genre: String) {
  mostPopular: movies(
     where: { genre: { eq: $genre } }, orderBy: { rating: DESC }
  ) {
    # graphql: list the fields from the results to return
    id
    title
    genre
    description
  }
}

query MoviesByReleaseYear($min: Int, $max: Int) {
  movies(where: {releaseYear: {le: $max, ge: $min}}, orderBy: [{releaseYear: ASC}]) {  }
}

عاملا التشغيل limit وoffset (طلبات البحث المفردة والمتعدّدة)

يمكنك تقسيم النتائج إلى صفحات. يتم قبول هذه الوسيطات ولكن لا يتم عرضها في النتائج.

query MoviesTop10 {
  movies(orderBy: [{ rating: DESC }], limit: 10) {
    # graphql: list the fields from the results to return
    title
  }
}

يشمل حقول الصفيف

يمكنك اختبار ما إذا كان حقل مصفوفة يتضمّن عنصرًا محدّدًا.

# Filter using arrays and embedded fields.
query ListMoviesByTag($tag: String!) {
  movies(where: { tags: { includes: $tag }}) {
    # graphql: list the fields from the results to return
    id
    title
  }
}

عمليات السلاسل والتعابير العادية

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

query MoviesTitleSearch($prefix: String, $suffix: String, $contained: String, $regex: String) {
  prefixed: movies(where: {title: {startsWith: $prefix}}) {...}
  suffixed: movies(where: {title: {endsWith: $suffix}}) {...}
  contained: movies(where: {title: {contains: $contained}}) {...}
  matchRegex: movies(where: {title: {pattern: {regex: $regex}}}) {...}
}

or وand للفلاتر المركبة

استخدِم or وand للعمليات المنطقية الأكثر تعقيدًا.

query ListMoviesByGenreAndGenre($minRating: Int!, $genre: String) {
  movies(
    where: { _or: [{ rating: { ge: $minRating } }, { genre: { eq: $genre } }] }
  ) {
    # graphql: list the fields from the results to return
    title
  }
}

طلبات البحث المعقّدة

يمكن أن تصل طلبات بحث Data Connect إلى البيانات استنادًا إلى العلاقات بين الجداول. يمكنك استخدام علاقات العناصر (واحد لواحد) أو الصفيف (واحد لعدة عناصر) المحدّدة في مخطّطك لإجراء طلبات بحث مُدمجة، أي جلب بيانات لنوع واحد بالإضافة إلى بيانات من نوع مُدمج أو ذي صلة.

تستخدِم هذه الطلبات بنية الجملة السحرية Data Connect _on_ و_via في الطلبات الضمنية التي تم إنشاؤها.

ستُجري تعديلات على المخطّط من النسخة الأولية.

من عدّة مصادر إلى مصدر واحد

لنضيف مراجعات إلى تطبيقنا، مع جدول Review وتعديلات على User.

# Users
# Suppose a user can leave reviews for movies
# user:reviews is a one to many relationship,
# movie:reviews is a one to many relationship,
# movie:user is a many to many relationship
type User
  @table(name: "Users", singular: "user", plural: "users", key: ["id"]) {
  id: UUID! @col(name: "user_id") @default(expr: "uuidV4()")
  auth: String @col(name: "user_auth") @default(expr: "auth.uid")
  username: String! @col(name: "username", dataType: "varchar(30)")
  # The following are generated from the @ref in the Review table
  # reviews_on_user
  # movies_via_Review
}
# Reviews
type Review @table(name: "Reviews", key: ["movie", "user"]) {
  id: UUID! @col(name: "review_id") @default(expr: "uuidV4()")
  user: User! @ref
  movie: Movie! @ref
  rating: Int
  reviewText: String
  reviewDate: Date! @default(expr: "request.time")
}

طلب بحث من عدّة عناصر إلى عنصر واحد

لنلقِ الآن نظرة على طلب بحث يتضمّن أسماء بديلة لتوضيح بنية _via_.

query UserMoviePreferences($username: String!) @auth(level: USER) {
  users(where: { username: { eq: $username } }) {
    likedMovies: movies_via_review(where: { rating: { ge: 4 } }) {
      title
      genre
      description
    }
    dislikedMovies: movies_via_review(where: { rating: { le: 2 } }) {
      title
      genre
      description
    }
  }
}

اجتماعات فردية

يمكنك الاطّلاع على النمط. في ما يلي، تم تعديل المخطّط للتوضيح.

# Movies
type Movie
  @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int @col(name: "release_year")
  genre: String
  rating: Int @col(name: "rating")
  description: String @col(name: "description")
  tags: [String] @col(name: "tags")
}
# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata
  @table(
    name: "MovieMetadata"
  ) {
  # @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type
  # In this case, @ref(fields: "id") is implied
  movie: Movie! @ref
  # movieId: UUID <- this is created by the above @ref
  director: String @col(name: "director")
}


extend type MovieMetadata {
  movieId: UUID! # matches primary key of referenced type
...
}

extend type Movie {
  movieMetadata: MovieMetadata # can only be non-nullable on ref side
  # conflict-free name, always generated
  movieMetadatas_on_movie: MovieMetadata
}

طلب محادثة بين شخصين

يمكنك إجراء طلب بحث باستخدام بنية _on_.

# One to one
query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) {
  movie(id: $id) {
    movieMetadatas_on_movie {
      director
    }
  }
}

بين عدّة عناصر

تحتاج الأفلام إلى ممثلين، والممثلون يحتاجون إلى أفلام. بينهما علاقة "واحد إلى واحد" يمكنك وضع نموذج لها باستخدام جدول ربط MovieActors.

# MovieActors Join Table Definition
type MovieActors @table(
  key: ["movie", "actor"] # join key triggers many-to-many generation
) {
  movie: Movie!
  actor: Actor!
}

# generated extensions for the MovieActors join table
extend type MovieActors {
  movieId: UUID!
  actorId: UUID!
}

# Extensions for Actor and Movie to handle many-to-many relationships
extend type Movie {
  movieActors: [MovieActors!]! # standard many-to-one relation to join table
  actors: [Actor!]! # many-to-many via join table

  movieActors_on_actor: [MovieActors!]!
  # since MovieActors joins distinct types, type name alone is sufficiently precise
  actors_via_MovieActors: [Actor!]!
}

extend type Actor {
  movieActors: [MovieActors!]! # standard many-to-one relation to join table
  movies: [Movie!]! # many-to-many via join table

  movieActors_on_movie: [MovieActors!]!
  movies_via_MovieActors: [Movie!]!
}

طلب بحث للكثيرين إلى الكثيرين

لنلقِ نظرة على طلب بحث يتضمّن أسماء بديلة لتوضيح بنية _via_.

query GetMovieCast($movieId: UUID!, $actorId: UUID!) @auth(level: PUBLIC) {
  movie(id: $movieId) {
    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
      name
    }
    supportingActors: actors_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      name
    }
  }
  actor(id: $actorId) {
    mainRoles: movies_via_MovieActor(where: { role: { eq: "main" } }) {
      title
    }
    supportingRoles: movies_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      title
    }
  }
}

تعديلات على قاعدة بيانات مراجعات الأفلام

كما ذكرنا، عند تحديد جدول في مخطّطك، سيُنشئ Data Connect طفرات ضمنية أساسية لكل جدول.

type Movie @table { ... }

extend type Mutation {
  # Insert a row into the movie table.
  movie_insert(...): Movie_Key!
  # Upsert a row into movie."
  movie_upsert(...): Movie_Key!
  # Update a row in Movie. Returns null if a row with the specified id/key does not exist
  movie_update(...): Movie_Key
  # Update rows based on a filter in Movie.
  movie_updateMany(...): Int!
  # Delete a single row in Movie. Returns null if a row with the specified id/key does not exist
  movie_delete(...): Movie_Key
  # Delete rows based on a filter in Movie.
  movie_deleteMany(...): Int!
}

باستخدام هذه الأدوات، يمكنك تنفيذ حالات CRUD الأساسية الأكثر تعقيدًا. قل ذلك خمس مرات بسرعة.

توجيه @transaction

تفرض هذه التوجيهات تنفيذ عملية تعديل دائمًا في معاملة قاعدة بيانات.

يُضمن أنّ الطفرات التي تحتوي على @transaction ستنجح بالكامل أو لن تنجح بالكامل. إذا تعذّر إكمال أيّ من الحقول في المعاملة، يتمّ التراجع عن المعاملة بالكامل. من وجهة نظر العميل، يتصرف أيّ تعذّر كما لو أنّه تعذّر تنفيذ الطلب بالكامل بسبب خطأ في الطلب ولم يبدأ التنفيذ.

لا تنفِّذ عمليات التحويل التي لا تتضمّن @transaction كل حقل جذر تلو الآخر بالترتيب. ويعرض أي أخطاء كأخطاء جزئية في الحقول، ولكن ليس تأثيرات عمليات التنفيذ اللاحقة.

إنشاء

لنبدأ بإنشاء المحتوى الأساسي.

# Create a movie based on user input
mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
  movie_insert(data: {
    title: $title
    releaseYear: $releaseYear
    genre: $genre
    rating: $rating
  })
}

# Create a movie with default values
mutation CreateMovie2 {
  movie_insert(data: {
    title: "Sherlock Holmes"
    releaseYear: 2009
    genre: "Mystery"
    rating: 5
  })
}

أو عملية إضافة.

# Movie upsert using combination of variables and literals
mutation UpsertMovie($title: String!) {
  movie_upsert(data: {
    title: $title
    releaseYear: 2009
    genre: "Mystery"
    rating: 5
    genre: "Mystery/Thriller"
  })
}

إجراء التحديثات

في ما يلي آخر المعلومات. يأمل المنتجون والمخرجون بالتأكيد أن يكون متوسط التقييمات مرتفعًا.

mutation UpdateMovie(
  $id: UUID!,
  $genre: String!,
  $rating: Int!,
  $description: String!
) {
  movie_update(id: $id, data: {
    genre: $genre
    rating: $rating
    description: $description
  })
}

# Multiple updates (increase all ratings of a genre)
mutation IncreaseRatingForGenre($genre: String!, $ratingIncrement: Int!) {
  movie_updateMany(
    where: { genre: { eq: $genre } },
    update: { rating: { inc: $ratingIncrement } }
  )
}

تنفيذ عمليات الحذف

يمكنك بالطبع حذف بيانات الأفلام. سيريد القائمون على الحفاظ على الأفلام بالتأكيد الاحتفاظ بالأفلام المادية لأطول فترة ممكنة.

# Delete by key
mutation DeleteMovie($id: UUID!) {
  movie_delete(id: $id)
}

يمكنك هنا استخدام _deleteMany.

# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
  movie_deleteMany(where: { rating: { le: $minRating } })
}

كتابة طفرات في العلاقات

راقِب كيفية استخدام العنصر النائب _upsert في عملية التحويل على علاقة.

# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
  movieMetadata_upsert(
    data: { movie: { id: $movieId }, director: $director }
  )
}

طلبات البحث عن بيانات التفويض

Data Connect يمكن تفويض عمليات التحويل من خلال الاستعلام أولاً عن قاعدة البيانات والتحقّق من نتائج الاستعلام باستخدام تعبيرات CEL. يكون ذلك مفعّلاً عند كتابة بيانات في جدول وتحتاج إلى التحقّق من محتوى صف في جدول آخر.

تتيح هذه الميزة ما يلي:

  • توجيه @check الذي يتيح لك تقييم محتويات الحقول استنادًا إلى نتائج هذا التقييم:
    • المتابعة مع عمليات الإنشاء والتعديل والحذف المحدّدة من خلال عملية التحويل
    • استخدِم القيم التي يعرضها الاستعلام للعملاء لتنفيذ منطق مختلف في عملائك.
  • توجيه @redact، الذي يتيح لك حذف نتائج طلبات البحث من نتائج بروتوكول الشبكات

هذه الميزات مفيدة في عمليات التفويض.

مخطّط SQL المكافئ

-- Movies Table
CREATE TABLE Movies (
    movie_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    release_year INT,
    genre VARCHAR(30),
    rating INT,
    description TEXT,
    tags TEXT[]
);
-- Movie Metadata Table
CREATE TABLE MovieMetadata (
    movie_id UUID REFERENCES Movies(movie_id) UNIQUE,
    director VARCHAR(255) NOT NULL,
    PRIMARY KEY (movie_id)
);
-- Actors Table
CREATE TABLE Actors (
    actor_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    name VARCHAR(30) NOT NULL
);
-- MovieActor Join Table for Many-to-Many Relationship
CREATE TABLE MovieActor (
    movie_id UUID REFERENCES Movies(movie_id),
    actor_id UUID REFERENCES Actors(actor_id),
    role VARCHAR(50) NOT NULL, # "main" or "supporting"
    PRIMARY KEY (movie_id, actor_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id),
    FOREIGN KEY (actor_id) REFERENCES Actors(actor_id)
);
-- Users Table
CREATE TABLE Users (
    user_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_auth VARCHAR(255) NOT NULL
    username VARCHAR(30) NOT NULL
);
-- Reviews Table
CREATE TABLE Reviews (
    review_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_id UUID REFERENCES Users(user_id),
    movie_id UUID REFERENCES Movies(movie_id),
    rating INT,
    review_text TEXT,
    review_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE (movie_id, user_id)
    FOREIGN KEY (user_id) REFERENCES Users(user_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id)
);
-- Self Join Example for Movie Sequel Relationship
ALTER TABLE Movies
ADD COLUMN sequel_to UUID REFERENCES Movies(movie_id);

ما هي الخطوات التالية؟