Firebase Data Connect ile derleme

1. Başlamadan Önce

FriendlyMovies uygulaması

Bu kod laboratuvarında, film yorumu web uygulaması oluşturmak için Firebase Data Connect'i bir Cloud SQL veritabanına entegre edeceksiniz. Tamamlanan uygulama, Firebase Data Connect'in SQL destekli uygulamalar oluşturma sürecini nasıl basitleştirdiğini gösterir. Bu özellikler şunlardır:

  • Kimlik doğrulama: Uygulamanızın sorguları ve mutasyonları için özel kimlik doğrulama uygulayarak yalnızca yetkili kullanıcıların verilerinizle etkileşim kurmasını sağlayın.
  • GraphQL şeması: Film yorumu web uygulamasının ihtiyaçlarına göre uyarlanmış esnek bir GraphQL şeması kullanarak veri yapılarınızı oluşturun ve yönetin.
  • SQL Sorguları ve Değişiklik İşlemleri: GraphQL tarafından desteklenen sorguları ve değişiklikleri kullanarak Cloud SQL'deki verileri alın, güncelleyin ve yönetin.
  • Kısmi dize eşleştirmeyle gelişmiş arama: Başlık, açıklama veya etiketler gibi alanlara göre film bulmak için filtreleri ve arama seçeneklerini kullanın.
  • İsteğe bağlı: Vektör Arama Entegrasyonu: Girişlere ve tercihlere dayalı zengin bir kullanıcı deneyimi sunmak için Firebase Data Connect'in vektör arama özelliğini kullanarak içerik arama işlevi ekleyin.

Ön koşullar

JavaScript hakkında temel düzeyde bilgi sahibi olmanız gerekir.

Öğrenecekleriniz

  • Firebase Data Connect'i yerel emülatörlerle ayarlama
  • Data Connect ve GraphQL'yi kullanarak veri şeması tasarlayın.
  • Film yorumu uygulaması için çeşitli sorgular ve mutasyonlar yazıp test edin.
  • Firebase Data Connect'in uygulamada SDK'yı nasıl oluşturduğunu ve kullandığını öğrenin.
  • Şemanızı dağıtın ve veritabanını verimli bir şekilde yönetin.

İhtiyacınız olanlar

Geliştirme Ortamınızı Kurma

Bu bölümde, Firebase Data Connect'i kullanarak film incelemesi uygulamanızı oluşturmaya başlamak için ortamı ayarlama konusunda size yol gösterilmektedir.

1. Adım: Proje deposunu klonlayın

Proje deposunu klonlayarak ve gerekli bağımlılıkları yükleyerek başlayın:

git clone https://github.com/firebaseextended/codelab-dataconnect-web
cd codelab-dataconnect-web
cd ./app && npm i
npm run dev
  1. Bu komutları çalıştırdıktan sonra web uygulamasının yerel olarak çalıştığını görmek için tarayıcınızda http://localhost:5173 adresini açın. Bu, film incelemesi uygulamasını oluşturmak ve özellikleriyle etkileşim kurmak için kullanacağınız ön uçtur.

93f6648a2532c606.png

2. Adım: Projeyi Visual Studio Code'da açın

Visual Studio Code'u kullanarak kopyalanan codelab-dataconnect-web klasörünü açın. Şemanızı tanımlayacağınız, sorgu yazacağınız ve uygulamanın işlevini test edeceğiniz yer burasıdır.

3. Adım: Firebase Data Connect Visual Studio uzantısını yükleyin

Data Connect özelliklerini kullanmak için Firebase Data Connect Visual Studio uzantısını yükleyin.Alternatif olarak: Visual Studio Code Marketplace'ten yükleyin veya VS Code'de arayın.

  1. Alternatif olarak: Visual Studio Code Marketplace'ten yükleyin veya VS Code'da arayın.

b03ee38c9a81b648.png

4. adım: Firebase projesi oluşturun

Henüz Firebase projeniz yoksa yeni bir Firebase projesi oluşturmak için Firebase Konsolu'na gidin. Ardından, Firebase Data Connect VSCode uzantısında:

  • Oturum aç düğmesini tıklayın.
  • Firebase projesi bağla'yı tıklayın ve Firebase Konsolu'nda oluşturduğunuz projeyi seçin.

4bb2fbf8f9fac29b.png

5. adım: Firebase emülatörlerini başlatın

Firebase Data Connect VSCode uzantısında, Emülatörleri Başlat'ı tıklayın ve emülatörlerin terminalde çalıştığını onaylayın.

6d3d95f4cb708db1.png

2. Başlangıç kod tabanını inceleyin

Bu bölümde, uygulamanın başlangıç kod tabanının önemli alanlarını keşfedeceksiniz. Uygulamada bazı işlevler eksik olsa da genel yapıyı anlamak faydalı olacaktır.

Klasör ve dosya yapısı

Uygulamanın klasör ve dosya yapısına genel bir bakış aşağıda verilmiştir:

dataconnect/

Firebase Data Connect yapılandırmalarını, bağlayıcıları (sorguları ve mutasyonları tanımlayan) ve şema dosyalarını içerir.

  • schema/schema.gql: GraphQL şemasını tanımlar
  • connector/queries.gql: Uygulamanızda gerekli olan sorgular.
  • connector/mutations.gql: Uygulamanızda yapılması gereken mutasyonlar.
  • connector/connector.yaml: SDK oluşturma için yapılandırma dosyası

app/src/

Uygulama mantığını ve Firebase Data Connect ile etkileşimi içerir.

  • firebase.ts: Konsolda bir Firebase uygulamasına bağlanmak için yapılandırma.
  • lib/dataconnect-sdk/: Bu klasör, oluşturulan SDK'yı içerir. SDK oluşturma konumunu connector/connector.yaml dosyasında düzenleyebilirsiniz. Böylece, bir sorgu veya mutasyon tanımladığınızda SDK'lar otomatik olarak oluşturulur.

3. Film yorumu için şema tanımlama

Bu bölümde, film uygulamasındaki temel öğeler arasındaki yapıyı ve ilişkileri bir şemada tanımlayacaksınız. Movie, User, Actor ve Review gibi varlıklar, Firebase Data Connect ve GraphQL şeması yönergeleri kullanılarak kurulan ilişkilerle veritabanı tablolarıyla eşlenir. Bu özelliği uygulamanıza ekledikten sonra, en yüksek puan alan filmleri aramaktan türe göre filtrelemeye, kullanıcıların yorum yazmasına, favorileri işaretlemesine, benzer filmleri keşfetmesine veya vektör arama üzerinden metin girişine göre önerilen filmleri bulmasına kadar her şeyi uygulamanızla yönetebilirsiniz.

Temel Varlıklar ve İlişkiler

Movie türü, uygulamanın aramalar ve film profilleri için kullandığı başlık, tür ve etiketler gibi önemli ayrıntıları içerir. User türü, yorumlar ve favoriler gibi kullanıcı etkileşimlerini izler. Reviews kullanıcıları filmlere yönlendirerek uygulamanın kullanıcı tarafından oluşturulan puanları ve geri bildirimleri göstermesine olanak tanır.

Filmler, aktörler ve kullanıcılar arasındaki ilişkiler uygulamayı daha dinamik hale getirir. MovieActor birleştirme tablosu, oyuncu kadrosu ayrıntılarını ve aktör filmografilerini görüntülemenize yardımcı olur. FavoriteMovie türü, kullanıcıların filmleri favorilere eklemesine olanak tanır. Böylece uygulama, kişiselleştirilmiş bir favoriler listesi gösterebilir ve popüler seçimleri öne çıkarabilir.

Film Tablosu

Film türü, başlık, tür, gösterimYılı ve derecelendirme gibi alanlar da dahil olmak üzere bir film öğesinin ana yapısını tanımlar.

Kod snippet'ini dataconnect/schema/schema.gql dosyanıza kopyalayıp yapıştırın:

type Movie
  @table {
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  imageUrl: String!
  releaseYear: Int
  genre: String
  rating: Float
  description: String
  tags: [String]
}

Temel Çıkarımlar:

  • id: Her film için @default(expr: "uuidV4()") kullanılarak oluşturulan benzersiz bir UUID.

MovieMetadata Tablosu

MovieMetadata türü, Movie türüyle bire bir ilişki kurar. Filmin yönetmeni gibi ek verileri içerir.

Kod snippet'ini dataconnect/schema/schema.gql dosyanıza kopyalayıp yapıştırın:

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

Temel Çıkarımlar:

  • Film! @ref: Movie türünü referans alarak yabancı anahtar ilişkisi oluşturur.

Oyuncu Tablosu

Kod snippet'ini dataconnect/schema/schema.gql dosyanıza kopyalayıp yapıştırın:

type Actor @table {
  id: UUID!
  imageUrl: String! 
  name: String! @col(name: "name", dataType: "varchar(30)")
}

Actor türü, film veritabanında bir oyuncuyu temsil eder. Her oyuncu birden fazla filmde yer alabilir ve bu da çoklu ilişki oluşturur.

MovieActor Tablosu

Kod snippet'ini dataconnect/schema/schema.gql dosyanıza kopyalayıp yapıştırın:

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!
  # movieId: UUID! <- this is created by the implied @ref, see: implicit.gql

  actor: Actor!
  # actorId: UUID! <- this is created by the implied  @ref, see: implicit.gql

  role: String! # "main" or "supporting"
}

Temel Çıkarımlar:

  • movie: Film türünü referans alır, film kimliği için yabancı anahtar (movieId: UUID!) oluşturur.
  • actor: İşlemi gerçekleştiren kullanıcı türünü referans alır, gizli olarak bir yabancı anahtar actorId: UUID! oluşturur.
  • role: Aktörün filmdeki rolünü tanımlar (ör. "main" veya "supporting").

Kullanıcı Tablosu

User türü, yorum bırakarak veya filmleri favorilere ekleyerek filmlerle etkileşimde bulunan bir kullanıcı öğesini tanımlar.

Kod snippet'ini dataconnect/schema/schema.gql dosyanıza kopyalayıp yapıştırın:

type User
  @table {
  id: String! @col(name: "auth_uid")
  username: String! @col(dataType: "varchar(50)")
  # The following are generated from the @ref in the Review table
  # reviews_on_user 
  # movies_via_Review
}

FavoriteMovie Tablosu

FavoriteMovie türü, kullanıcılar ile en sevdikleri filmler veya aktörler arasındaki çok-çok ilişkilerini yöneten bir birleştirme tablosudur. Her tablo bir User'ü bir Movie'a bağlar.

Kod snippet'ini dataconnect/schema/schema.gql dosyanıza kopyalayıp yapıştırın:

type FavoriteMovie
  @table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
  # @ref is implicit
  user: User!
  movie: Movie!
}

Temel Çıkarımlar:

  • movie: Film türünü referans alır, film kimliği için yabancı anahtar (movieId: UUID!) oluşturur.
  • user: Kullanıcı türünü referans alır, userId: UUID! adlı bir yabancı anahtar oluşturur.

İnceleme Tablosu

Review türü, yorum öğesini temsil eder ve User ile Movie türlerini çok-çok ilişkisi ile bağlar (bir kullanıcı çok sayıda yorum bırakabilir ve her filmin çok sayıda yorumu olabilir).

Kod snippet'ini dataconnect/schema/schema.gql dosyanıza kopyalayıp yapıştırın:

type Review @table(name: "Reviews", key: ["movie", "user"]) {
  id: UUID! @default(expr: "uuidV4()")
  user: User!
  movie: Movie!
  rating: Int
  reviewText: String
  reviewDate: Date! @default(expr: "request.time")
}

Temel Çıkarımlar:

  • user: Yorumu yazan kullanıcıyı belirtir.
  • movie: İncelenen filmi referans alır.
  • reviewDate: @default(expr: "request.time") kullanılarak yorumun oluşturulduğu saate otomatik olarak ayarlanır.

Otomatik Oluşturulan Alanlar ve Varsayılanlar

Şema, benzersiz kimlikler ve zaman damgaları otomatik olarak oluşturmak için @default(expr: "uuidV4()") gibi ifadeleri kullanır. Örneğin, yeni bir kayıt oluşturulduğunda Film ve Yorum türlerindeki kimlik alanı otomatik olarak bir UUID ile doldurulur.

Şema tanımlandığından film uygulamanız, veri yapısı ve ilişkileri için sağlam bir temele sahip oldu.

4. En Popüler ve En Son Filmleri Alma

FriendlyMovies uygulaması

Bu bölümde, yerel emülatörlere örnek film verileri ekleyeceğiz. Ardından, bu bağlayıcıları web uygulamasında çağırmak için bağlayıcıları (sorgular) ve TypeScript kodunu uygulayacağız. Bu işlem tamamlandığında uygulamanız, en yüksek puana sahip ve en yeni filmleri doğrudan veritabanından dinamik olarak alıp gösterebilecek.

Örnek Film, Oyuncu ve Yorum Verileri Ekleme

  1. VSCode'da dataconnect/moviedata_insert.gql dosyasını açın . Firebase Data Connect uzantısındaki emülatörlerin çalıştığından emin olun.
  2. Dosyanın üst kısmında Çalıştır (yerel) düğmesini görürsünüz. Sahte film verilerini veritabanınıza eklemek için bunu tıklayın.

e424f75e63bf2e10.png

  1. Verilerin başarıyla eklendiğini onaylamak için Veri Bağlantısı Çalıştırma terminalini kontrol edin.

e0943d7704fb84ea.png

Bağlayıcıyı uygulama

  1. dataconnect/movie-connector/queries.gql adlı görüşmeyi açın. Yorumlarda temel bir ListMovies sorgusu bulabilirsiniz:
query ListMovies @auth(level: PUBLIC) {
  movies {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

Bu sorgu, tüm filmleri ve ayrıntılarını (ör. kimlik, başlık, yayın yılı) getirir. Ancak filmleri sıralamaz.

  1. Sıralama ve sınırlama seçenekleri eklemek için ListMovies sorgusunu aşağıdaki sorguyla değiştirin:
# List subset of fields for movies
query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
  movies(
    orderBy: [
      { rating: $orderByRating },
      { releaseYear: $orderByReleaseYear }
    ]
    limit: $limit
  ) {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

Sorguyu yerel veritabanınızda yürütmek için Çalıştır (yerel) düğmesini tıklayın. Sorgu değişkenlerini çalıştırmadan önce yapılandırma bölmesine de girebilirsiniz.

c4d947115bb11b16.png

Temel Çıkarımlar:

  • movies(): Veritabanında film verilerini almak için kullanılan GraphQL sorgu alanı.
  • orderByRating: Filmleri puana göre (artan/azalan) sıralamak için kullanılan parametre.
  • orderByReleaseYear: Filmleri yayınlanma yılına göre (artan/azalan) sıralamak için kullanılan parametre.
  • limit: Döndürülen film sayısını kısıtlar.

Sorguları web uygulamasına entegre etme

Bu bölümde, web uygulamanızda önceki bölümde tanımlanan sorguları kullanacaksınız. Firebase Data Connect emülatörleri, .gql dosyalarındaki (schema.gql, queries.gql, mutations.gql) ve connector.yaml'daki bilgilere göre SDK'lar oluşturur. Bu SDK'lar doğrudan uygulamanızda çağrılabilir.

  1. MovieService (app/src/lib/MovieService.tsx) dosyasında, en üstteki içe aktarma ifadesinin yorumunu kaldırın:
import { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";

listMovies işlevi, ListMoviesData yanıt türü ve OrderDirection enum'i, Firebase Data Connect emülatörleri tarafından daha önce tanımladığınız şemaya ve sorgulara göre oluşturulan SDK'lardır .

  1. handleGetTopMovies ve handleGetLatestMovies işlevlerini aşağıdaki kodla değiştirin:
// Fetch top-rated movies
export const handleGetTopMovies = async (
  limit: number
): Promise<ListMoviesData["movies"] | null> => {
  try {
    const response = await listMovies({
      orderByRating: OrderDirection.DESC,
      limit,
    });
    return response.data.movies;
  } catch (error) {
    console.error("Error fetching top movies:", error);
    return null;
  }
};

// Fetch latest movies
export const handleGetLatestMovies = async (
  limit: number
): Promise<ListMoviesData["movies"] | null> => {
  try {
    const response = await listMovies({
      orderByReleaseYear: OrderDirection.DESC,
      limit,
    });
    return response.data.movies;
  } catch (error) {
    console.error("Error fetching latest movies:", error);
    return null;
  }
};

Temel Çıkarımlar:

  • listMovies: Film listesini almak için listMovies sorgusunu çağıran, otomatik olarak oluşturulan bir işlev. Bu sayfa, derecelendirmeye veya yayın yılına göre sıralama ve sonuç sayısını sınırlama seçenekleri sunar.
  • ListMoviesData: Ana sayfada en iyi 10 filmi ve en yeni filmleri göstermek için kullanılan sonuç türü.

Örnek üzerinden inceleyin

Sorgunun işleyişini görmek için web uygulamanızı yeniden yükleyin. Ana sayfa artık film listesini dinamik olarak görüntüler ve verileri doğrudan yerel veritabanınızdan alır. En yüksek puan alan ve en yeni filmler, yeni ayarladığınız verileri yansıtacak şekilde sorunsuz bir şekilde gösterilir.

5. Film ve Oyuncu Ayrıntılarını Gösterme

Bu bölümde, bir film veya aktörle ilgili ayrıntılı bilgileri benzersiz kimliklerini kullanarak alma işlevini uygulayacaksınız. Bu işlem, yalnızca ilgili tablolardan veri getirmeyi değil, film yorumları ve aktör filmografileri gibi kapsamlı ayrıntıları görüntülemek için ilgili tabloları birleştirmeyi de içerir.

ac7fefa7ff779231.png

Bağlayıcıları uygulama

  1. Projenizde dataconnect/movie-connector/queries.gql'yi açın .
  2. Film ve aktör ayrıntılarını almak için aşağıdaki sorguları ekleyin:
# Get movie by id
query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
 movie(id: $id) {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    description
    tags
    metadata: movieMetadatas_on_movie {
      director
    }
    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
      id
      name
      imageUrl
    }
    supportingActors: actors_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      id
      name
      imageUrl
    }
    reviews: reviews_on_movie {
      id
      reviewText
      reviewDate
      rating
      user {
        id
        username
      }
    }
  }
 }

# Get actor by id
query GetActorById($id: UUID!) @auth(level: PUBLIC) {
  actor(id: $id) {
    id
    name
    imageUrl
    mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
      id
      title
      genre
      tags
      imageUrl
    }
    supportingActors: movies_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      id
      title
      genre
      tags
      imageUrl
    }
  }
}
  1. Değişikliklerinizi kaydedin ve sorguları inceleyin.

Temel Çıkarımlar:

  • movie()/actor(): Filmler veya Oyuncular tablosundan tek bir film veya aktör getirmeye yönelik GraphQL sorgu alanları.
  • _on_: Bu, yabancı anahtar ilişkisi olan ilişkili bir türdeki alanlara doğrudan erişmenize olanak tanır. Örneğin, reviews_on_movie belirli bir filmle ilgili tüm yorumları getirir.
  • _via_: Bir birleştirme tablosu aracılığıyla çoklu-çoklu ilişkilerde gezinmek için kullanılır. Örneğin, actors_via_MovieActor, MovieActor birleştirme tablosu aracılığıyla Actor türüne erişir ve where koşulu, oyuncuları rollerine göre filtreler (ör. "ana" veya "destekleyici").

Veri Bağlantısı yürütme bölmesinde, aşağıdaki gibi sahte kimlikler girerek sorguyu test edebilirsiniz:

{"id": "550e8400-e29b-41d4-a716-446655440000"}

"Quantum Paradox" (yukarıdaki kimliğin ilişkili olduğu parodi film) ile ilgili ayrıntıları almak için GetMovieById için Çalıştır (yerel)'i tıklayın.

1b08961891e44da2.png

Sorguları web uygulamasına entegre etme

  1. MovieService (app/src/lib/MovieService.tsx) dosyasında aşağıdaki içe aktarma işlemlerinin yorumunu kaldırın:
import { getMovieById, GetMovieByIdData } from "@movie/dataconnect";
import { GetActorByIdData, getActorById } from "@movie/dataconnect";
  1. handleGetMovieById ve handleGetActorById işlevlerini aşağıdaki kodla değiştirin:
// Fetch movie details by ID
export const handleGetMovieById = async (
  movieId: string
) => {
  try {
    const response = await getMovieById({ id: movieId });
    if (response.data.movie) {
      return response.data.movie;
    }
    return null;
  } catch (error) {
    console.error("Error fetching movie:", error);
    return null;
  }
};

// Calling generated SDK for GetActorById
export const handleGetActorById = async (
  actorId: string
): Promise<GetActorByIdData["actor"] | null> => {
  try {
    const response = await getActorById({ id: actorId });
    if (response.data.actor) {
      return response.data.actor;
    }
    return null;
  } catch (error) {
    console.error("Error fetching actor:", error);
    return null;
  }
};

Temel Çıkarımlar:

  • getMovieById / getActorById: Bunlar, tanımladığınız sorguları çağıran ve belirli bir film veya aktörle ilgili ayrıntılı bilgiler alan otomatik olarak oluşturulan işlevlerdir.
  • GetMovieByIdData / GetActorByIdData: Bunlar, uygulamada film ve aktör ayrıntılarını görüntülemek için kullanılan sonuç türleridir.

Örnek üzerinden inceleyin

Ardından web uygulamanızın ana sayfasına gidin. Bir filmi tıkladığınızda, ilgili tablolardan alınan bilgilerle birlikte oyuncular ve yorumlar da dahil olmak üzere filmin tüm ayrıntılarını görüntüleyebilirsiniz. Benzer şekilde, bir oyuncuyu tıkladığınızda o oyuncunun yer aldığı filmler gösterilir.

6. Kullanıcı Kimlik Doğrulamasını İşleme

Bu bölümde, Firebase Authentication'ı kullanarak kullanıcı oturum açma ve oturum kapatma işlevini uygulayacaksınız. Ayrıca, Firebase Authentication verilerini kullanarak kullanıcı verilerini Firebase DataConnect'te doğrudan alabilir veya güncelleyebilirsiniz. Böylece uygulamanızda güvenli kullanıcı yönetimi sağlayabilirsiniz.

9890838045d5a00e.png

Bağlayıcıları uygulama

  1. dataconnect/movie-connector/'da mutations.gql dosyasını açın .
  2. Mevcut kimliği doğrulanmış kullanıcıyı oluşturmak veya güncellemek için aşağıdaki mutasyonu ekleyin:
# Create or update the current authenticated user
mutation UpsertUser($username: String!) @auth(level: USER) {
  user_upsert(
    data: {
      id_expr: "auth.uid"
      username: $username
    }
  )
}

Temel Çıkarımlar:

  • id_expr: "auth.uid": Bu yöntemde, kullanıcı veya uygulama tarafından değil, doğrudan Firebase Authentication tarafından sağlanan auth.uid kullanılır. Bu sayede, kullanıcı kimliğinin güvenli ve otomatik bir şekilde ele alınması sağlanarak ek bir güvenlik katmanı eklenir.

Ardından dataconnect/movie-connector/'da queries.gql dosyasını açın .

Mevcut kullanıcıyı almak için aşağıdaki sorguyu ekleyin:

# Get user by ID
query GetCurrentUser @auth(level: USER) {
  user(key: { id_expr: "auth.uid" }) {
    id
    username
    reviews: reviews_on_user {
      id
      rating
      reviewDate
      reviewText
      movie {
        id
        title
      }
    }
    favoriteMovies: favorite_movies_on_user {
      movie {
        id
        title
        genre
        imageUrl
        releaseYear
        rating
        description
        tags
        metadata: movieMetadatas_on_movie {
          director
        }
      }
    }
  }
}

Temel Çıkarımlar:

  • auth.uid: Bu değer doğrudan Firebase Authentication'dan alınır ve kullanıcıya özgü verilere güvenli erişim sağlar.
  • _on_ Alanlar: Bu alanlar, birleştirme tablolarını temsil eder:
  • reviews_on_user: Filmin kimliği ve başlığı da dahil olmak üzere kullanıcıyla ilgili tüm yorumları getirir.
  • favorite_movies_on_user: Tür, yayın yılı, derecelendirme ve meta veri gibi ayrıntılı bilgiler de dahil olmak üzere kullanıcı tarafından favori olarak işaretlenen tüm filmleri getirir.

Sorguları web uygulamasına entegre etme

  1. MovieService (app/src/lib/MovieService.tsx) dosyasında aşağıdaki içe aktarma işlemlerinin yorumunu kaldırın:
import { upsertUser } from "@movie/dataconnect";
import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
  1. handleAuthStateChange ve handleGetCurrentUser işlevlerini aşağıdaki kodla değiştirin:
// Handle user authentication state changes and upsert user
export const handleAuthStateChange = (
  auth: any,
  setUser: (user: User | null) => void
) => {
  return onAuthStateChanged(auth, async (user) => {
    if (user) {
      setUser(user);
      const username = user.email?.split("@")[0] || "anon";
      await upsertUser({ username });
    } else {
      setUser(null);
    }
  });
};

// Fetch current user profile
export const handleGetCurrentUser = async (): Promise<
  GetCurrentUserData["user"] | null
> => {
  try {
    const response = await getCurrentUser();
    return response.data.user;
  } catch (error) {
    console.error("Error fetching user profile:", error);
    return null;
  }
};

Temel Çıkarımlar:

  • handleAuthStateChange: Bu işlev, kimlik doğrulama durumu değişikliklerini izler. Kullanıcı oturum açtığında, kullanıcının verilerini ayarlar ve veritabanında kullanıcının bilgilerini oluşturmak veya güncellemek için upsertUser mutasyonunu çağırır.
  • handleGetCurrentUser: Kullanıcının yorumlarını ve favori filmlerini alan getCurrentUser sorgusunu kullanarak mevcut kullanıcının profilini getirir.

Örnek üzerinden inceleyin

Ardından, gezinme çubuğundaki "Google ile oturum aç" düğmesini tıklayın. Firebase Auth emülatörünü kullanarak oturum açabilirsiniz. Oturum açtıktan sonra "Profilim"i tıklayın. Bu klasör şimdilik boş olacak ancak uygulamanızda kullanıcıya özel veri işleme için temeli oluşturdunuz.

7. Kullanıcı Etkileşimleri'ni uygulama

Bu bölümde, film yorumu uygulamasına kullanıcı etkileşimlerini uygulayarak kullanıcıların favori filmlerini yönetmelerine ve yorum bırakmalarına ya da yorumları silmelerine olanak tanıyacaksınız.

b3d0ac1e181c9de9.png

Bağlayıcıları uygulama

  1. dataconnect/movie-connector/'da mutations.gql dosyasını açın .
  2. Filmleri favorilere ekleme işlemini gerçekleştirmek için aşağıdaki mutasyonları ekleyin:
# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}

# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

Temel Çıkarımlar:

  • userId_expr: "auth.uid": Doğrudan Firebase Authentication tarafından sağlanan auth.uid'ı kullanır. Bu sayede yalnızca kimliği doğrulanmış kullanıcının verilerine erişilir veya bu veriler değiştirilir.
  1. Ardından dataconnect/movie-connector/'da queries.gql dosyasını açın .
  2. Bir filmin favorilere eklenip eklenmediğini kontrol etmek için aşağıdaki sorguyu ekleyin:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
    movieId
  }
}

Temel Çıkarımlar:

  • auth.uid: Firebase Authentication'i kullanarak kullanıcıya özgü verilere güvenli erişim sağlar.
  • favorite_movie: Belirli bir filmin mevcut kullanıcı tarafından favori olarak işaretlenip işaretlenmediğini görmek için favorite_movies birleştirme tablosunu kontrol eder.

Sorguları web uygulamasına entegre etme

  1. MovieService (app/src/lib/MovieService.tsx) dosyasında aşağıdaki içe aktarma işlemlerinin yorumunu kaldırın:
import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from "@movie/dataconnect";
  1. handleAddFavoritedMovie, handleDeleteFavoritedMovie ve handleGetIfFavoritedMovie işlevlerini aşağıdaki kodla değiştirin:
// Add a movie to user's favorites
export const handleAddFavoritedMovie = async (
  movieId: string
): Promise<void> => {
  try {
    await addFavoritedMovie({ movieId });
  } catch (error) {
    console.error("Error adding movie to favorites:", error);
    throw error;
  }
};

// Remove a movie from user's favorites
export const handleDeleteFavoritedMovie = async (
  movieId: string
): Promise<void> => {
  try {
    await deleteFavoritedMovie({ movieId });
  } catch (error) {
    console.error("Error removing movie from favorites:", error);
    throw error;
  }
};

// Check if the movie is favorited by the user
export const handleGetIfFavoritedMovie = async (
  movieId: string
): Promise<boolean> => {
  try {
    const response = await getIfFavoritedMovie({ movieId });
    return !!response.data.favorite_movie;
  } catch (error) {
    console.error("Error checking if movie is favorited:", error);
    return false;
  }
};

Temel Çıkarımlar:

  • handleAddFavoritedMovie ve handleDeleteFavoritedMovie: Bir filmi kullanıcının favorilerine güvenli bir şekilde eklemek veya favorilerinden kaldırmak için mutasyonları kullanın.
  • handleGetIfFavoritedMovie: Bir filmin kullanıcı tarafından favori olarak işaretlenip işaretlenmediğini kontrol etmek için getIfFavoritedMovie sorgusunu kullanır.

Örnek üzerinden inceleyin

Artık film kartlarındaki ve film ayrıntıları sayfasındaki kalp simgesini tıklayarak filmleri favorilere ekleyebilir veya favorilerden kaldırabilirsiniz. Ayrıca, favori filmlerinizi profil sayfanızda görüntüleyebilirsiniz.

Kullanıcı Yorumlarını Uygulama

Ardından, uygulamada kullanıcı yorumlarını yönetme bölümünü uygulayacaksınız.

Bağlayıcıları uygulama

  1. mutations.gql (dataconnect/movie-connector/mutations.gql) dosyasına aşağıdaki mutasyonları ekleyin:
# Add a review for a movie
mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
@auth(level: USER) {
  review_insert(
    data: {
      userId_expr: "auth.uid"
      movieId: $movieId
      rating: $rating
      reviewText: $reviewText
      reviewDate_date: { today: true }
    }
  )
}

# Delete a user's review for a movie
mutation DeleteReview($movieId: UUID!) @auth(level: USER) {
  review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

Temel Çıkarımlar:

  • userId_expr: "auth.uid": Yorumların kimliği doğrulanmış kullanıcıyla ilişkilendirilmesini sağlar.
  • reviewDate_date: { today: true }: DataConnect'i kullanarak incelemenin geçerli tarihini otomatik olarak oluşturur ve manuel giriş ihtiyacını ortadan kaldırır.

Sorguları web uygulamasına entegre etme

  1. MovieService (app/src/lib/MovieService.tsx) dosyasında aşağıdaki içe aktarma işlemlerinin yorumunu kaldırın:
import { addReview, deleteReview } from "@movie/dataconnect";
  1. handleAddReview ve handleDeleteReview işlevlerini aşağıdaki kodla değiştirin:
// Add a review to a movie
export const handleAddReview = async (
  movieId: string,
  rating: number,
  reviewText: string
): Promise<void> => {
  try {
    await addReview({ movieId, rating, reviewText });
  } catch (error) {
    console.error("Error adding review:", error);
    throw error;
  }
};

// Delete a review from a movie
export const handleDeleteReview = async (movieId: string): Promise<void> => {
  try {
    await deleteReview({ movieId });
  } catch (error) {
    console.error("Error deleting review:", error);
    throw error;
  }
};

Temel Çıkarımlar:

  • handleAddReview: Belirtilen film için yorum eklemek üzere addReview mutasyonunu çağırır ve yorumu kimliği doğrulanmış kullanıcıya güvenli bir şekilde bağlar.
  • handleDeleteReview: Kimliği doğrulanmış kullanıcının bir filmle ilgili yorumunu kaldırmak için deleteReview mutasyonunu kullanır.

Örnek üzerinden inceleyin

Kullanıcılar artık film ayrıntıları sayfasında filmlerle ilgili yorum bırakabilir. Ayrıca, profil sayfalarında yorumlarını görüntüleyip silebilirler. Böylece, uygulamayla olan etkileşimleri üzerinde tam kontrol sahibi olurlar.

8. Gelişmiş Filtreler ve Kısmi Metin Eşleştirme

Bu bölümde, kullanıcıların filmleri çeşitli derecelendirmelere ve gösterim yıllarına göre arama yapmasına, türlere ve etiketlere göre filtrelemesine, başlıklarda veya açıklamalarda kısmi metin eşleştirme yapmasına ve hatta daha doğru sonuçlar için birden fazla filtreyi birleştirmesine olanak tanıyan gelişmiş arama özelliklerini uygulayacaksınız.

ece70ee0ab964e28.png

Bağlayıcıları uygulama

  1. queries.gql dosyasını dataconnect/movie-connector/ uygulamasında açın.
  2. Çeşitli arama özelliklerini desteklemek için aşağıdaki sorguyu ekleyin:
# Search for movies, actors, and reviews
query SearchAll(
  $input: String
  $minYear: Int!
  $maxYear: Int!
  $minRating: Float!
  $maxRating: Float!
  $genre: String!
) @auth(level: PUBLIC) {
  moviesMatchingTitle: movies(
    where: {
      _and: [
        { releaseYear: { ge: $minYear } }
        { releaseYear: { le: $maxYear } }
        { rating: { ge: $minRating } }
        { rating: { le: $maxRating } }
        { genre: { contains: $genre } }
        { title: { contains: $input } }
      ]
    }
  ) {
    id
    title
    genre
    rating
    imageUrl
  }
  moviesMatchingDescription: movies(
    where: {
      _and: [
        { releaseYear: { ge: $minYear } }
        { releaseYear: { le: $maxYear } }
        { rating: { ge: $minRating } }
        { rating: { le: $maxRating } }
        { genre: { contains: $genre } }
        { description: { contains: $input } }
      ]
    }
  ) {
    id
    title
    genre
    rating
    imageUrl
  }
  actorsMatchingName: actors(where: { name: { contains: $input } }) {
    id
    name
    imageUrl
  }
  reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) {
    id
    rating
    reviewText
    reviewDate
    movie {
      id
      title
    }
    user {
      id
      username
    }
  }
}

Temel Çıkarımlar:

  • _and operatörü: Birden fazla koşulu tek bir sorguda birleştirerek aramanın releaseYear, rating ve genre gibi çeşitli alanlara göre filtrelenmesine olanak tanır.
  • contains operatörü: Alanlar içinde kısmi metin eşleşmelerini arar. Bu sorguda title, description, name veya reviewText içinde eşleşmeler aranır.
  • where yan tümcesi: Verileri filtreleme koşullarını belirtir. Her bölümde (filmler, aktörler, yorumlar) aramayla ilgili belirli ölçütleri tanımlamak için bir where yan tümcesi kullanılır.

Sorguları web uygulamasına entegre etme

  1. MovieService (app/src/lib/MovieService.tsx) dosyasında aşağıdaki içe aktarma işlemlerinin yorumunu kaldırın:
import { searchAll, SearchAllData } from "@movie/dataconnect";
  1. handleSearchAll işlevini aşağıdaki kodla değiştirin:
// Function to perform the search using the query and filters
export const handleSearchAll = async (
  searchQuery: string,
  minYear: number,
  maxYear: number,
  minRating: number,
  maxRating: number,
  genre: string
): Promise<SearchAllData | null> => {
  try {
    const response = await searchAll({
      input: searchQuery,
      minYear,
      maxYear,
      minRating,
      maxRating,
      genre,
    });

    return response.data;
  } catch (error) {
    console.error("Error performing search:", error);
    return null;
  }
};

Temel Çıkarımlar:

  • handleSearchAll: Bu işlev, kullanıcının girişine göre arama yapmak için searchAll sorgusunu kullanır ve sonuçları yıl, puan, tür ve kısmi metin eşleşmeleri gibi parametrelere göre filtreler.

Örnek üzerinden inceleyin

Web uygulamasındaki gezinme çubuğundan "Gelişmiş Arama" sayfasına gidin. Artık çeşitli filtreler ve girişler kullanarak film, aktör ve yorum arayabilir, ayrıntılı ve size özel arama sonuçları elde edebilirsiniz.

9. İsteğe bağlı: Cloud'a dağıtma (Faturalandırma Gerekli)

Yerel geliştirme iterasyonunu tamamladığınıza göre şemanızı, verilerinizi ve sorgularınızı sunucuya dağıtma zamanı geldi. Bu işlem, Firebase Data Connect VS Code uzantısı veya Firebase CLI kullanılarak yapılabilir.

Firebase Konsolu'nda web uygulaması ekleme

  1. Firebase Konsolu'nda bir web uygulaması oluşturun ve uygulama kimliğinizi not edin.

7030822793e4d75b.png

  1. "Uygulama Ekle"yi tıklayarak Firebase Konsolu'nda bir web uygulaması oluşturun. SDK kurulumunu ve yapılandırma ayarlarını şimdilik güvenle yoksayabilirsiniz ancak oluşturulan firebaseConfig nesnesini not edin.
  2. app/src/lib/firebase.tsx içindeki firebaseConfig değerini değiştirin:
const firebaseConfig = {
  apiKey: "API_KEY",
  authDomain: "PROJECT_ID.firebaseapp.com",
  projectId: "PROJECT_ID",
  storageBucket: "PROJECT_ID.appspot.com",
  messagingSenderId: "SENDER_ID",
  appId: "APP_ID"
};
  1. Web uygulamasını derleyin: app klasöründe, barındırma dağıtımı için web uygulamasını derlemek üzere Vite'yi kullanın:
cd app
npm run build

Konsol'da Firebase Kimlik Doğrulaması'nı ayarlama

  1. Google ile oturum açma özelliğini kullanarak Firebase Auth'u ayarlama

62af2f225e790ef6.png

  1. (İsteğe bağlı) Proje konsolunuzda (Firebase Auth) [https://firebase.google.com/docs/auth/web/hosting] alan adlarına izin verin (ör. http://127.0.0.1):

c255098f12549886.png

Firebase CLI ile dağıtma

  1. dataconnect/dataconnect.yaml'te örnek kimliğinizin, veritabanınızın ve hizmet kimliğinizin projenizle eşleştiğinden emin olun:
specVersion: "v1alpha"
serviceId: "your-service-id"
location: "us-central1"
schema:
  source: "./schema"
  datasource:
    postgresql:
      database: "your-database-id"
      cloudSql:
        instanceId: "your-instance-id"
connectorDirs: ["./movie-connector"]
  1. Firebase CLI'yi projenizle ayarladığınızdan emin olun
npm i -g firebase-tools
firebase login --reauth
firebase use --add
  1. Dağıtmak için terminalinizde aşağıdaki komutu çalıştırın:
firebase deploy --only dataconnect,hosting
  1. Şema değişikliklerinizi karşılaştırmak için şu komutu çalıştırın:
firebase dataconnect:sql:diff
  1. Değişiklikler kabul edilebilirse aşağıdakilerle uygulayın:
firebase dataconnect:sql:migrate

PostgreSQL için Cloud SQL örneğiniz, dağıtılan nihai şema ve verilerle güncellenir. Durumu Firebase Konsolu'nda izleyebilirsiniz.

Artık uygulamanızı your-project.web.app/ adresinde canlı olarak görebilirsiniz. Ayrıca, üretim ortamına veri eklemek için yerel emülatörlerde yaptığınız gibi Firebase Data Connect panelinde Çalıştır (Üretim)'ı tıklayabilirsiniz.

10. İsteğe bağlı: Firebase Data Connect ile Vektör Arama

Bu bölümde, Firebase Data Connect'i kullanarak film yorumu uygulamanızda vektör aramayı etkinleştireceksiniz. Bu özellik, içerik tabanlı aramalara (ör. vektör yerleştirmelerini kullanarak benzer açıklamalara sahip filmleri bulma) olanak tanır.

4b5aca5a447d2feb.png

Şemayı bir alan için yerleşik öğeleri içerecek şekilde güncelleme

  1. dataconnect/schema/schema.gql'te, descriptionEmbedding alanını Movie tablosuna ekleyin:
type Movie
  # The below parameter values are generated by default with @table, and can be edited manually.
  @table {
  # implicitly calls @col to generates a column name. ex: @col(name: "movie_id")
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  imageUrl: String!
  releaseYear: Int
  genre: String
  rating: Float
  description: String
  tags: [String]
  descriptionEmbedding: Vector @col(size:768) # Enables vector search
}

Temel Çıkarımlar:

  • descriptionEmbedding: Vector @col(size:768): Bu alan, film açıklamalarının anlamsal yerleştirmelerini depolar ve uygulamanızda vektör tabanlı içerik aramasını etkinleştirir.

Vertex AI'ı etkinleştirme

  1. Vertex AI API'lerini Google Cloud ile ayarlamak için ön koşullar kılavuzunu uygulayın. Bu adım, yerleştirilmiş öğe oluşturma ve vektör arama işlevini desteklemek için gereklidir.
  2. Firebase Data Connect VSCode uzantısını kullanarak Üretime Yayınla'yı tıklayarak pgvector ve vektör aramayı etkinleştirmek için şemanızı yeniden dağıtın.

Veritabanını Yerleşimlerle Doldurma

  1. Veritabanınıza filmlerin yerleştirmelerini eklemek için VSCode'da dataconnect klasörünü açın ve optional_vector_embed.gql'da Çalıştır(yerel)'ı tıklayın.

b858da780f6ec103.png

Vektör Arama Sorgusu ekleme

  1. dataconnect/movie-connector/queries.gql alanına, vektör aramaları yapmak için aşağıdaki sorguyu ekleyin:
# Search movie descriptions using L2 similarity with Vertex AI
query SearchMovieDescriptionUsingL2Similarity($query: String!)
@auth(level: PUBLIC) {
  movies_descriptionEmbedding_similarity(
    compare_embed: { model: "textembedding-gecko@003", text: $query }
    method: L2
    within: 2
    limit: 5
  ) {
    id
    title
    description
    tags
    rating
    imageUrl
  }
}

Temel Çıkarımlar:

  • compare_embed: Karşılaştırma için yerleştirme modelini (textembedding-gecko@003) ve giriş metnini ($query) belirtir.
  • method: Öklid uzaklığını temsil eden benzerlik yöntemini (L2) belirtir.
  • within: Aramayı, yakın içerik eşleşmelerine odaklanarak L2 mesafesi 2 veya daha az olan filmlerle sınırlandırır.
  • limit: Döndürülen sonuç sayısını 5 ile sınırlandırır.

Uygulamaya Vector Search işlevini uygulama

  1. app/src/lib/MovieService.ts dosyasında aşağıdaki içe aktarma işlemlerinin yorumunu kaldırın:

Uygulamada Vektör Arama işlevini uygulama

Şema ve sorgu oluşturulduğuna göre vektör aramayı uygulamanızın hizmet katmanına entegre edin. Bu adım, arama sorgusunu web uygulamanızdan çağırmanıza olanak tanır.

app/src/lib/ MovieService.ts dosyasında, SDK'lardan aşağıdaki içe aktarma işlemlerinin yorumunu kaldırın. Bu işlem diğer tüm sorgular gibi çalışır.

import {
  searchMovieDescriptionUsingL2similarity,
  SearchMovieDescriptionUsingL2similarityData,
} from "@movie/dataconnect";

Vektör tabanlı aramayı uygulamaya entegre etmek için aşağıdaki işlevi ekleyin:

// Perform vector-based search for movies based on description
export const searchMoviesByDescription = async (
  query: string
): Promise<
  | SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
  | null
> => {
  try {
    const response = await searchMovieDescriptionUsingL2similarity({ query });
    return response.data.movies_descriptionEmbedding_similarity;
  } catch (error) {
    console.error("Error fetching movie descriptions:", error);
    return null;
  }
};


Temel Çıkarımlar:

  • searchMoviesByDescription: Bu işlev, searchMovieDescriptionUsingL2similarity sorgusunu çağırır ve vektör tabanlı bir içerik araması gerçekleştirmek için giriş metnini iletir.

Örnek üzerinden inceleyin

Gezinme çubuğundaki "Vektör Arama" bölümüne gidin ve "romantik ve modern" gibi ifadeler yazın. Aradığınız içerikle eşleşen filmlerin listesini görürsünüz. Dilerseniz herhangi bir filmin ayrıntılar sayfasına gidip sayfanın alt kısmındaki benzer filmler bölümüne göz atabilirsiniz.

7b71f1c75633c1be.png

11. Sonuç

Tebrikler, web uygulamasını kullanabilirsiniz. Kendi film verilerinizle oynamak istiyorsanız endişelenmeyin. _insert.gql dosyalarını taklit ederek FDC uzantısını kullanarak kendi verilerinizi ekleyin veya Veri Bağlantısı Yürütme bölmesinden ekleyin.

Daha fazla bilgi