المخططات وطلبات البحث وعمليات التغيير في 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(name) و@col(name) لتخصيص أسماء جدول وعمود SQL تُنشئ أداة Data Connect أسماء بتنسيق snake_case في حال عدم تحديدها.
  • @col(dataType) لتخصيص أنواع أعمدة SQL
  • @default لضبط القيم التلقائية لعمود SQL أثناء الإدراج

لمزيد من التفاصيل، اطّلِع على المستندات المرجعية لكل من @table و@col و@default.

# Movies
type Movie @table(name: "movie", key: "id") {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int
  genre: String @col(dataType: "varchar(20)")
  rating: Int
  description: String
}

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

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

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

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

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

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

أضِف حقل المرجع لتحديد العلاقات.

يمكنك استخدام التوجيه @ref لتخصيص قيد المفتاح الخارجي.

  • @ref(fields) لتحديد حقول المفتاح الخارجي
  • @ref(references) لتحديد الحقول المُشار إليها في الجدول المستهدَف. يكون هذا المرجع تلقائيًا هو المفتاح الأساسي، ولكن الحقول التي تحتوي على @unique متوافقة أيضًا.

لمزيد من التفاصيل، اطّلِع على المستندات المرجعية @ref.

# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata @table {
  # @unique ensures that each Movie only has one MoiveMetadata.
  movie: Movie! @unique
  # Since it references to another table type, it adds a foreign key constraint.
  #  movie: Movie! @unique @ref(fields: "movieId", references: "id")
  #  movieId: UUID! <- implicitly added foreign key field
  director: String
}

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 {
  id: UUID! @default(expr: "uuidV4()")
  name: String! @col(dataType: "varchar(30)")
}
# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary keys of this table
# In this case, the keys are [movieId, actorId], the foreign key fields of the reference fields [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  movie: Movie!
  # movieId: UUID! <- implicitly added foreign key field
  actor: Actor!
  # actorId: UUID! <- implicitly added foreign key field
  role: String! # "main" or "supporting"
  # optional other fields
}

المستخدم

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

# Users
# Suppose a user can leave reviews for movies
type User @table {
  id: String! @default(expr: "auth.uid")
  username: String! @col(dataType: "varchar(50)")
}

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

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

نوع Data Connect نوع مضمّن في GraphQL أو
Data Connect نوع مخصّص
نوع PostgreSQL التلقائي أنواع PostgreSQL المتوافقة
(الاسم المعرِّف بين قوسين)
سلسلة GraphQL النص نص
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.

# User table is keyed by Firebase Auth UID.
type User @table {
  # `@default(expr: "auth.uid")` sets it to Firebase Auth UID during insert and upsert.
  id: String! @default(expr: "auth.uid")
  username: String! @col(dataType: "varchar(50)")
  # The `user: User!` field in the Review table generates the following one-to-many query field.
  #  reviews_on_user: [Review!]!
  # The `Review` join table the following many-to-many query field.
  #  movies_via_Review: [Movie!]!
}

# Reviews is a join table tween User and Movie.
# It has a composite primary keys `userUid` and `movieId`.
# A user can leave reviews for many movies. A movie can have reviews from many users.
# User  <-> Review is a one-to-many relationship
# Movie <-> Review is a one-to-many relationship
# Movie <-> User is a many-to-many relationship
type Review @table(name: "Reviews", key: ["movie", "user"]) {
  user: User!
  # The user field adds the following foreign key field. Feel free to uncomment and customize it.
  #  userUid: String!
  movie: Movie!
  # The movie field adds the following foreign key field. Feel free to uncomment and customize it.
  #  movieId: UUID!
  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
    }
    dislikedMovies: movies_via_Review(where: { rating: { le: 2 } }) {
      title
      genre
    }
  }
}

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

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

# 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);

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