diff --git a/dataconnect/.firebaserc b/dataconnect/.firebaserc
index 89a1108c..6def5060 100644
--- a/dataconnect/.firebaserc
+++ b/dataconnect/.firebaserc
@@ -1,12 +1,7 @@
{
"projects": {
- "default": "FIREBASE_PROJECT_ID_HERE"
+ "default": null
},
"targets": {},
- "etags": {},
- "dataconnectEmulatorConfig": {
- "postgres": {
- "localConnectionString": "postgresql://user:mypassword@localhost:5432/dataconnect?sslmode=disable"
- }
- }
+ "etags": {}
}
diff --git a/dataconnect/README.md b/dataconnect/README.md
index aeceda69..eec07d80 100644
--- a/dataconnect/README.md
+++ b/dataconnect/README.md
@@ -1,5 +1,5 @@
# Firebase Data Connect
-
+
diff --git a/dataconnect/flutter-blank/.gitignore b/dataconnect/flutter-blank/.gitignore
new file mode 100644
index 00000000..29a3a501
--- /dev/null
+++ b/dataconnect/flutter-blank/.gitignore
@@ -0,0 +1,43 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/dataconnect/flutter-blank/.metadata b/dataconnect/flutter-blank/.metadata
new file mode 100644
index 00000000..90eabcff
--- /dev/null
+++ b/dataconnect/flutter-blank/.metadata
@@ -0,0 +1,45 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ - platform: android
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ - platform: ios
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ - platform: linux
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ - platform: macos
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ - platform: web
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ - platform: windows
+ create_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+ base_revision: 80c2e84975bbd28ecf5f8d4bd4ca5a2490bfc819
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/dataconnect/flutter-blank/analysis_options.yaml b/dataconnect/flutter-blank/analysis_options.yaml
new file mode 100644
index 00000000..0d290213
--- /dev/null
+++ b/dataconnect/flutter-blank/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/dataconnect/flutter-blank/android/.gitignore b/dataconnect/flutter-blank/android/.gitignore
new file mode 100644
index 00000000..55afd919
--- /dev/null
+++ b/dataconnect/flutter-blank/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/to/reference-keystore
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/dataconnect/flutter-blank/android/app/build.gradle b/dataconnect/flutter-blank/android/app/build.gradle
new file mode 100644
index 00000000..309ddf75
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/build.gradle
@@ -0,0 +1,63 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file("local.properties")
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader("UTF-8") { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
+if (flutterVersionCode == null) {
+ flutterVersionCode = "1"
+}
+
+def flutterVersionName = localProperties.getProperty("flutter.versionName")
+if (flutterVersionName == null) {
+ flutterVersionName = "1.0"
+}
+
+
+android {
+ namespace = "com.example.blank"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.example.blank"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
+ minSdk = 23
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutterVersionCode.toInteger()
+ versionName = flutterVersionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/dataconnect/flutter-blank/android/app/src/debug/AndroidManifest.xml b/dataconnect/flutter-blank/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 00000000..399f6981
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/dataconnect/flutter-blank/android/app/src/main/AndroidManifest.xml b/dataconnect/flutter-blank/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..b79e6209
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-blank/android/app/src/main/kotlin/com/example/blank/MainActivity.kt b/dataconnect/flutter-blank/android/app/src/main/kotlin/com/example/blank/MainActivity.kt
new file mode 100644
index 00000000..06a2fff7
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/main/kotlin/com/example/blank/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.example.blank
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/drawable-v21/launch_background.xml b/dataconnect/flutter-blank/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 00000000..f74085f3
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/drawable/launch_background.xml b/dataconnect/flutter-blank/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 00000000..304732f8
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..db77bb4b
Binary files /dev/null and b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..17987b79
Binary files /dev/null and b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..09d43914
Binary files /dev/null and b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..d5f1c8d3
Binary files /dev/null and b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..4d6372ee
Binary files /dev/null and b/dataconnect/flutter-blank/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/values-night/styles.xml b/dataconnect/flutter-blank/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 00000000..06952be7
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-blank/android/app/src/main/res/values/styles.xml b/dataconnect/flutter-blank/android/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..cb1ef880
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-blank/android/app/src/profile/AndroidManifest.xml b/dataconnect/flutter-blank/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 00000000..399f6981
--- /dev/null
+++ b/dataconnect/flutter-blank/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/dataconnect/flutter-blank/android/build.gradle b/dataconnect/flutter-blank/android/build.gradle
new file mode 100644
index 00000000..d2ffbffa
--- /dev/null
+++ b/dataconnect/flutter-blank/android/build.gradle
@@ -0,0 +1,18 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = "../build"
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/dataconnect/flutter-blank/android/gradle.properties b/dataconnect/flutter-blank/android/gradle.properties
new file mode 100644
index 00000000..25971708
--- /dev/null
+++ b/dataconnect/flutter-blank/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/dataconnect/flutter-blank/android/gradle/wrapper/gradle-wrapper.properties b/dataconnect/flutter-blank/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..e1ca574e
--- /dev/null
+++ b/dataconnect/flutter-blank/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
diff --git a/dataconnect/flutter-blank/android/settings.gradle b/dataconnect/flutter-blank/android/settings.gradle
new file mode 100644
index 00000000..536165d3
--- /dev/null
+++ b/dataconnect/flutter-blank/android/settings.gradle
@@ -0,0 +1,25 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }()
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+ id "com.android.application" version "7.3.0" apply false
+ id "org.jetbrains.kotlin.android" version "1.7.10" apply false
+}
+
+include ":app"
diff --git a/dataconnect/nextjs-blank/dataconnect/connector/connector.yaml b/dataconnect/flutter-blank/dataconnect/connector/connector.yaml
similarity index 76%
rename from dataconnect/nextjs-blank/dataconnect/connector/connector.yaml
rename to dataconnect/flutter-blank/dataconnect/connector/connector.yaml
index 8cf696c4..f2dcf8ab 100644
--- a/dataconnect/nextjs-blank/dataconnect/connector/connector.yaml
+++ b/dataconnect/flutter-blank/dataconnect/connector/connector.yaml
@@ -10,11 +10,9 @@ generate:
# kotlinSdk:
# outputDir:
# package: connectors.default
- javascriptSdk:
+ dartSdk:
# Create a custom package name for your generated SDK
- package: "@blank/generated"
+ package: "blank_package"
# Tells Data Connect where to store the generated SDK code, this should be in the same
# directory as your app code
- outputDir: "../../webapp/dataconnect-generated"
- # This property tells Data Connect what directory to install the generated SDK to
- packageJsonDir: "../../webapp"
+ outputDir: "../../lib/generated"
diff --git a/dataconnect/nextjs-blank/dataconnect/connector/mutations.gql b/dataconnect/flutter-blank/dataconnect/connector/mutations.gql
similarity index 100%
rename from dataconnect/nextjs-blank/dataconnect/connector/mutations.gql
rename to dataconnect/flutter-blank/dataconnect/connector/mutations.gql
diff --git a/dataconnect/nextjs-blank/dataconnect/connector/queries.gql b/dataconnect/flutter-blank/dataconnect/connector/queries.gql
similarity index 100%
rename from dataconnect/nextjs-blank/dataconnect/connector/queries.gql
rename to dataconnect/flutter-blank/dataconnect/connector/queries.gql
diff --git a/dataconnect/nextjs-blank/dataconnect/dataconnect.yaml b/dataconnect/flutter-blank/dataconnect/dataconnect.yaml
similarity index 100%
rename from dataconnect/nextjs-blank/dataconnect/dataconnect.yaml
rename to dataconnect/flutter-blank/dataconnect/dataconnect.yaml
diff --git a/dataconnect/nextjs-blank/dataconnect/schema/schema.gql b/dataconnect/flutter-blank/dataconnect/schema/schema.gql
similarity index 100%
rename from dataconnect/nextjs-blank/dataconnect/schema/schema.gql
rename to dataconnect/flutter-blank/dataconnect/schema/schema.gql
diff --git a/dataconnect/flutter-blank/dev.nix b/dataconnect/flutter-blank/dev.nix
new file mode 100644
index 00000000..064d6520
--- /dev/null
+++ b/dataconnect/flutter-blank/dev.nix
@@ -0,0 +1,73 @@
+# To learn more about how to use Nix to configure your environment
+# see: https://developers.google.com/idx/guides/customize-idx-env
+{ pkgs, ... }: {
+ processes = {
+ writeEnv = {
+ command = "echo \"HOST=$WEB_HOST\" > .env";
+ };
+ };
+
+ # Which nixpkgs channel to use.
+ channel = "stable-24.05"; # or "unstable"
+
+
+ # Use https://search.nixos.org/packages to find packages
+ packages = [
+ pkgs.nodejs_20
+ (pkgs.postgresql_15.withPackages (p: [ p.pgvector ]))
+ pkgs.nodePackages.pnpm
+ pkgs.jdk17
+ pkgs.unzip
+ pkgs.caddy
+ ];
+
+ # Sets environment variables in the workspace
+ env = {
+ POSTGRESQL_CONN_STRING = "postgresql://user:mypassword@localhost:5432/dataconnect?sslmode=disable";
+ PATH = ["/home/user/.pub-cache/bin" "/home/user/flutter/bin" "./.flutter-sdk/flutter/bin"];
+ };
+ idx = {
+ # Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
+ extensions = [
+ "mtxr.sqltools"
+ "Dart-Code.flutter"
+ "Dart-Code.dart-code"
+ "mtxr.sqltools-driver-pg"
+ "GraphQL.vscode-graphql-syntax"
+ "GoogleCloudTools.firebase-dataconnect-vscode"
+ ];
+
+ workspace = {
+ # Runs when a workspace is first created with this `dev.nix` file
+ onCreate = {
+ installSdk = ''
+ chmod +x ./installDeps.sh
+ ./installDeps.sh
+ '';
+ };
+ onStart = {
+ startProxy = ''
+ caddy run
+ '';
+ };
+
+ # To run something each time the workspace is (re)started, use the `onStart` hook
+ };
+ # set up a proxy that routes requests from $PORT in IDX to 9003, and any FDC-like queries are automatically rerouted to FDC
+ # Enable previews and customize configuration
+ previews = {
+ enable = true;
+ previews = {
+ web = {
+ command = ["flutter" "run" "--machine" "-d" "web-server" "--web-hostname" "0.0.0.0" "--web-port" "9003"];
+ manager = "flutter";
+ };
+ android = {
+ command = ["flutter" "run" "--machine" "-d" "android" "-d" "localhost:5555"];
+ manager = "flutter";
+ };
+ };
+ };
+ };
+
+}
\ No newline at end of file
diff --git a/dataconnect/nextjs-email-app/firebase.json b/dataconnect/flutter-blank/firebase.json
similarity index 90%
rename from dataconnect/nextjs-email-app/firebase.json
rename to dataconnect/flutter-blank/firebase.json
index 861a21dc..57c62dd9 100644
--- a/dataconnect/nextjs-email-app/firebase.json
+++ b/dataconnect/flutter-blank/firebase.json
@@ -4,7 +4,7 @@
},
"emulators": {
"dataconnect": {
- "port": 9399
+ "port": 9400
},
"ui": {
"enabled": false
diff --git a/dataconnect/flutter-blank/lib/firebase_options.dart b/dataconnect/flutter-blank/lib/firebase_options.dart
new file mode 100644
index 00000000..9c664017
--- /dev/null
+++ b/dataconnect/flutter-blank/lib/firebase_options.dart
@@ -0,0 +1,57 @@
+// File generated by FlutterFire CLI.
+// ignore_for_file: type=lint
+import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
+import 'package:flutter/foundation.dart'
+ show defaultTargetPlatform, kIsWeb, TargetPlatform;
+
+/// Default [FirebaseOptions] for use with your Firebase apps.
+///
+/// Example:
+/// ```dart
+/// import 'firebase_options.dart';
+/// // ...
+/// await Firebase.initializeApp(
+/// options: DefaultFirebaseOptions.currentPlatform,
+/// );
+/// ```
+class DefaultFirebaseOptions {
+ static FirebaseOptions get currentPlatform {
+ if (kIsWeb) {
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for ios - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ }
+ switch (defaultTargetPlatform) {
+ case TargetPlatform.android:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for ios - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.iOS:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for ios - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.macOS:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for macos - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.windows:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for windows - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.linux:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for linux - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ default:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions are not supported for this platform.',
+ );
+ }
+ }
+}
diff --git a/dataconnect/flutter-blank/lib/main.dart b/dataconnect/flutter-blank/lib/main.dart
new file mode 100644
index 00000000..419aa3cb
--- /dev/null
+++ b/dataconnect/flutter-blank/lib/main.dart
@@ -0,0 +1,210 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+
+import 'package:firebase_core/firebase_core.dart';
+import 'package:flutter_dotenv/flutter_dotenv.dart';
+
+import 'firebase_options.dart';
+import 'error_handler.dart';
+import 'package:blank/generated/blank.dart';
+
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ int port = 443;
+ String hostName = Uri.base.host;
+ if (!kIsWeb) {
+ hostName = '10.0.2.2';
+ port = 9403;
+ }
+ try {
+ await Firebase.initializeApp(
+ options: DefaultFirebaseOptions.currentPlatform,
+ );
+ MovieConnectorConnector.instance.dataConnect
+ .useDataConnectEmulator(hostName, port, isSecure: true);
+ runApp(const MyApp());
+ } catch (_) {
+ runApp(const ShowError());
+ }
+}
+
+class ShowError extends StatelessWidget {
+ const ShowError({super.key});
+
+ // This widget is the root of your application.
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Error',
+ theme: ThemeData(
+ // This is the theme of your application.
+ //
+ // TRY THIS: Try running your application with "flutter run". You'll see
+ // the application has a purple toolbar. Then, without quitting the app,
+ // try changing the seedColor in the colorScheme below to Colors.green
+ // and then invoke "hot reload" (save your changes or press the "hot
+ // reload" button in a Flutter-supported IDE, or press "r" if you used
+ // the command line to start the app).
+ //
+ // Notice that the counter didn't reset back to zero; the application
+ // state is not lost during the reload. To reset the state, use hot
+ // restart instead.
+ //
+ // This works for code too, not just values: Most code changes can be
+ // tested with just a hot reload.
+ colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+ useMaterial3: true,
+ ),
+ home: const Text(
+ "Run flutterfire configure to continue and refresh the page."),
+ );
+ }
+}
+
+class ErrorContent extends StatelessWidget {
+ const ErrorContent({super.key});
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ // TRY THIS: Try changing the color here to a specific color (to
+ // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
+ // change color while the other colors stay the same.
+ backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+ // Here we take the value from the MyHomePage object that was created by
+ // the App.build method, and use it to set our appbar title.
+ title: Text(widget.title),
+ ),
+ body: Center(
+ // Center is a layout widget. It takes a single child and positions it
+ // in the middle of the parent.
+ child: Column(
+ // Column is also a layout widget. It takes a list of children and
+ // arranges them vertically. By default, it sizes itself to fit its
+ // children horizontally, and tries to be as tall as its parent.
+ //
+ // Column has various properties to control how it sizes itself and
+ // how it positions its children. Here we use mainAxisAlignment to
+ // center the children vertically; the main axis here is the vertical
+ // axis because Columns are vertical (the cross axis would be
+ // horizontal).
+ //
+ // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
+ // action in the IDE, or press "p" in the console), to see the
+ // wireframe for each widget.
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Center(
+ child: Text(
+ "Open the Firebase Data Connect Extension and click 'Start Emulators' to get started."),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ // This widget is the root of your application.
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Demo',
+ theme: ThemeData(
+ // This is the theme of your application.
+ //
+ // TRY THIS: Try running your application with "flutter run". You'll see
+ // the application has a purple toolbar. Then, without quitting the app,
+ // try changing the seedColor in the colorScheme below to Colors.green
+ // and then invoke "hot reload" (save your changes or press the "hot
+ // reload" button in a Flutter-supported IDE, or press "r" if you used
+ // the command line to start the app).
+ //
+ // Notice that the counter didn't reset back to zero; the application
+ // state is not lost during the reload. To reset the state, use hot
+ // restart instead.
+ //
+ // This works for code too, not just values: Most code changes can be
+ // tested with just a hot reload.
+ colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
+ useMaterial3: true,
+ ),
+ home: const MyHomePage(title: 'Flutter Demo Home Page'),
+ );
+ }
+}
+
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({super.key, required this.title});
+
+ // This widget is the home page of your application. It is stateful, meaning
+ // that it has a State object (defined below) that contains fields that affect
+ // how it looks.
+
+ // This class is the configuration for the state. It holds the values (in this
+ // case the title) provided by the parent (in this case the App widget) and
+ // used by the build method of the State. Fields in a Widget subclass are
+ // always marked "final".
+
+ final String title;
+
+ @override
+ State createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State {
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ // This method is rerun every time setState is called, for instance as done
+ // by the _incrementCounter method above.
+ //
+ // The Flutter framework has been optimized to make rerunning build methods
+ // fast, so that you can just rebuild anything that needs updating rather
+ // than having to individually change instances of widgets.
+ return Scaffold(
+ appBar: AppBar(
+ // TRY THIS: Try changing the color here to a specific color (to
+ // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
+ // change color while the other colors stay the same.
+ backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+ // Here we take the value from the MyHomePage object that was created by
+ // the App.build method, and use it to set our appbar title.
+ title: Text(widget.title),
+ ),
+ body: Center(
+ // Center is a layout widget. It takes a single child and positions it
+ // in the middle of the parent.
+ child: Column(
+ // Column is also a layout widget. It takes a list of children and
+ // arranges them vertically. By default, it sizes itself to fit its
+ // children horizontally, and tries to be as tall as its parent.
+ //
+ // Column has various properties to control how it sizes itself and
+ // how it positions its children. Here we use mainAxisAlignment to
+ // center the children vertically; the main axis here is the vertical
+ // axis because Columns are vertical (the cross axis would be
+ // horizontal).
+ //
+ // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
+ // action in the IDE, or press "p" in the console), to see the
+ // wireframe for each widget.
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Center(
+ child: Text(
+ "Open the Firebase Data Connect Extension and click 'Start Emulators' to get started."),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/dataconnect/flutter-blank/package.json b/dataconnect/flutter-blank/package.json
new file mode 100644
index 00000000..12b361ac
--- /dev/null
+++ b/dataconnect/flutter-blank/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@firebase/dart-sample",
+ "scripts": {
+ "start:proxy": "node proxy-web/proxy.js"
+ },
+ "devDependencies": {
+ "express": "^4.19.2",
+ "http-proxy-middleware": "^3.0.0"
+ }
+}
diff --git a/dataconnect/flutter-blank/pnpm-lock.yaml b/dataconnect/flutter-blank/pnpm-lock.yaml
new file mode 100644
index 00000000..5eb3e376
--- /dev/null
+++ b/dataconnect/flutter-blank/pnpm-lock.yaml
@@ -0,0 +1,697 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ devDependencies:
+ express:
+ specifier: ^4.19.2
+ version: 4.21.0
+ http-proxy-middleware:
+ specifier: ^3.0.0
+ version: 3.0.2
+
+packages:
+
+ '@types/http-proxy@1.17.15':
+ resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==}
+
+ '@types/node@22.7.4':
+ resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==}
+
+ accepts@1.3.8:
+ resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+ engines: {node: '>= 0.6'}
+
+ array-flatten@1.1.1:
+ resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
+
+ body-parser@1.20.3:
+ resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
+ call-bind@1.0.7:
+ resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+ engines: {node: '>= 0.4'}
+
+ content-disposition@0.5.4:
+ resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+ engines: {node: '>= 0.6'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
+ cookie-signature@1.0.6:
+ resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+
+ cookie@0.6.0:
+ resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
+ engines: {node: '>= 0.6'}
+
+ debug@2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.3.7:
+ resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
+ destroy@1.2.0:
+ resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
+ engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
+
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
+ encodeurl@1.0.2:
+ resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
+ engines: {node: '>= 0.8'}
+
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
+ es-define-property@1.0.0:
+ resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
+ eventemitter3@4.0.7:
+ resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+
+ express@4.21.0:
+ resolution: {integrity: sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==}
+ engines: {node: '>= 0.10.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ finalhandler@1.3.1:
+ resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}
+ engines: {node: '>= 0.8'}
+
+ follow-redirects@1.15.9:
+ resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@0.5.2:
+ resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
+ engines: {node: '>= 0.6'}
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ get-intrinsic@1.2.4:
+ resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+ engines: {node: '>= 0.4'}
+
+ gopd@1.0.1:
+ resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
+ has-proto@1.0.3:
+ resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+ engines: {node: '>= 0.4'}
+
+ has-symbols@1.0.3:
+ resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
+ http-proxy-middleware@3.0.2:
+ resolution: {integrity: sha512-fBLFpmvDzlxdckwZRjM0wWtwDZ4KBtQ8NFqhrFKoEtK4myzuiumBuNTxD+F4cVbXfOZljIbrynmvByofDzT7Ag==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ http-proxy@1.18.1:
+ resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
+ engines: {node: '>=8.0.0'}
+
+ iconv-lite@0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-plain-object@5.0.0:
+ resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+ engines: {node: '>=0.10.0'}
+
+ media-typer@0.3.0:
+ resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
+ engines: {node: '>= 0.6'}
+
+ merge-descriptors@1.0.3:
+ resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}
+
+ methods@1.1.2:
+ resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
+ engines: {node: '>= 0.6'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ ms@2.0.0:
+ resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ negotiator@0.6.3:
+ resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+ engines: {node: '>= 0.6'}
+
+ object-inspect@1.13.2:
+ resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==}
+ engines: {node: '>= 0.4'}
+
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
+ path-to-regexp@0.1.10:
+ resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
+ qs@6.13.0:
+ resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
+ engines: {node: '>=0.6'}
+
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@2.5.2:
+ resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
+ engines: {node: '>= 0.8'}
+
+ requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ send@0.19.0:
+ resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}
+ engines: {node: '>= 0.8.0'}
+
+ serve-static@1.16.2:
+ resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}
+ engines: {node: '>= 0.8.0'}
+
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+ side-channel@1.0.6:
+ resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
+ engines: {node: '>= 0.4'}
+
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
+ type-is@1.6.18:
+ resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+ engines: {node: '>= 0.6'}
+
+ undici-types@6.19.8:
+ resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
+
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
+ utils-merge@1.0.1:
+ resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
+ engines: {node: '>= 0.4.0'}
+
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
+snapshots:
+
+ '@types/http-proxy@1.17.15':
+ dependencies:
+ '@types/node': 22.7.4
+
+ '@types/node@22.7.4':
+ dependencies:
+ undici-types: 6.19.8
+
+ accepts@1.3.8:
+ dependencies:
+ mime-types: 2.1.35
+ negotiator: 0.6.3
+
+ array-flatten@1.1.1: {}
+
+ body-parser@1.20.3:
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ on-finished: 2.4.1
+ qs: 6.13.0
+ raw-body: 2.5.2
+ type-is: 1.6.18
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ bytes@3.1.2: {}
+
+ call-bind@1.0.7:
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ set-function-length: 1.2.2
+
+ content-disposition@0.5.4:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ content-type@1.0.5: {}
+
+ cookie-signature@1.0.6: {}
+
+ cookie@0.6.0: {}
+
+ debug@2.6.9:
+ dependencies:
+ ms: 2.0.0
+
+ debug@4.3.7:
+ dependencies:
+ ms: 2.1.3
+
+ define-data-property@1.1.4:
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ gopd: 1.0.1
+
+ depd@2.0.0: {}
+
+ destroy@1.2.0: {}
+
+ ee-first@1.1.1: {}
+
+ encodeurl@1.0.2: {}
+
+ encodeurl@2.0.0: {}
+
+ es-define-property@1.0.0:
+ dependencies:
+ get-intrinsic: 1.2.4
+
+ es-errors@1.3.0: {}
+
+ escape-html@1.0.3: {}
+
+ etag@1.8.1: {}
+
+ eventemitter3@4.0.7: {}
+
+ express@4.21.0:
+ dependencies:
+ accepts: 1.3.8
+ array-flatten: 1.1.1
+ body-parser: 1.20.3
+ content-disposition: 0.5.4
+ content-type: 1.0.5
+ cookie: 0.6.0
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 2.0.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 1.3.1
+ fresh: 0.5.2
+ http-errors: 2.0.0
+ merge-descriptors: 1.0.3
+ methods: 1.1.2
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ path-to-regexp: 0.1.10
+ proxy-addr: 2.0.7
+ qs: 6.13.0
+ range-parser: 1.2.1
+ safe-buffer: 5.2.1
+ send: 0.19.0
+ serve-static: 1.16.2
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ type-is: 1.6.18
+ utils-merge: 1.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ finalhandler@1.3.1:
+ dependencies:
+ debug: 2.6.9
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.1
+ unpipe: 1.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ follow-redirects@1.15.9(debug@4.3.7):
+ optionalDependencies:
+ debug: 4.3.7
+
+ forwarded@0.2.0: {}
+
+ fresh@0.5.2: {}
+
+ function-bind@1.1.2: {}
+
+ get-intrinsic@1.2.4:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ has-proto: 1.0.3
+ has-symbols: 1.0.3
+ hasown: 2.0.2
+
+ gopd@1.0.1:
+ dependencies:
+ get-intrinsic: 1.2.4
+
+ has-property-descriptors@1.0.2:
+ dependencies:
+ es-define-property: 1.0.0
+
+ has-proto@1.0.3: {}
+
+ has-symbols@1.0.3: {}
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ http-errors@2.0.0:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+
+ http-proxy-middleware@3.0.2:
+ dependencies:
+ '@types/http-proxy': 1.17.15
+ debug: 4.3.7
+ http-proxy: 1.18.1(debug@4.3.7)
+ is-glob: 4.0.3
+ is-plain-object: 5.0.0
+ micromatch: 4.0.8
+ transitivePeerDependencies:
+ - supports-color
+
+ http-proxy@1.18.1(debug@4.3.7):
+ dependencies:
+ eventemitter3: 4.0.7
+ follow-redirects: 1.15.9(debug@4.3.7)
+ requires-port: 1.0.0
+ transitivePeerDependencies:
+ - debug
+
+ iconv-lite@0.4.24:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ inherits@2.0.4: {}
+
+ ipaddr.js@1.9.1: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ is-plain-object@5.0.0: {}
+
+ media-typer@0.3.0: {}
+
+ merge-descriptors@1.0.3: {}
+
+ methods@1.1.2: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ mime-db@1.52.0: {}
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
+ mime@1.6.0: {}
+
+ ms@2.0.0: {}
+
+ ms@2.1.3: {}
+
+ negotiator@0.6.3: {}
+
+ object-inspect@1.13.2: {}
+
+ on-finished@2.4.1:
+ dependencies:
+ ee-first: 1.1.1
+
+ parseurl@1.3.3: {}
+
+ path-to-regexp@0.1.10: {}
+
+ picomatch@2.3.1: {}
+
+ proxy-addr@2.0.7:
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+
+ qs@6.13.0:
+ dependencies:
+ side-channel: 1.0.6
+
+ range-parser@1.2.1: {}
+
+ raw-body@2.5.2:
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.0
+ iconv-lite: 0.4.24
+ unpipe: 1.0.0
+
+ requires-port@1.0.0: {}
+
+ safe-buffer@5.2.1: {}
+
+ safer-buffer@2.1.2: {}
+
+ send@0.19.0:
+ dependencies:
+ debug: 2.6.9
+ depd: 2.0.0
+ destroy: 1.2.0
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 0.5.2
+ http-errors: 2.0.0
+ mime: 1.6.0
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
+ serve-static@1.16.2:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 0.19.0
+ transitivePeerDependencies:
+ - supports-color
+
+ set-function-length@1.2.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+
+ setprototypeof@1.2.0: {}
+
+ side-channel@1.0.6:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ object-inspect: 1.13.2
+
+ statuses@2.0.1: {}
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ toidentifier@1.0.1: {}
+
+ type-is@1.6.18:
+ dependencies:
+ media-typer: 0.3.0
+ mime-types: 2.1.35
+
+ undici-types@6.19.8: {}
+
+ unpipe@1.0.0: {}
+
+ utils-merge@1.0.1: {}
+
+ vary@1.1.2: {}
diff --git a/dataconnect/flutter-blank/proxy-web/package-lock.json b/dataconnect/flutter-blank/proxy-web/package-lock.json
new file mode 100644
index 00000000..75c8f2a2
--- /dev/null
+++ b/dataconnect/flutter-blank/proxy-web/package-lock.json
@@ -0,0 +1,1131 @@
+{
+ "name": "proxy-web",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "express": "^4.19.2",
+ "http-proxy-middleware": "^3.0.0",
+ "nodemon": "^3.1.4"
+ }
+ },
+ "node_modules/@types/http-proxy": {
+ "version": "1.17.15",
+ "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz",
+ "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.5.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz",
+ "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==",
+ "dependencies": {
+ "undici-types": "~6.19.2"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
+ "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ },
+ "node_modules/express": {
+ "version": "4.19.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
+ "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.2",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.6.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/http-proxy-middleware": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.0.tgz",
+ "integrity": "sha512-36AV1fIaI2cWRzHo+rbcxhe3M3jUDCNzc4D5zRl57sEWRAxdXYtw7FSQKYY6PDKssiAKjLYypbssHk+xs/kMXw==",
+ "dependencies": {
+ "@types/http-proxy": "^1.17.10",
+ "debug": "^4.3.4",
+ "http-proxy": "^1.18.1",
+ "is-glob": "^4.0.1",
+ "is-plain-obj": "^3.0.0",
+ "micromatch": "^4.0.5"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/http-proxy-middleware/node_modules/debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/http-proxy-middleware/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
+ "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
+ "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nodemon": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz",
+ "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/node_modules/debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nodemon/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="
+ },
+ "node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
+ },
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ }
+ }
+}
diff --git a/dataconnect/flutter-blank/proxy-web/proxy.js b/dataconnect/flutter-blank/proxy-web/proxy.js
new file mode 100644
index 00000000..4ec6a4db
--- /dev/null
+++ b/dataconnect/flutter-blank/proxy-web/proxy.js
@@ -0,0 +1,30 @@
+const express = require("express");
+const { createProxyMiddleware } = require("http-proxy-middleware");
+
+const EXT_PORT = 9002;
+const FLUTTER_PORT = 9003;
+const DATACONNECT_PORT = 9400;
+const app = express();
+
+app.use(
+ createProxyMiddleware({
+ target: `http://localhost:${FLUTTER_PORT}`,
+ router: {
+ [`/v1beta`]: `http://localhost:${DATACONNECT_PORT}`, // API on 8081 should support /api/* paths
+ },
+ })
+);
+
+app.listen(EXT_PORT, () => {
+ console.log(`
+ ====Firebase Data Connect Proxy Server========
+ ====Please DO NOT CLOSE=======================
+ `);
+ console.log(
+ "Proxy Server Listening on: " +
+ EXT_PORT
+ );
+ console.log(`
+ ==============================================
+ `);
+});
\ No newline at end of file
diff --git a/dataconnect/flutter-blank/pubspec.lock b/dataconnect/flutter-blank/pubspec.lock
new file mode 100644
index 00000000..9196d529
--- /dev/null
+++ b/dataconnect/flutter-blank/pubspec.lock
@@ -0,0 +1,434 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+ _flutterfire_internals:
+ dependency: transitive
+ description:
+ name: _flutterfire_internals
+ sha256: "5534e701a2c505fed1f0799e652dd6ae23bd4d2c4cf797220e5ced5764a7c1c2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.44"
+ archive:
+ dependency: transitive
+ description:
+ name: archive
+ sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.6.1"
+ args:
+ dependency: transitive
+ description:
+ name: args
+ sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.0"
+ async:
+ dependency: transitive
+ description:
+ name: async
+ sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.11.0"
+ boolean_selector:
+ dependency: transitive
+ description:
+ name: boolean_selector
+ sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.0"
+ clock:
+ dependency: transitive
+ description:
+ name: clock
+ sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ collection:
+ dependency: transitive
+ description:
+ name: collection
+ sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.18.0"
+ crypto:
+ dependency: transitive
+ description:
+ name: crypto
+ sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.5"
+ cupertino_icons:
+ dependency: "direct main"
+ description:
+ name: cupertino_icons
+ sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.8"
+ fake_async:
+ dependency: transitive
+ description:
+ name: fake_async
+ sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.1"
+ firebase_app_check:
+ dependency: transitive
+ description:
+ name: firebase_app_check
+ sha256: b5b3c1df2698d6b6bd183f27fb10fbf61f9a0a564d8ccba3d87d0e0760a9ffea
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.1+4"
+ firebase_app_check_platform_interface:
+ dependency: transitive
+ description:
+ name: firebase_app_check_platform_interface
+ sha256: "8dbb826d99c67512212331331461ee142e46645740f1c1209706ca2f72958e57"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.0+38"
+ firebase_app_check_web:
+ dependency: transitive
+ description:
+ name: firebase_app_check_web
+ sha256: d9cf8d7e7eb904399784ecdc21ac66119ff2a93181bd7a3f8ab43e8220ad0be8
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.0"
+ firebase_auth:
+ dependency: transitive
+ description:
+ name: firebase_auth
+ sha256: d453acec0d958ba0e25d41a9901b32cb77d1535766903dea7a61b2788c304596
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.3.1"
+ firebase_auth_platform_interface:
+ dependency: transitive
+ description:
+ name: firebase_auth_platform_interface
+ sha256: "78966c2ef774f5bf2a8381a307222867e9ece3509110500f7a138c115926aa65"
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.4.7"
+ firebase_auth_web:
+ dependency: transitive
+ description:
+ name: firebase_auth_web
+ sha256: "77ad3b252badedd3f08dfa21a4c7fe244be96c6da3a4067f253b13ea5d32424c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.13.2"
+ firebase_core:
+ dependency: "direct main"
+ description:
+ name: firebase_core
+ sha256: "51dfe2fbf3a984787a2e7b8592f2f05c986bfedd6fdacea3f9e0a7beb334de96"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.6.0"
+ firebase_core_platform_interface:
+ dependency: transitive
+ description:
+ name: firebase_core_platform_interface
+ sha256: e30da58198a6d4b49d5bce4e852f985c32cb10db329ebef9473db2b9f09ce810
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.3.0"
+ firebase_core_web:
+ dependency: transitive
+ description:
+ name: firebase_core_web
+ sha256: f967a7138f5d2ffb1ce15950e2a382924239eaa521150a8f144af34e68b3b3e5
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.18.1"
+ firebase_data_connect:
+ dependency: "direct main"
+ description:
+ name: firebase_data_connect
+ sha256: "0893243bf24fbb7ae82a53b751a85e8fa6c5096ddff380eccb0c1efa11029f5c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.2+1"
+ fixnum:
+ dependency: transitive
+ description:
+ name: fixnum
+ sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
+ flutter:
+ dependency: "direct main"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_dotenv:
+ dependency: "direct main"
+ description:
+ name: flutter_dotenv
+ sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.1.0"
+ flutter_lints:
+ dependency: "direct dev"
+ description:
+ name: flutter_lints
+ sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.0"
+ flutter_test:
+ dependency: "direct dev"
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ flutter_web_plugins:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
+ google_identity_services_web:
+ dependency: transitive
+ description:
+ name: google_identity_services_web
+ sha256: "5be191523702ba8d7a01ca97c17fca096822ccf246b0a9f11923a6ded06199b6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.1+4"
+ googleapis_auth:
+ dependency: transitive
+ description:
+ name: googleapis_auth
+ sha256: befd71383a955535060acde8792e7efc11d2fccd03dd1d3ec434e85b68775938
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.6.0"
+ grpc:
+ dependency: transitive
+ description:
+ name: grpc
+ sha256: e93ee3bce45c134bf44e9728119102358c7cd69de7832d9a874e2e74eb8cab40
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.4"
+ http:
+ dependency: transitive
+ description:
+ name: http
+ sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.2"
+ http2:
+ dependency: transitive
+ description:
+ name: http2
+ sha256: "9ced024a160b77aba8fb8674e38f70875e321d319e6f303ec18e87bd5a4b0c1d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.0"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.2"
+ intl:
+ dependency: transitive
+ description:
+ name: intl
+ sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.19.0"
+ leak_tracker:
+ dependency: transitive
+ description:
+ name: leak_tracker
+ sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
+ url: "https://pub.dev"
+ source: hosted
+ version: "10.0.5"
+ leak_tracker_flutter_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_flutter_testing
+ sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.5"
+ leak_tracker_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_testing
+ sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.1"
+ lints:
+ dependency: transitive
+ description:
+ name: lints
+ sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.0"
+ matcher:
+ dependency: transitive
+ description:
+ name: matcher
+ sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.12.16+1"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.11.1"
+ meta:
+ dependency: transitive
+ description:
+ name: meta
+ sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.15.0"
+ path:
+ dependency: transitive
+ description:
+ name: path
+ sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.0"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.8"
+ protobuf:
+ dependency: transitive
+ description:
+ name: protobuf
+ sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.1.0"
+ sky_engine:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.99"
+ source_span:
+ dependency: transitive
+ description:
+ name: source_span
+ sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.10.0"
+ stack_trace:
+ dependency: transitive
+ description:
+ name: stack_trace
+ sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.11.1"
+ stream_channel:
+ dependency: transitive
+ description:
+ name: stream_channel
+ sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.2"
+ string_scanner:
+ dependency: transitive
+ description:
+ name: string_scanner
+ sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.0"
+ term_glyph:
+ dependency: transitive
+ description:
+ name: term_glyph
+ sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ test_api:
+ dependency: transitive
+ description:
+ name: test_api
+ sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.7.2"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.2"
+ vector_math:
+ dependency: transitive
+ description:
+ name: vector_math
+ sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "14.2.5"
+ web:
+ dependency: transitive
+ description:
+ name: web
+ sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
+sdks:
+ dart: ">=3.4.0 <4.0.0"
+ flutter: ">=3.22.0"
diff --git a/dataconnect/flutter-blank/pubspec.yaml b/dataconnect/flutter-blank/pubspec.yaml
new file mode 100644
index 00000000..3c610369
--- /dev/null
+++ b/dataconnect/flutter-blank/pubspec.yaml
@@ -0,0 +1,94 @@
+name: blank
+description: "A new Flutter project."
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+# In Windows, build-name is used as the major, minor, and patch parts
+# of the product and file versions while build-number is used as the build suffix.
+version: 1.0.0+1
+
+environment:
+ sdk: ^3.4.0
+
+# Dependencies specify other packages that you*r package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+ flutter:
+ sdk: flutter
+
+
+ # The following adds the Cupertino Icons font to your application.
+ # Use with the CupertinoIcons class for iOS style icons.
+ cupertino_icons: ^1.0.8
+ firebase_core: ^3.3.0
+ firebase_data_connect: ^0.1.2
+ flutter_dotenv: ^5.1.0
+
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+
+ # The "flutter_lints" package below contains a set of recommended lints to
+ # encourage good coding practices. The lint set provided by the package is
+ # activated in the `analysis_options.yaml` file located at the root of your
+ # package. See that file for information about deactivating specific lint
+ # rules and activating additional ones.
+ flutter_lints: ^4.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+ # The following line ensures that the Material Icons font is
+ # included with your application, so that you can use the icons in
+ # the material Icons class.
+ uses-material-design: true
+
+ # To add assets to your application, add an assets section, like this:
+ assets:
+ - .env
+ # - images/a_dot_burr.jpeg
+ # - images/a_dot_ham.jpeg
+
+ # An image asset can refer to one or more resolution-specific "variants", see
+ # https://flutter.dev/to/resolution-aware-images
+
+ # For details regarding adding assets from package dependencies, see
+ # https://flutter.dev/to/asset-from-package
+
+ # To add custom fonts to your application, add a fonts section here,
+ # in this "flutter" section. Each entry in this list should have a
+ # "family" key with the font family name, and a "fonts" key with a
+ # list giving the asset and other descriptors for the font. For
+ # example:
+ # fonts:
+ # - family: Schyler
+ # fonts:
+ # - asset: fonts/Schyler-Regular.ttf
+ # - asset: fonts/Schyler-Italic.ttf
+ # style: italic
+ # - family: Trajan Pro
+ # fonts:
+ # - asset: fonts/TrajanPro.ttf
+ # - asset: fonts/TrajanPro_Bold.ttf
+ # weight: 700
+ #
+ # For details regarding fonts from package dependencies,
+ # see https://flutter.dev/to/font-from-package
diff --git a/dataconnect/flutter-blank/startProxy.sh b/dataconnect/flutter-blank/startProxy.sh
new file mode 100755
index 00000000..a41cc714
--- /dev/null
+++ b/dataconnect/flutter-blank/startProxy.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+fail() {
+ echo "Unable to log in. Please re-run ./installDeps.sh to configure Flutter for your workstation."
+ exit 1
+}
+pnpm install 2>&1 | tee install.txt
+pnpm run start:proxy 2>&1 | tee start_proxy.txt
diff --git a/dataconnect/flutter-blank/test/widget_test.dart b/dataconnect/flutter-blank/test/widget_test.dart
new file mode 100644
index 00000000..c96ea8a4
--- /dev/null
+++ b/dataconnect/flutter-blank/test/widget_test.dart
@@ -0,0 +1,30 @@
+// This is a basic Flutter widget test.
+//
+// To perform an interaction with a widget in your test, use the WidgetTester
+// utility in the flutter_test package. For example, you can send tap and scroll
+// gestures. You can also use WidgetTester to find child widgets in the widget
+// tree, read text, and verify that the values of widget properties are correct.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:blank/main.dart';
+
+void main() {
+ testWidgets('Counter increments smoke test', (WidgetTester tester) async {
+ // Build our app and trigger a frame.
+ await tester.pumpWidget(const MyApp());
+
+ // Verify that our counter starts at 0.
+ expect(find.text('0'), findsOneWidget);
+ expect(find.text('1'), findsNothing);
+
+ // Tap the '+' icon and trigger a frame.
+ await tester.tap(find.byIcon(Icons.add));
+ await tester.pump();
+
+ // Verify that our counter has incremented.
+ expect(find.text('0'), findsNothing);
+ expect(find.text('1'), findsOneWidget);
+ });
+}
diff --git a/dataconnect/flutter-blank/web/favicon.png b/dataconnect/flutter-blank/web/favicon.png
new file mode 100644
index 00000000..8aaa46ac
Binary files /dev/null and b/dataconnect/flutter-blank/web/favicon.png differ
diff --git a/dataconnect/flutter-blank/web/icons/Icon-192.png b/dataconnect/flutter-blank/web/icons/Icon-192.png
new file mode 100644
index 00000000..b749bfef
Binary files /dev/null and b/dataconnect/flutter-blank/web/icons/Icon-192.png differ
diff --git a/dataconnect/flutter-blank/web/icons/Icon-512.png b/dataconnect/flutter-blank/web/icons/Icon-512.png
new file mode 100644
index 00000000..88cfd48d
Binary files /dev/null and b/dataconnect/flutter-blank/web/icons/Icon-512.png differ
diff --git a/dataconnect/flutter-blank/web/icons/Icon-maskable-192.png b/dataconnect/flutter-blank/web/icons/Icon-maskable-192.png
new file mode 100644
index 00000000..eb9b4d76
Binary files /dev/null and b/dataconnect/flutter-blank/web/icons/Icon-maskable-192.png differ
diff --git a/dataconnect/flutter-blank/web/icons/Icon-maskable-512.png b/dataconnect/flutter-blank/web/icons/Icon-maskable-512.png
new file mode 100644
index 00000000..d69c5669
Binary files /dev/null and b/dataconnect/flutter-blank/web/icons/Icon-maskable-512.png differ
diff --git a/dataconnect/flutter-blank/web/index.html b/dataconnect/flutter-blank/web/index.html
new file mode 100644
index 00000000..c065fd27
--- /dev/null
+++ b/dataconnect/flutter-blank/web/index.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ blank
+
+
+
+
+
+
diff --git a/dataconnect/flutter-blank/web/manifest.json b/dataconnect/flutter-blank/web/manifest.json
new file mode 100644
index 00000000..00e3a5bb
--- /dev/null
+++ b/dataconnect/flutter-blank/web/manifest.json
@@ -0,0 +1,35 @@
+{
+ "name": "blank",
+ "short_name": "blank",
+ "start_url": ".",
+ "display": "standalone",
+ "background_color": "#0175C2",
+ "theme_color": "#0175C2",
+ "description": "A new Flutter project.",
+ "orientation": "portrait-primary",
+ "prefer_related_applications": false,
+ "icons": [
+ {
+ "src": "icons/Icon-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "icons/Icon-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ },
+ {
+ "src": "icons/Icon-maskable-192.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "maskable"
+ },
+ {
+ "src": "icons/Icon-maskable-512.png",
+ "sizes": "512x512",
+ "type": "image/png",
+ "purpose": "maskable"
+ }
+ ]
+}
diff --git a/dataconnect/flutter-movie/.firebase/.graphqlrc b/dataconnect/flutter-movie/.firebase/.graphqlrc
new file mode 100644
index 00000000..51bf7fd7
--- /dev/null
+++ b/dataconnect/flutter-movie/.firebase/.graphqlrc
@@ -0,0 +1 @@
+{"schema":["../dataconnect/schema/**/*.gql","../dataconnect/.dataconnect/**/*.gql"],"document":["../dataconnect/connector/**/*.gql"]}
\ No newline at end of file
diff --git a/dataconnect/flutter-movie/.firebaserc b/dataconnect/flutter-movie/.firebaserc
new file mode 100644
index 00000000..6b2c9934
--- /dev/null
+++ b/dataconnect/flutter-movie/.firebaserc
@@ -0,0 +1,5 @@
+{
+ "projects": {
+ "default": null
+ }
+}
diff --git a/dataconnect/flutter-movie/.gitignore b/dataconnect/flutter-movie/.gitignore
new file mode 100644
index 00000000..5b1e3843
--- /dev/null
+++ b/dataconnect/flutter-movie/.gitignore
@@ -0,0 +1,45 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
+
+/lib/firebase_options.dart
diff --git a/dataconnect/flutter-movie/.metadata b/dataconnect/flutter-movie/.metadata
new file mode 100644
index 00000000..c2aa44bd
--- /dev/null
+++ b/dataconnect/flutter-movie/.metadata
@@ -0,0 +1,45 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "603104015dd692ea3403755b55d07813d5cf8965"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ base_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ - platform: android
+ create_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ base_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ - platform: ios
+ create_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ base_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ - platform: linux
+ create_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ base_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ - platform: macos
+ create_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ base_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ - platform: web
+ create_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ base_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ - platform: windows
+ create_revision: 603104015dd692ea3403755b55d07813d5cf8965
+ base_revision: 603104015dd692ea3403755b55d07813d5cf8965
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/dataconnect/flutter-movie/.vscode/launch.json b/dataconnect/flutter-movie/.vscode/launch.json
new file mode 100644
index 00000000..ff72c193
--- /dev/null
+++ b/dataconnect/flutter-movie/.vscode/launch.json
@@ -0,0 +1,25 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "dataconnect",
+ "request": "launch",
+ "type": "dart"
+ },
+ {
+ "name": "dataconnect (profile mode)",
+ "request": "launch",
+ "type": "dart",
+ "flutterMode": "profile"
+ },
+ {
+ "name": "dataconnect (release mode)",
+ "request": "launch",
+ "type": "dart",
+ "flutterMode": "release"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/dataconnect/flutter-movie/README.md b/dataconnect/flutter-movie/README.md
new file mode 100644
index 00000000..94315621
--- /dev/null
+++ b/dataconnect/flutter-movie/README.md
@@ -0,0 +1,48 @@
+# Firebase Data Connect Quickstart
+
+## Introduction
+
+This quickstart is a movie review app to demonstrate the use of Firebase Data Connect with a Cloud SQL database. For more information about Firebase Data Connect visit [the docs](https://firebase.google.com/docs/data-connect/).
+
+
+## Getting Started
+
+Follow these steps to get up and running with Firebase Data Connect. For more detailed instructions, check out the [official documentation](https://firebase.google.com/docs/data-connect/quickstart).
+
+### 1. Connect to your Firebase project
+
+1. If you haven't already, create a Firebase project.
+ 1. In the [Firebase console](https://console.firebase.google.com), click
+ **Add project**, then follow the on-screen instructions.
+2. Enable Email/Password Sign-in method [here](https://console.firebase.google.com/project/_/authentication/providers).
+
+### 2. Cloning the repository
+
+1. Clone this repository to your local machine:
+ ```sh
+ git clone https://github.com/firebase/quickstart-flutter.git
+ ```
+2. Configure flutterfire
+This will automatically download and set up firebase for your project:
+```sh
+flutterfire configure -y -a com.example.dataconnect
+```
+
+
+### 3. Open in Visual Studio Code (VS Code)
+
+1. Click on the Firebase Data Connect icon on the VS Code sidebar to load the Extension.
+ a. Sign in with your Google Account if you haven't already.
+2. Click on "Connect a Firebase project" and choose the project where you have set up Data Connect.
+3. Click on "Start Emulators" - this should generate the Kotlin SDK for you and start the emulators.
+
+### 4. Populate the database
+In VS Code, open the `quickstart-flutter/dataconnect/dataconnect/moviedata_insert.gql` file and click the
+ `Run (local)` button at the top of the file.
+
+If you’d like to confirm that the data was correctly inserted,
+open `quickstart-flutter/dataconnect/movie-connector/queries.gql` and run the `ListMovies` query.
+
+### 5. Running the app
+
+Press the Run button in VS Code to run the sample app on your device.
diff --git a/dataconnect/flutter-movie/analysis_options.yaml b/dataconnect/flutter-movie/analysis_options.yaml
new file mode 100644
index 00000000..86cb8820
--- /dev/null
+++ b/dataconnect/flutter-movie/analysis_options.yaml
@@ -0,0 +1,31 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+analyzer:
+ exclude:
+ - lib/movies_connector/**
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/dataconnect/flutter-movie/android/.gitignore b/dataconnect/flutter-movie/android/.gitignore
new file mode 100644
index 00000000..55afd919
--- /dev/null
+++ b/dataconnect/flutter-movie/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/to/reference-keystore
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/dataconnect/flutter-movie/android/app/build.gradle b/dataconnect/flutter-movie/android/app/build.gradle
new file mode 100644
index 00000000..49cc888e
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/build.gradle
@@ -0,0 +1,47 @@
+plugins {
+ id "com.android.application"
+ // START: FlutterFire Configuration
+ id 'com.google.gms.google-services'
+ // END: FlutterFire Configuration
+ id "kotlin-android"
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+android {
+ namespace = "com.example.dataconnect"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.example.dataconnect"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
+ minSdk = 23
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/dataconnect/flutter-movie/android/app/google-services.json b/dataconnect/flutter-movie/android/app/google-services.json
new file mode 100644
index 00000000..2a2315fd
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/google-services.json
@@ -0,0 +1,28 @@
+{
+ "project_info": {
+ "project_id": "mockproject-1234",
+ "project_number": "123456789000",
+ "name": "FirebaseQuickstarts",
+ "firebase_url": "https://mockproject-1234.firebaseio.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "123456789000",
+ "client_id": "android:com.example.dataconnect",
+ "client_type": 1,
+ "android_client_info": {
+ "package_name": "com.example.dataconnect",
+ "certificate_hash": []
+ }
+ },
+ "api_key": [
+ {
+ "current_key": "AIzbSzCn1"
+ }
+ ]
+ }
+ ],
+ "client_info": [],
+ "ARTIFACT_VERSION": "1"
+ }
\ No newline at end of file
diff --git a/dataconnect/flutter-movie/android/app/src/debug/AndroidManifest.xml b/dataconnect/flutter-movie/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 00000000..399f6981
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/dataconnect/flutter-movie/android/app/src/main/AndroidManifest.xml b/dataconnect/flutter-movie/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..136e48a8
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/android/app/src/main/kotlin/com/example/dataconnect/MainActivity.kt b/dataconnect/flutter-movie/android/app/src/main/kotlin/com/example/dataconnect/MainActivity.kt
new file mode 100644
index 00000000..e3f53e16
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/main/kotlin/com/example/dataconnect/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.example.dataconnect
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/drawable-v21/launch_background.xml b/dataconnect/flutter-movie/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 00000000..f74085f3
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/drawable/launch_background.xml b/dataconnect/flutter-movie/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 00000000..304732f8
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..db77bb4b
Binary files /dev/null and b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..17987b79
Binary files /dev/null and b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..09d43914
Binary files /dev/null and b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..d5f1c8d3
Binary files /dev/null and b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..4d6372ee
Binary files /dev/null and b/dataconnect/flutter-movie/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/values-night/styles.xml b/dataconnect/flutter-movie/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 00000000..06952be7
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/values/styles.xml b/dataconnect/flutter-movie/android/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..cb1ef880
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/android/app/src/main/res/xml/network_security_config.xml b/dataconnect/flutter-movie/android/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 00000000..17abf3ac
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,6 @@
+
+
+
+ 10.0.2.2
+
+
\ No newline at end of file
diff --git a/dataconnect/flutter-movie/android/app/src/profile/AndroidManifest.xml b/dataconnect/flutter-movie/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 00000000..399f6981
--- /dev/null
+++ b/dataconnect/flutter-movie/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/dataconnect/flutter-movie/android/build.gradle b/dataconnect/flutter-movie/android/build.gradle
new file mode 100644
index 00000000..d2ffbffa
--- /dev/null
+++ b/dataconnect/flutter-movie/android/build.gradle
@@ -0,0 +1,18 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = "../build"
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/dataconnect/flutter-movie/android/gradle.properties b/dataconnect/flutter-movie/android/gradle.properties
new file mode 100644
index 00000000..25971708
--- /dev/null
+++ b/dataconnect/flutter-movie/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/dataconnect/flutter-movie/android/gradle/wrapper/gradle-wrapper.properties b/dataconnect/flutter-movie/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..7bb2df6b
--- /dev/null
+++ b/dataconnect/flutter-movie/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
diff --git a/dataconnect/flutter-movie/android/settings.gradle b/dataconnect/flutter-movie/android/settings.gradle
new file mode 100644
index 00000000..9759a220
--- /dev/null
+++ b/dataconnect/flutter-movie/android/settings.gradle
@@ -0,0 +1,28 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }()
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+ id "com.android.application" version "8.1.0" apply false
+ // START: FlutterFire Configuration
+ id "com.google.gms.google-services" version "4.3.15" apply false
+ // END: FlutterFire Configuration
+ id "org.jetbrains.kotlin.android" version "1.8.22" apply false
+}
+
+include ":app"
diff --git a/dataconnect/flutter-movie/assets/open-in-new-tab.png b/dataconnect/flutter-movie/assets/open-in-new-tab.png
new file mode 100644
index 00000000..b3ab4213
Binary files /dev/null and b/dataconnect/flutter-movie/assets/open-in-new-tab.png differ
diff --git a/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/implicit.gql b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/implicit.gql
new file mode 100644
index 00000000..c7944ef7
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/implicit.gql
@@ -0,0 +1,40 @@
+extend type FavoriteMovie {
+ """
+ ✨ Implicit foreign key field based on `FavoriteMovie`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it.
+ """
+ userId: String! @fdc_generated(from: "FavoriteMovie.user", purpose: IMPLICIT_REF_FIELD)
+ """
+ ✨ Implicit foreign key field based on `FavoriteMovie`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it.
+ """
+ movieId: UUID! @fdc_generated(from: "FavoriteMovie.movie", purpose: IMPLICIT_REF_FIELD)
+}
+extend type MovieActor {
+ """
+ ✨ Implicit foreign key field based on `MovieActor`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it.
+ """
+ movieId: UUID! @fdc_generated(from: "MovieActor.movie", purpose: IMPLICIT_REF_FIELD)
+ """
+ ✨ Implicit foreign key field based on `MovieActor`.`actor`. It must match the value of `Actor`.`id`. See `@ref` for how to customize it.
+ """
+ actorId: UUID! @fdc_generated(from: "MovieActor.actor", purpose: IMPLICIT_REF_FIELD)
+}
+extend type MovieMetadata {
+ """
+ ✨ Implicit primary key field. It's a UUID column default to a generated new value. See `@table` for how to customize it.
+ """
+ id: UUID! @default(expr: "uuidV4()") @fdc_generated(from: "MovieMetadata", purpose: IMPLICIT_KEY_FIELD)
+ """
+ ✨ Implicit foreign key field based on `MovieMetadata`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it.
+ """
+ movieId: UUID! @fdc_generated(from: "MovieMetadata.movie", purpose: IMPLICIT_REF_FIELD)
+}
+extend type Review {
+ """
+ ✨ Implicit foreign key field based on `Review`.`movie`. It must match the value of `Movie`.`id`. See `@ref` for how to customize it.
+ """
+ movieId: UUID! @fdc_generated(from: "Review.movie", purpose: IMPLICIT_REF_FIELD)
+ """
+ ✨ Implicit foreign key field based on `Review`.`user`. It must match the value of `User`.`id`. See `@ref` for how to customize it.
+ """
+ userId: String! @fdc_generated(from: "Review.user", purpose: IMPLICIT_REF_FIELD)
+}
diff --git a/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/input.gql b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/input.gql
new file mode 100644
index 00000000..4ea8e393
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/input.gql
@@ -0,0 +1,1152 @@
+"""
+✨ `Actor_KeyOutput` returns the primary key fields of table type `Actor`.
+
+It has the same format as `Actor_Key`, but is only used as mutation return value.
+"""
+scalar Actor_KeyOutput
+"""
+✨ `FavoriteMovie_KeyOutput` returns the primary key fields of table type `FavoriteMovie`.
+
+It has the same format as `FavoriteMovie_Key`, but is only used as mutation return value.
+"""
+scalar FavoriteMovie_KeyOutput
+"""
+✨ `Movie_KeyOutput` returns the primary key fields of table type `Movie`.
+
+It has the same format as `Movie_Key`, but is only used as mutation return value.
+"""
+scalar Movie_KeyOutput
+"""
+✨ `MovieActor_KeyOutput` returns the primary key fields of table type `MovieActor`.
+
+It has the same format as `MovieActor_Key`, but is only used as mutation return value.
+"""
+scalar MovieActor_KeyOutput
+"""
+✨ `MovieMetadata_KeyOutput` returns the primary key fields of table type `MovieMetadata`.
+
+It has the same format as `MovieMetadata_Key`, but is only used as mutation return value.
+"""
+scalar MovieMetadata_KeyOutput
+"""
+✨ `Review_KeyOutput` returns the primary key fields of table type `Review`.
+
+It has the same format as `Review_Key`, but is only used as mutation return value.
+"""
+scalar Review_KeyOutput
+"""
+✨ `User_KeyOutput` returns the primary key fields of table type `User`.
+
+It has the same format as `User_Key`, but is only used as mutation return value.
+"""
+scalar User_KeyOutput
+"""
+✨ Generated data input type for table 'Actor'. It includes all necessary fields for creating or upserting rows into table.
+"""
+input Actor_Data {
+ """
+ ✨ Generated from Field `Actor`.`id` of type `UUID!`
+ """
+ id: UUID
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `Actor`.`id` of type `UUID!`)
+ """
+ id_expr: UUID_Expr
+ """
+ ✨ Generated from Field `Actor`.`imageUrl` of type `String!`
+ """
+ imageUrl: String
+ """
+ ✨ `_expr` server value variant of `imageUrl` (✨ Generated from Field `Actor`.`imageUrl` of type `String!`)
+ """
+ imageUrl_expr: String_Expr
+ """
+ ✨ Generated from Field `Actor`.`name` of type `String!`
+ """
+ name: String
+ """
+ ✨ `_expr` server value variant of `name` (✨ Generated from Field `Actor`.`name` of type `String!`)
+ """
+ name_expr: String_Expr
+}
+"""
+✨ Generated filter input type for table 'Actor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input Actor_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [Actor_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: Actor_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [Actor_Filter!]
+ """
+ ✨ Generated from Field `Actor`.`id` of type `UUID!`
+ """
+ id: UUID_Filter
+ """
+ ✨ Generated from Field `Actor`.`imageUrl` of type `String!`
+ """
+ imageUrl: String_Filter
+ """
+ ✨ Generated from Field `Actor`.`name` of type `String!`
+ """
+ name: String_Filter
+ """
+ ✨ Generated from Field `Actor`.`movieActors_on_actor` of type `[MovieActor!]!`
+ """
+ movieActors_on_actor: MovieActor_ListFilter
+ """
+ ✨ Generated from Field `Actor`.`movies_via_MovieActor` of type `[Movie!]!`
+ """
+ movies_via_MovieActor: Movie_ListFilter
+}
+"""
+✨ Generated first-row input type for table 'Actor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input Actor_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [Actor_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: Actor_Filter
+}
+"""
+✨ Generated key input type for table 'Actor'. It represents the primary key fields used to uniquely identify a row in the table.
+"""
+input Actor_Key {
+ """
+ ✨ Generated from Field `Actor`.`id` of type `UUID!`
+ """
+ id: UUID
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `Actor`.`id` of type `UUID!`)
+ """
+ id_expr: UUID_Expr
+}
+"""
+✨ Generated list filter input type for table 'Actor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input Actor_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: Actor_Filter
+}
+"""
+✨ Generated order input type for table 'Actor'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input Actor_Order {
+ """
+ ✨ Generated from Field `Actor`.`id` of type `UUID!`
+ """
+ id: OrderDirection
+ """
+ ✨ Generated from Field `Actor`.`imageUrl` of type `String!`
+ """
+ imageUrl: OrderDirection
+ """
+ ✨ Generated from Field `Actor`.`name` of type `String!`
+ """
+ name: OrderDirection
+}
+"""
+✨ Generated data input type for table 'FavoriteMovie'. It includes all necessary fields for creating or upserting rows into table.
+"""
+input FavoriteMovie_Data {
+ """
+ ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`
+ """
+ userId: String
+ """
+ ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`)
+ """
+ userId_expr: String_Expr
+ """
+ ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`
+ """
+ movieId: UUID
+ """
+ ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`)
+ """
+ movieId_expr: UUID_Expr
+ """
+ ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!`
+ """
+ movie: Movie_Key
+ """
+ ✨ Generated from Field `FavoriteMovie`.`user` of type `User!`
+ """
+ user: User_Key
+}
+"""
+✨ Generated filter input type for table 'FavoriteMovie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input FavoriteMovie_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [FavoriteMovie_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: FavoriteMovie_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [FavoriteMovie_Filter!]
+ """
+ ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`
+ """
+ userId: String_Filter
+ """
+ ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`
+ """
+ movieId: UUID_Filter
+ """
+ ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!`
+ """
+ movie: Movie_Filter
+ """
+ ✨ Generated from Field `FavoriteMovie`.`user` of type `User!`
+ """
+ user: User_Filter
+}
+"""
+✨ Generated first-row input type for table 'FavoriteMovie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input FavoriteMovie_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [FavoriteMovie_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: FavoriteMovie_Filter
+}
+"""
+✨ Generated key input type for table 'FavoriteMovie'. It represents the primary key fields used to uniquely identify a row in the table.
+"""
+input FavoriteMovie_Key {
+ """
+ ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`
+ """
+ userId: String
+ """
+ ✨ `_expr` server value variant of `userId` (✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`)
+ """
+ userId_expr: String_Expr
+ """
+ ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`
+ """
+ movieId: UUID
+ """
+ ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`)
+ """
+ movieId_expr: UUID_Expr
+}
+"""
+✨ Generated list filter input type for table 'FavoriteMovie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input FavoriteMovie_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: FavoriteMovie_Filter
+}
+"""
+✨ Generated order input type for table 'FavoriteMovie'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input FavoriteMovie_Order {
+ """
+ ✨ Generated from Field `FavoriteMovie`.`userId` of type `String!`
+ """
+ userId: OrderDirection
+ """
+ ✨ Generated from Field `FavoriteMovie`.`movieId` of type `UUID!`
+ """
+ movieId: OrderDirection
+ """
+ ✨ Generated from Field `FavoriteMovie`.`movie` of type `Movie!`
+ """
+ movie: Movie_Order
+ """
+ ✨ Generated from Field `FavoriteMovie`.`user` of type `User!`
+ """
+ user: User_Order
+}
+"""
+✨ Generated filter input type for table 'Genre'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input Genre_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [Genre_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: Genre_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [Genre_Filter!]
+ """
+ ✨ Generated from Field `Genre`.`genre` of type `String`
+ """
+ genre: String_Filter
+}
+"""
+✨ Generated first-row input type for table 'Genre'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input Genre_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [Genre_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: Genre_Filter
+}
+"""
+✨ Generated list filter input type for table 'Genre'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input Genre_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: Genre_Filter
+}
+"""
+✨ Generated order input type for table 'Genre'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input Genre_Order {
+ """
+ ✨ Generated from Field `Genre`.`genre` of type `String`
+ """
+ genre: OrderDirection
+}
+"""
+✨ Generated data input type for table 'Movie'. It includes all necessary fields for creating or upserting rows into table.
+"""
+input Movie_Data {
+ """
+ ✨ Generated from Field `Movie`.`id` of type `UUID!`
+ """
+ id: UUID
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `Movie`.`id` of type `UUID!`)
+ """
+ id_expr: UUID_Expr
+ """
+ ✨ Generated from Field `Movie`.`description` of type `String`
+ """
+ description: String
+ """
+ ✨ `_expr` server value variant of `description` (✨ Generated from Field `Movie`.`description` of type `String`)
+ """
+ description_expr: String_Expr
+ """
+ ✨ Generated from Field `Movie`.`genre` of type `String`
+ """
+ genre: String
+ """
+ ✨ `_expr` server value variant of `genre` (✨ Generated from Field `Movie`.`genre` of type `String`)
+ """
+ genre_expr: String_Expr
+ """
+ ✨ Generated from Field `Movie`.`imageUrl` of type `String!`
+ """
+ imageUrl: String
+ """
+ ✨ `_expr` server value variant of `imageUrl` (✨ Generated from Field `Movie`.`imageUrl` of type `String!`)
+ """
+ imageUrl_expr: String_Expr
+ """
+ ✨ Generated from Field `Movie`.`rating` of type `Float`
+ """
+ rating: Float
+ """
+ ✨ Generated from Field `Movie`.`releaseYear` of type `Int`
+ """
+ releaseYear: Int
+ """
+ ✨ Generated from Field `Movie`.`tags` of type `[String]`
+ """
+ tags: [String!]
+ """
+ ✨ Generated from Field `Movie`.`title` of type `String!`
+ """
+ title: String
+ """
+ ✨ `_expr` server value variant of `title` (✨ Generated from Field `Movie`.`title` of type `String!`)
+ """
+ title_expr: String_Expr
+}
+"""
+✨ Generated filter input type for table 'Movie'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input Movie_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [Movie_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: Movie_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [Movie_Filter!]
+ """
+ ✨ Generated from Field `Movie`.`id` of type `UUID!`
+ """
+ id: UUID_Filter
+ """
+ ✨ Generated from Field `Movie`.`description` of type `String`
+ """
+ description: String_Filter
+ """
+ ✨ Generated from Field `Movie`.`genre` of type `String`
+ """
+ genre: String_Filter
+ """
+ ✨ Generated from Field `Movie`.`imageUrl` of type `String!`
+ """
+ imageUrl: String_Filter
+ """
+ ✨ Generated from Field `Movie`.`rating` of type `Float`
+ """
+ rating: Float_Filter
+ """
+ ✨ Generated from Field `Movie`.`releaseYear` of type `Int`
+ """
+ releaseYear: Int_Filter
+ """
+ ✨ Generated from Field `Movie`.`tags` of type `[String]`
+ """
+ tags: String_ListFilter
+ """
+ ✨ Generated from Field `Movie`.`title` of type `String!`
+ """
+ title: String_Filter
+ """
+ ✨ Generated from Field `Movie`.`favorite_movies_on_movie` of type `[FavoriteMovie!]!`
+ """
+ favorite_movies_on_movie: FavoriteMovie_ListFilter
+ """
+ ✨ Generated from Field `Movie`.`movieActors_on_movie` of type `[MovieActor!]!`
+ """
+ movieActors_on_movie: MovieActor_ListFilter
+ """
+ ✨ Generated from Field `Movie`.`movieMetadatas_on_movie` of type `[MovieMetadata!]!`
+ """
+ movieMetadatas_on_movie: MovieMetadata_ListFilter
+ """
+ ✨ Generated from Field `Movie`.`reviews_on_movie` of type `[Review!]!`
+ """
+ reviews_on_movie: Review_ListFilter
+ """
+ ✨ Generated from Field `Movie`.`actors_via_MovieActor` of type `[Actor!]!`
+ """
+ actors_via_MovieActor: Actor_ListFilter
+ """
+ ✨ Generated from Field `Movie`.`users_via_FavoriteMovie` of type `[User!]!`
+ """
+ users_via_FavoriteMovie: User_ListFilter
+ """
+ ✨ Generated from Field `Movie`.`users_via_Review` of type `[User!]!`
+ """
+ users_via_Review: User_ListFilter
+}
+"""
+✨ Generated first-row input type for table 'Movie'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input Movie_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [Movie_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: Movie_Filter
+}
+"""
+✨ Generated key input type for table 'Movie'. It represents the primary key fields used to uniquely identify a row in the table.
+"""
+input Movie_Key {
+ """
+ ✨ Generated from Field `Movie`.`id` of type `UUID!`
+ """
+ id: UUID
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `Movie`.`id` of type `UUID!`)
+ """
+ id_expr: UUID_Expr
+}
+"""
+✨ Generated list filter input type for table 'Movie'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input Movie_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: Movie_Filter
+}
+"""
+✨ Generated order input type for table 'Movie'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input Movie_Order {
+ """
+ ✨ Generated from Field `Movie`.`id` of type `UUID!`
+ """
+ id: OrderDirection
+ """
+ ✨ Generated from Field `Movie`.`description` of type `String`
+ """
+ description: OrderDirection
+ """
+ ✨ Generated from Field `Movie`.`genre` of type `String`
+ """
+ genre: OrderDirection
+ """
+ ✨ Generated from Field `Movie`.`imageUrl` of type `String!`
+ """
+ imageUrl: OrderDirection
+ """
+ ✨ Generated from Field `Movie`.`rating` of type `Float`
+ """
+ rating: OrderDirection
+ """
+ ✨ Generated from Field `Movie`.`releaseYear` of type `Int`
+ """
+ releaseYear: OrderDirection
+ """
+ ✨ Generated from Field `Movie`.`title` of type `String!`
+ """
+ title: OrderDirection
+}
+"""
+✨ Generated data input type for table 'MovieActor'. It includes all necessary fields for creating or upserting rows into table.
+"""
+input MovieActor_Data {
+ """
+ ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`
+ """
+ movieId: UUID
+ """
+ ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`)
+ """
+ movieId_expr: UUID_Expr
+ """
+ ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`
+ """
+ actorId: UUID
+ """
+ ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`)
+ """
+ actorId_expr: UUID_Expr
+ """
+ ✨ Generated from Field `MovieActor`.`actor` of type `Actor!`
+ """
+ actor: Actor_Key
+ """
+ ✨ Generated from Field `MovieActor`.`movie` of type `Movie!`
+ """
+ movie: Movie_Key
+ """
+ ✨ Generated from Field `MovieActor`.`role` of type `String!`
+ """
+ role: String
+ """
+ ✨ `_expr` server value variant of `role` (✨ Generated from Field `MovieActor`.`role` of type `String!`)
+ """
+ role_expr: String_Expr
+}
+"""
+✨ Generated filter input type for table 'MovieActor'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input MovieActor_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [MovieActor_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: MovieActor_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [MovieActor_Filter!]
+ """
+ ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`
+ """
+ movieId: UUID_Filter
+ """
+ ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`
+ """
+ actorId: UUID_Filter
+ """
+ ✨ Generated from Field `MovieActor`.`actor` of type `Actor!`
+ """
+ actor: Actor_Filter
+ """
+ ✨ Generated from Field `MovieActor`.`movie` of type `Movie!`
+ """
+ movie: Movie_Filter
+ """
+ ✨ Generated from Field `MovieActor`.`role` of type `String!`
+ """
+ role: String_Filter
+}
+"""
+✨ Generated first-row input type for table 'MovieActor'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input MovieActor_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [MovieActor_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: MovieActor_Filter
+}
+"""
+✨ Generated key input type for table 'MovieActor'. It represents the primary key fields used to uniquely identify a row in the table.
+"""
+input MovieActor_Key {
+ """
+ ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`
+ """
+ movieId: UUID
+ """
+ ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`)
+ """
+ movieId_expr: UUID_Expr
+ """
+ ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`
+ """
+ actorId: UUID
+ """
+ ✨ `_expr` server value variant of `actorId` (✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`)
+ """
+ actorId_expr: UUID_Expr
+}
+"""
+✨ Generated list filter input type for table 'MovieActor'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input MovieActor_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: MovieActor_Filter
+}
+"""
+✨ Generated order input type for table 'MovieActor'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input MovieActor_Order {
+ """
+ ✨ Generated from Field `MovieActor`.`movieId` of type `UUID!`
+ """
+ movieId: OrderDirection
+ """
+ ✨ Generated from Field `MovieActor`.`actorId` of type `UUID!`
+ """
+ actorId: OrderDirection
+ """
+ ✨ Generated from Field `MovieActor`.`actor` of type `Actor!`
+ """
+ actor: Actor_Order
+ """
+ ✨ Generated from Field `MovieActor`.`movie` of type `Movie!`
+ """
+ movie: Movie_Order
+ """
+ ✨ Generated from Field `MovieActor`.`role` of type `String!`
+ """
+ role: OrderDirection
+}
+"""
+✨ Generated data input type for table 'MovieMetadata'. It includes all necessary fields for creating or upserting rows into table.
+"""
+input MovieMetadata_Data {
+ """
+ ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`
+ """
+ id: UUID
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`)
+ """
+ id_expr: UUID_Expr
+ """
+ ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!`
+ """
+ movieId: UUID
+ """
+ ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!`)
+ """
+ movieId_expr: UUID_Expr
+ """
+ ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!`
+ """
+ movie: Movie_Key
+ """
+ ✨ Generated from Field `MovieMetadata`.`director` of type `String`
+ """
+ director: String
+ """
+ ✨ `_expr` server value variant of `director` (✨ Generated from Field `MovieMetadata`.`director` of type `String`)
+ """
+ director_expr: String_Expr
+}
+"""
+✨ Generated filter input type for table 'MovieMetadata'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input MovieMetadata_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [MovieMetadata_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: MovieMetadata_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [MovieMetadata_Filter!]
+ """
+ ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`
+ """
+ id: UUID_Filter
+ """
+ ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!`
+ """
+ movieId: UUID_Filter
+ """
+ ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!`
+ """
+ movie: Movie_Filter
+ """
+ ✨ Generated from Field `MovieMetadata`.`director` of type `String`
+ """
+ director: String_Filter
+}
+"""
+✨ Generated first-row input type for table 'MovieMetadata'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input MovieMetadata_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [MovieMetadata_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: MovieMetadata_Filter
+}
+"""
+✨ Generated key input type for table 'MovieMetadata'. It represents the primary key fields used to uniquely identify a row in the table.
+"""
+input MovieMetadata_Key {
+ """
+ ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`
+ """
+ id: UUID
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`)
+ """
+ id_expr: UUID_Expr
+}
+"""
+✨ Generated list filter input type for table 'MovieMetadata'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input MovieMetadata_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: MovieMetadata_Filter
+}
+"""
+✨ Generated order input type for table 'MovieMetadata'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input MovieMetadata_Order {
+ """
+ ✨ Generated from Field `MovieMetadata`.`id` of type `UUID!`
+ """
+ id: OrderDirection
+ """
+ ✨ Generated from Field `MovieMetadata`.`movieId` of type `UUID!`
+ """
+ movieId: OrderDirection
+ """
+ ✨ Generated from Field `MovieMetadata`.`movie` of type `Movie!`
+ """
+ movie: Movie_Order
+ """
+ ✨ Generated from Field `MovieMetadata`.`director` of type `String`
+ """
+ director: OrderDirection
+}
+"""
+✨ Generated data input type for table 'Review'. It includes all necessary fields for creating or upserting rows into table.
+"""
+input Review_Data {
+ """
+ ✨ Generated from Field `Review`.`movieId` of type `UUID!`
+ """
+ movieId: UUID
+ """
+ ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `Review`.`movieId` of type `UUID!`)
+ """
+ movieId_expr: UUID_Expr
+ """
+ ✨ Generated from Field `Review`.`userId` of type `String!`
+ """
+ userId: String
+ """
+ ✨ `_expr` server value variant of `userId` (✨ Generated from Field `Review`.`userId` of type `String!`)
+ """
+ userId_expr: String_Expr
+ """
+ ✨ Generated from Field `Review`.`movie` of type `Movie!`
+ """
+ movie: Movie_Key
+ """
+ ✨ Generated from Field `Review`.`user` of type `User!`
+ """
+ user: User_Key
+ """
+ ✨ Generated from Field `Review`.`id` of type `UUID!`
+ """
+ id: UUID
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `Review`.`id` of type `UUID!`)
+ """
+ id_expr: UUID_Expr
+ """
+ ✨ Generated from Field `Review`.`rating` of type `Int`
+ """
+ rating: Int
+ """
+ ✨ Generated from Field `Review`.`reviewDate` of type `Date!`
+ """
+ reviewDate: Date
+ """
+ ✨ `_date` server value variant of `reviewDate` (✨ Generated from Field `Review`.`reviewDate` of type `Date!`)
+ """
+ reviewDate_date: Date_Relative
+ """
+ ✨ `_expr` server value variant of `reviewDate` (✨ Generated from Field `Review`.`reviewDate` of type `Date!`)
+ """
+ reviewDate_expr: Date_Expr
+ """
+ ✨ Generated from Field `Review`.`reviewText` of type `String`
+ """
+ reviewText: String
+ """
+ ✨ `_expr` server value variant of `reviewText` (✨ Generated from Field `Review`.`reviewText` of type `String`)
+ """
+ reviewText_expr: String_Expr
+}
+"""
+✨ Generated filter input type for table 'Review'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input Review_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [Review_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: Review_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [Review_Filter!]
+ """
+ ✨ Generated from Field `Review`.`movieId` of type `UUID!`
+ """
+ movieId: UUID_Filter
+ """
+ ✨ Generated from Field `Review`.`userId` of type `String!`
+ """
+ userId: String_Filter
+ """
+ ✨ Generated from Field `Review`.`movie` of type `Movie!`
+ """
+ movie: Movie_Filter
+ """
+ ✨ Generated from Field `Review`.`user` of type `User!`
+ """
+ user: User_Filter
+ """
+ ✨ Generated from Field `Review`.`id` of type `UUID!`
+ """
+ id: UUID_Filter
+ """
+ ✨ Generated from Field `Review`.`rating` of type `Int`
+ """
+ rating: Int_Filter
+ """
+ ✨ Generated from Field `Review`.`reviewDate` of type `Date!`
+ """
+ reviewDate: Date_Filter
+ """
+ ✨ Generated from Field `Review`.`reviewText` of type `String`
+ """
+ reviewText: String_Filter
+}
+"""
+✨ Generated first-row input type for table 'Review'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input Review_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [Review_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: Review_Filter
+}
+"""
+✨ Generated key input type for table 'Review'. It represents the primary key fields used to uniquely identify a row in the table.
+"""
+input Review_Key {
+ """
+ ✨ Generated from Field `Review`.`movieId` of type `UUID!`
+ """
+ movieId: UUID
+ """
+ ✨ `_expr` server value variant of `movieId` (✨ Generated from Field `Review`.`movieId` of type `UUID!`)
+ """
+ movieId_expr: UUID_Expr
+ """
+ ✨ Generated from Field `Review`.`userId` of type `String!`
+ """
+ userId: String
+ """
+ ✨ `_expr` server value variant of `userId` (✨ Generated from Field `Review`.`userId` of type `String!`)
+ """
+ userId_expr: String_Expr
+}
+"""
+✨ Generated list filter input type for table 'Review'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input Review_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: Review_Filter
+}
+"""
+✨ Generated order input type for table 'Review'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input Review_Order {
+ """
+ ✨ Generated from Field `Review`.`movieId` of type `UUID!`
+ """
+ movieId: OrderDirection
+ """
+ ✨ Generated from Field `Review`.`userId` of type `String!`
+ """
+ userId: OrderDirection
+ """
+ ✨ Generated from Field `Review`.`movie` of type `Movie!`
+ """
+ movie: Movie_Order
+ """
+ ✨ Generated from Field `Review`.`user` of type `User!`
+ """
+ user: User_Order
+ """
+ ✨ Generated from Field `Review`.`id` of type `UUID!`
+ """
+ id: OrderDirection
+ """
+ ✨ Generated from Field `Review`.`rating` of type `Int`
+ """
+ rating: OrderDirection
+ """
+ ✨ Generated from Field `Review`.`reviewDate` of type `Date!`
+ """
+ reviewDate: OrderDirection
+ """
+ ✨ Generated from Field `Review`.`reviewText` of type `String`
+ """
+ reviewText: OrderDirection
+}
+"""
+✨ Generated data input type for table 'User'. It includes all necessary fields for creating or upserting rows into table.
+"""
+input User_Data {
+ """
+ ✨ Generated from Field `User`.`id` of type `String!`
+ """
+ id: String
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `User`.`id` of type `String!`)
+ """
+ id_expr: String_Expr
+ """
+ ✨ Generated from Field `User`.`name` of type `String!`
+ """
+ name: String
+ """
+ ✨ `_expr` server value variant of `name` (✨ Generated from Field `User`.`name` of type `String!`)
+ """
+ name_expr: String_Expr
+ """
+ ✨ Generated from Field `User`.`username` of type `String!`
+ """
+ username: String
+ """
+ ✨ `_expr` server value variant of `username` (✨ Generated from Field `User`.`username` of type `String!`)
+ """
+ username_expr: String_Expr
+}
+"""
+✨ Generated filter input type for table 'User'. This input allows filtering objects using various conditions. Use `_or`, `_and`, and `_not` to compose complex filters.
+"""
+input User_Filter {
+ """
+ Apply multiple filter conditions using `AND` logic.
+ """
+ _and: [User_Filter!]
+ """
+ Negate the result of the provided filter condition.
+ """
+ _not: User_Filter
+ """
+ Apply multiple filter conditions using `OR` logic.
+ """
+ _or: [User_Filter!]
+ """
+ ✨ Generated from Field `User`.`id` of type `String!`
+ """
+ id: String_Filter
+ """
+ ✨ Generated from Field `User`.`name` of type `String!`
+ """
+ name: String_Filter
+ """
+ ✨ Generated from Field `User`.`username` of type `String!`
+ """
+ username: String_Filter
+ """
+ ✨ Generated from Field `User`.`favorite_movies_on_user` of type `[FavoriteMovie!]!`
+ """
+ favorite_movies_on_user: FavoriteMovie_ListFilter
+ """
+ ✨ Generated from Field `User`.`reviews_on_user` of type `[Review!]!`
+ """
+ reviews_on_user: Review_ListFilter
+ """
+ ✨ Generated from Field `User`.`movies_via_FavoriteMovie` of type `[Movie!]!`
+ """
+ movies_via_FavoriteMovie: Movie_ListFilter
+ """
+ ✨ Generated from Field `User`.`movies_via_Review` of type `[Movie!]!`
+ """
+ movies_via_Review: Movie_ListFilter
+}
+"""
+✨ Generated first-row input type for table 'User'. This input selects the first row matching the filter criteria, ordered according to the specified conditions.
+"""
+input User_FirstRow {
+ """
+ Order the result by the specified fields.
+ """
+ orderBy: [User_Order!]
+ """
+ Filters rows based on the specified conditions.
+ """
+ where: User_Filter
+}
+"""
+✨ Generated key input type for table 'User'. It represents the primary key fields used to uniquely identify a row in the table.
+"""
+input User_Key {
+ """
+ ✨ Generated from Field `User`.`id` of type `String!`
+ """
+ id: String
+ """
+ ✨ `_expr` server value variant of `id` (✨ Generated from Field `User`.`id` of type `String!`)
+ """
+ id_expr: String_Expr
+}
+"""
+✨ Generated list filter input type for table 'User'. This input applies filtering logic based on the count or existence of related objects that matches certain criteria.
+"""
+input User_ListFilter {
+ """
+ The desired number of objects that match the condition (defaults to at least one).
+ """
+ count: Int_Filter = {gt:0}
+ """
+ Condition of the related objects to filter for.
+ """
+ exist: User_Filter
+}
+"""
+✨ Generated order input type for table 'User'. This input defines the sorting order of rows in query results based on one or more fields.
+"""
+input User_Order {
+ """
+ ✨ Generated from Field `User`.`id` of type `String!`
+ """
+ id: OrderDirection
+ """
+ ✨ Generated from Field `User`.`name` of type `String!`
+ """
+ name: OrderDirection
+ """
+ ✨ Generated from Field `User`.`username` of type `String!`
+ """
+ username: OrderDirection
+}
diff --git a/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/mutation.gql b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/mutation.gql
new file mode 100644
index 00000000..1dad2178
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/mutation.gql
@@ -0,0 +1,766 @@
+extend type Mutation {
+ """
+ ✨ Insert a single `Actor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ actor_insert(
+ """
+ Data object to insert into the table.
+ """
+ data: Actor_Data!
+ ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: INSERT_SINGLE)
+ """
+ ✨ Insert a single `FavoriteMovie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ favorite_movie_insert(
+ """
+ Data object to insert into the table.
+ """
+ data: FavoriteMovie_Data!
+ ): FavoriteMovie_KeyOutput! @fdc_generated(from: "FavoriteMovie", purpose: INSERT_SINGLE)
+ """
+ ✨ Insert a single `Movie` into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ movie_insert(
+ """
+ Data object to insert into the table.
+ """
+ data: Movie_Data!
+ ): Movie_KeyOutput! @fdc_generated(from: "Movie", purpose: INSERT_SINGLE)
+ """
+ ✨ Insert a single `MovieActor` into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ movieActor_insert(
+ """
+ Data object to insert into the table.
+ """
+ data: MovieActor_Data!
+ ): MovieActor_KeyOutput! @fdc_generated(from: "MovieActor", purpose: INSERT_SINGLE)
+ """
+ ✨ Insert a single `MovieMetadata` into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ movieMetadata_insert(
+ """
+ Data object to insert into the table.
+ """
+ data: MovieMetadata_Data!
+ ): MovieMetadata_KeyOutput! @fdc_generated(from: "MovieMetadata", purpose: INSERT_SINGLE)
+ """
+ ✨ Insert a single `Review` into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ review_insert(
+ """
+ Data object to insert into the table.
+ """
+ data: Review_Data!
+ ): Review_KeyOutput! @fdc_generated(from: "Review", purpose: INSERT_SINGLE)
+ """
+ ✨ Insert a single `User` into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ user_insert(
+ """
+ Data object to insert into the table.
+ """
+ data: User_Data!
+ ): User_KeyOutput! @fdc_generated(from: "User", purpose: INSERT_SINGLE)
+ """
+ ✨ Insert `Actor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ actor_insertMany(
+ """
+ List of data objects to insert into the table.
+ """
+ data: [Actor_Data!]!
+ ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: INSERT_MULTIPLE)
+ """
+ ✨ Insert `FavoriteMovie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ favorite_movie_insertMany(
+ """
+ List of data objects to insert into the table.
+ """
+ data: [FavoriteMovie_Data!]!
+ ): [FavoriteMovie_KeyOutput!]! @fdc_generated(from: "FavoriteMovie", purpose: INSERT_MULTIPLE)
+ """
+ ✨ Insert `Movie` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ movie_insertMany(
+ """
+ List of data objects to insert into the table.
+ """
+ data: [Movie_Data!]!
+ ): [Movie_KeyOutput!]! @fdc_generated(from: "Movie", purpose: INSERT_MULTIPLE)
+ """
+ ✨ Insert `MovieActor` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ movieActor_insertMany(
+ """
+ List of data objects to insert into the table.
+ """
+ data: [MovieActor_Data!]!
+ ): [MovieActor_KeyOutput!]! @fdc_generated(from: "MovieActor", purpose: INSERT_MULTIPLE)
+ """
+ ✨ Insert `MovieMetadata` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ movieMetadata_insertMany(
+ """
+ List of data objects to insert into the table.
+ """
+ data: [MovieMetadata_Data!]!
+ ): [MovieMetadata_KeyOutput!]! @fdc_generated(from: "MovieMetadata", purpose: INSERT_MULTIPLE)
+ """
+ ✨ Insert `Review` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ review_insertMany(
+ """
+ List of data objects to insert into the table.
+ """
+ data: [Review_Data!]!
+ ): [Review_KeyOutput!]! @fdc_generated(from: "Review", purpose: INSERT_MULTIPLE)
+ """
+ ✨ Insert `User` objects into the table. Columns not specified in `data` will receive defaults (e.g. `null`).
+ """
+ user_insertMany(
+ """
+ List of data objects to insert into the table.
+ """
+ data: [User_Data!]!
+ ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: INSERT_MULTIPLE)
+ """
+ ✨ Insert or update a single `Actor` into the table, based on the primary key. Returns the key of the newly inserted `Actor`.
+ """
+ actor_upsert(
+ """
+ Data object to insert or update if it already exists.
+ """
+ data: Actor_Data!
+ ): Actor_KeyOutput! @fdc_generated(from: "Actor", purpose: UPSERT_SINGLE)
+ """
+ ✨ Insert or update a single `FavoriteMovie` into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`.
+ """
+ favorite_movie_upsert(
+ """
+ Data object to insert or update if it already exists.
+ """
+ data: FavoriteMovie_Data!
+ ): FavoriteMovie_KeyOutput! @fdc_generated(from: "FavoriteMovie", purpose: UPSERT_SINGLE)
+ """
+ ✨ Insert or update a single `Movie` into the table, based on the primary key. Returns the key of the newly inserted `Movie`.
+ """
+ movie_upsert(
+ """
+ Data object to insert or update if it already exists.
+ """
+ data: Movie_Data!
+ ): Movie_KeyOutput! @fdc_generated(from: "Movie", purpose: UPSERT_SINGLE)
+ """
+ ✨ Insert or update a single `MovieActor` into the table, based on the primary key. Returns the key of the newly inserted `MovieActor`.
+ """
+ movieActor_upsert(
+ """
+ Data object to insert or update if it already exists.
+ """
+ data: MovieActor_Data!
+ ): MovieActor_KeyOutput! @fdc_generated(from: "MovieActor", purpose: UPSERT_SINGLE)
+ """
+ ✨ Insert or update a single `MovieMetadata` into the table, based on the primary key. Returns the key of the newly inserted `MovieMetadata`.
+ """
+ movieMetadata_upsert(
+ """
+ Data object to insert or update if it already exists.
+ """
+ data: MovieMetadata_Data!
+ ): MovieMetadata_KeyOutput! @fdc_generated(from: "MovieMetadata", purpose: UPSERT_SINGLE)
+ """
+ ✨ Insert or update a single `Review` into the table, based on the primary key. Returns the key of the newly inserted `Review`.
+ """
+ review_upsert(
+ """
+ Data object to insert or update if it already exists.
+ """
+ data: Review_Data!
+ ): Review_KeyOutput! @fdc_generated(from: "Review", purpose: UPSERT_SINGLE)
+ """
+ ✨ Insert or update a single `User` into the table, based on the primary key. Returns the key of the newly inserted `User`.
+ """
+ user_upsert(
+ """
+ Data object to insert or update if it already exists.
+ """
+ data: User_Data!
+ ): User_KeyOutput! @fdc_generated(from: "User", purpose: UPSERT_SINGLE)
+ """
+ ✨ Insert or update `Actor` objects into the table, based on the primary key. Returns the key of the newly inserted `Actor`.
+ """
+ actor_upsertMany(
+ """
+ List of data objects to insert or update if it already exists.
+ """
+ data: [Actor_Data!]!
+ ): [Actor_KeyOutput!]! @fdc_generated(from: "Actor", purpose: UPSERT_MULTIPLE)
+ """
+ ✨ Insert or update `FavoriteMovie` objects into the table, based on the primary key. Returns the key of the newly inserted `FavoriteMovie`.
+ """
+ favorite_movie_upsertMany(
+ """
+ List of data objects to insert or update if it already exists.
+ """
+ data: [FavoriteMovie_Data!]!
+ ): [FavoriteMovie_KeyOutput!]! @fdc_generated(from: "FavoriteMovie", purpose: UPSERT_MULTIPLE)
+ """
+ ✨ Insert or update `Movie` objects into the table, based on the primary key. Returns the key of the newly inserted `Movie`.
+ """
+ movie_upsertMany(
+ """
+ List of data objects to insert or update if it already exists.
+ """
+ data: [Movie_Data!]!
+ ): [Movie_KeyOutput!]! @fdc_generated(from: "Movie", purpose: UPSERT_MULTIPLE)
+ """
+ ✨ Insert or update `MovieActor` objects into the table, based on the primary key. Returns the key of the newly inserted `MovieActor`.
+ """
+ movieActor_upsertMany(
+ """
+ List of data objects to insert or update if it already exists.
+ """
+ data: [MovieActor_Data!]!
+ ): [MovieActor_KeyOutput!]! @fdc_generated(from: "MovieActor", purpose: UPSERT_MULTIPLE)
+ """
+ ✨ Insert or update `MovieMetadata` objects into the table, based on the primary key. Returns the key of the newly inserted `MovieMetadata`.
+ """
+ movieMetadata_upsertMany(
+ """
+ List of data objects to insert or update if it already exists.
+ """
+ data: [MovieMetadata_Data!]!
+ ): [MovieMetadata_KeyOutput!]! @fdc_generated(from: "MovieMetadata", purpose: UPSERT_MULTIPLE)
+ """
+ ✨ Insert or update `Review` objects into the table, based on the primary key. Returns the key of the newly inserted `Review`.
+ """
+ review_upsertMany(
+ """
+ List of data objects to insert or update if it already exists.
+ """
+ data: [Review_Data!]!
+ ): [Review_KeyOutput!]! @fdc_generated(from: "Review", purpose: UPSERT_MULTIPLE)
+ """
+ ✨ Insert or update `User` objects into the table, based on the primary key. Returns the key of the newly inserted `User`.
+ """
+ user_upsertMany(
+ """
+ List of data objects to insert or update if it already exists.
+ """
+ data: [User_Data!]!
+ ): [User_KeyOutput!]! @fdc_generated(from: "User", purpose: UPSERT_MULTIPLE)
+ """
+ ✨ Update a single `Actor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found.
+ """
+ actor_update(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: Actor_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Actor_FirstRow
+
+ """
+ Data object containing fields to be updated.
+ """
+ data: Actor_Data!
+ ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: UPDATE_SINGLE)
+ """
+ ✨ Update a single `FavoriteMovie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found.
+ """
+ favorite_movie_update(
+ """
+ The key used to identify the object.
+ """
+ key: FavoriteMovie_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: FavoriteMovie_FirstRow
+
+ """
+ Data object containing fields to be updated.
+ """
+ data: FavoriteMovie_Data!
+ ): FavoriteMovie_KeyOutput @fdc_generated(from: "FavoriteMovie", purpose: UPDATE_SINGLE)
+ """
+ ✨ Update a single `Movie` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found.
+ """
+ movie_update(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: Movie_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Movie_FirstRow
+
+ """
+ Data object containing fields to be updated.
+ """
+ data: Movie_Data!
+ ): Movie_KeyOutput @fdc_generated(from: "Movie", purpose: UPDATE_SINGLE)
+ """
+ ✨ Update a single `MovieActor` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found.
+ """
+ movieActor_update(
+ """
+ The key used to identify the object.
+ """
+ key: MovieActor_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: MovieActor_FirstRow
+
+ """
+ Data object containing fields to be updated.
+ """
+ data: MovieActor_Data!
+ ): MovieActor_KeyOutput @fdc_generated(from: "MovieActor", purpose: UPDATE_SINGLE)
+ """
+ ✨ Update a single `MovieMetadata` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found.
+ """
+ movieMetadata_update(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: MovieMetadata_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: MovieMetadata_FirstRow
+
+ """
+ Data object containing fields to be updated.
+ """
+ data: MovieMetadata_Data!
+ ): MovieMetadata_KeyOutput @fdc_generated(from: "MovieMetadata", purpose: UPDATE_SINGLE)
+ """
+ ✨ Update a single `Review` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found.
+ """
+ review_update(
+ """
+ The key used to identify the object.
+ """
+ key: Review_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Review_FirstRow
+
+ """
+ Data object containing fields to be updated.
+ """
+ data: Review_Data!
+ ): Review_KeyOutput @fdc_generated(from: "Review", purpose: UPDATE_SINGLE)
+ """
+ ✨ Update a single `User` based on `id`, `key` or `first`, setting columns specified in `data`. Returns `null` if not found.
+ """
+ user_update(
+ """
+ The unique ID of the object.
+ """
+ id: String
+
+ """
+ ✨ `_expr` server value variant of `id` (The unique ID of the object.)
+ """
+ id_expr: String_Expr
+
+ """
+ The key used to identify the object.
+ """
+ key: User_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: User_FirstRow
+
+ """
+ Data object containing fields to be updated.
+ """
+ data: User_Data!
+ ): User_KeyOutput @fdc_generated(from: "User", purpose: UPDATE_SINGLE)
+ """
+ ✨ Update `Actor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+ """
+ actor_updateMany(
+ """
+ Filter condition to specify which rows to update.
+ """
+ where: Actor_Filter
+
+ """
+ Set to true to update all rows.
+ """
+ all: Boolean = false
+
+ """
+ Data object containing fields to update.
+ """
+ data: Actor_Data!
+ ): Int! @fdc_generated(from: "Actor", purpose: UPDATE_MULTIPLE)
+ """
+ ✨ Update `FavoriteMovie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+ """
+ favorite_movie_updateMany(
+ """
+ Filter condition to specify which rows to update.
+ """
+ where: FavoriteMovie_Filter
+
+ """
+ Set to true to update all rows.
+ """
+ all: Boolean = false
+
+ """
+ Data object containing fields to update.
+ """
+ data: FavoriteMovie_Data!
+ ): Int! @fdc_generated(from: "FavoriteMovie", purpose: UPDATE_MULTIPLE)
+ """
+ ✨ Update `Movie` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+ """
+ movie_updateMany(
+ """
+ Filter condition to specify which rows to update.
+ """
+ where: Movie_Filter
+
+ """
+ Set to true to update all rows.
+ """
+ all: Boolean = false
+
+ """
+ Data object containing fields to update.
+ """
+ data: Movie_Data!
+ ): Int! @fdc_generated(from: "Movie", purpose: UPDATE_MULTIPLE)
+ """
+ ✨ Update `MovieActor` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+ """
+ movieActor_updateMany(
+ """
+ Filter condition to specify which rows to update.
+ """
+ where: MovieActor_Filter
+
+ """
+ Set to true to update all rows.
+ """
+ all: Boolean = false
+
+ """
+ Data object containing fields to update.
+ """
+ data: MovieActor_Data!
+ ): Int! @fdc_generated(from: "MovieActor", purpose: UPDATE_MULTIPLE)
+ """
+ ✨ Update `MovieMetadata` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+ """
+ movieMetadata_updateMany(
+ """
+ Filter condition to specify which rows to update.
+ """
+ where: MovieMetadata_Filter
+
+ """
+ Set to true to update all rows.
+ """
+ all: Boolean = false
+
+ """
+ Data object containing fields to update.
+ """
+ data: MovieMetadata_Data!
+ ): Int! @fdc_generated(from: "MovieMetadata", purpose: UPDATE_MULTIPLE)
+ """
+ ✨ Update `Review` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+ """
+ review_updateMany(
+ """
+ Filter condition to specify which rows to update.
+ """
+ where: Review_Filter
+
+ """
+ Set to true to update all rows.
+ """
+ all: Boolean = false
+
+ """
+ Data object containing fields to update.
+ """
+ data: Review_Data!
+ ): Int! @fdc_generated(from: "Review", purpose: UPDATE_MULTIPLE)
+ """
+ ✨ Update `User` objects matching `where` conditions (or `all`, if true) according to `data`. Returns the number of rows updated.
+ """
+ user_updateMany(
+ """
+ Filter condition to specify which rows to update.
+ """
+ where: User_Filter
+
+ """
+ Set to true to update all rows.
+ """
+ all: Boolean = false
+
+ """
+ Data object containing fields to update.
+ """
+ data: User_Data!
+ ): Int! @fdc_generated(from: "User", purpose: UPDATE_MULTIPLE)
+ """
+ ✨ Delete a single `Actor` based on `id`, `key` or `first` and return its key (or `null` if not found).
+ """
+ actor_delete(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: Actor_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Actor_FirstRow
+ ): Actor_KeyOutput @fdc_generated(from: "Actor", purpose: DELETE_SINGLE)
+ """
+ ✨ Delete a single `FavoriteMovie` based on `id`, `key` or `first` and return its key (or `null` if not found).
+ """
+ favorite_movie_delete(
+ """
+ The key used to identify the object.
+ """
+ key: FavoriteMovie_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: FavoriteMovie_FirstRow
+ ): FavoriteMovie_KeyOutput @fdc_generated(from: "FavoriteMovie", purpose: DELETE_SINGLE)
+ """
+ ✨ Delete a single `Movie` based on `id`, `key` or `first` and return its key (or `null` if not found).
+ """
+ movie_delete(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: Movie_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Movie_FirstRow
+ ): Movie_KeyOutput @fdc_generated(from: "Movie", purpose: DELETE_SINGLE)
+ """
+ ✨ Delete a single `MovieActor` based on `id`, `key` or `first` and return its key (or `null` if not found).
+ """
+ movieActor_delete(
+ """
+ The key used to identify the object.
+ """
+ key: MovieActor_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: MovieActor_FirstRow
+ ): MovieActor_KeyOutput @fdc_generated(from: "MovieActor", purpose: DELETE_SINGLE)
+ """
+ ✨ Delete a single `MovieMetadata` based on `id`, `key` or `first` and return its key (or `null` if not found).
+ """
+ movieMetadata_delete(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: MovieMetadata_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: MovieMetadata_FirstRow
+ ): MovieMetadata_KeyOutput @fdc_generated(from: "MovieMetadata", purpose: DELETE_SINGLE)
+ """
+ ✨ Delete a single `Review` based on `id`, `key` or `first` and return its key (or `null` if not found).
+ """
+ review_delete(
+ """
+ The key used to identify the object.
+ """
+ key: Review_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Review_FirstRow
+ ): Review_KeyOutput @fdc_generated(from: "Review", purpose: DELETE_SINGLE)
+ """
+ ✨ Delete a single `User` based on `id`, `key` or `first` and return its key (or `null` if not found).
+ """
+ user_delete(
+ """
+ The unique ID of the object.
+ """
+ id: String
+
+ """
+ ✨ `_expr` server value variant of `id` (The unique ID of the object.)
+ """
+ id_expr: String_Expr
+
+ """
+ The key used to identify the object.
+ """
+ key: User_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: User_FirstRow
+ ): User_KeyOutput @fdc_generated(from: "User", purpose: DELETE_SINGLE)
+ """
+ ✨ Delete `Actor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+ """
+ actor_deleteMany(
+ """
+ Filter condition to specify which rows to delete.
+ """
+ where: Actor_Filter
+
+ """
+ Set to true to delete all rows.
+ """
+ all: Boolean = false
+ ): Int! @fdc_generated(from: "Actor", purpose: DELETE_MULTIPLE)
+ """
+ ✨ Delete `FavoriteMovie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+ """
+ favorite_movie_deleteMany(
+ """
+ Filter condition to specify which rows to delete.
+ """
+ where: FavoriteMovie_Filter
+
+ """
+ Set to true to delete all rows.
+ """
+ all: Boolean = false
+ ): Int! @fdc_generated(from: "FavoriteMovie", purpose: DELETE_MULTIPLE)
+ """
+ ✨ Delete `Movie` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+ """
+ movie_deleteMany(
+ """
+ Filter condition to specify which rows to delete.
+ """
+ where: Movie_Filter
+
+ """
+ Set to true to delete all rows.
+ """
+ all: Boolean = false
+ ): Int! @fdc_generated(from: "Movie", purpose: DELETE_MULTIPLE)
+ """
+ ✨ Delete `MovieActor` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+ """
+ movieActor_deleteMany(
+ """
+ Filter condition to specify which rows to delete.
+ """
+ where: MovieActor_Filter
+
+ """
+ Set to true to delete all rows.
+ """
+ all: Boolean = false
+ ): Int! @fdc_generated(from: "MovieActor", purpose: DELETE_MULTIPLE)
+ """
+ ✨ Delete `MovieMetadata` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+ """
+ movieMetadata_deleteMany(
+ """
+ Filter condition to specify which rows to delete.
+ """
+ where: MovieMetadata_Filter
+
+ """
+ Set to true to delete all rows.
+ """
+ all: Boolean = false
+ ): Int! @fdc_generated(from: "MovieMetadata", purpose: DELETE_MULTIPLE)
+ """
+ ✨ Delete `Review` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+ """
+ review_deleteMany(
+ """
+ Filter condition to specify which rows to delete.
+ """
+ where: Review_Filter
+
+ """
+ Set to true to delete all rows.
+ """
+ all: Boolean = false
+ ): Int! @fdc_generated(from: "Review", purpose: DELETE_MULTIPLE)
+ """
+ ✨ Delete `User` objects matching `where` conditions (or `all`, if true). Returns the number of rows deleted.
+ """
+ user_deleteMany(
+ """
+ Filter condition to specify which rows to delete.
+ """
+ where: User_Filter
+
+ """
+ Set to true to delete all rows.
+ """
+ all: Boolean = false
+ ): Int! @fdc_generated(from: "User", purpose: DELETE_MULTIPLE)
+}
diff --git a/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/query.gql b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/query.gql
new file mode 100644
index 00000000..a2f3bc6f
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/query.gql
@@ -0,0 +1,317 @@
+extend type Query {
+ """
+ ✨ Look up a single `Actor` based on `id`, `key` or `first` and return selected fields (or `null` if not found).
+ """
+ actor(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: Actor_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Actor_FirstRow
+ ): Actor @fdc_generated(from: "Actor", purpose: QUERY_SINGLE)
+ """
+ ✨ Look up a single `FavoriteMovie` based on `id`, `key` or `first` and return selected fields (or `null` if not found).
+ """
+ favorite_movie(
+ """
+ The key used to identify the object.
+ """
+ key: FavoriteMovie_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: FavoriteMovie_FirstRow
+ ): FavoriteMovie @fdc_generated(from: "FavoriteMovie", purpose: QUERY_SINGLE)
+ """
+ ✨ Look up a single `Movie` based on `id`, `key` or `first` and return selected fields (or `null` if not found).
+ """
+ movie(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: Movie_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Movie_FirstRow
+ ): Movie @fdc_generated(from: "Movie", purpose: QUERY_SINGLE)
+ """
+ ✨ Look up a single `MovieActor` based on `id`, `key` or `first` and return selected fields (or `null` if not found).
+ """
+ movieActor(
+ """
+ The key used to identify the object.
+ """
+ key: MovieActor_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: MovieActor_FirstRow
+ ): MovieActor @fdc_generated(from: "MovieActor", purpose: QUERY_SINGLE)
+ """
+ ✨ Look up a single `MovieMetadata` based on `id`, `key` or `first` and return selected fields (or `null` if not found).
+ """
+ movieMetadata(
+ """
+ The unique ID of the object.
+ """
+ id: UUID
+
+ """
+ The key used to identify the object.
+ """
+ key: MovieMetadata_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: MovieMetadata_FirstRow
+ ): MovieMetadata @fdc_generated(from: "MovieMetadata", purpose: QUERY_SINGLE)
+ """
+ ✨ Look up a single `Review` based on `id`, `key` or `first` and return selected fields (or `null` if not found).
+ """
+ review(
+ """
+ The key used to identify the object.
+ """
+ key: Review_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: Review_FirstRow
+ ): Review @fdc_generated(from: "Review", purpose: QUERY_SINGLE)
+ """
+ ✨ Look up a single `User` based on `id`, `key` or `first` and return selected fields (or `null` if not found).
+ """
+ user(
+ """
+ The unique ID of the object.
+ """
+ id: String
+
+ """
+ ✨ `_expr` server value variant of `id` (The unique ID of the object.)
+ """
+ id_expr: String_Expr
+
+ """
+ The key used to identify the object.
+ """
+ key: User_Key
+
+ """
+ Fetch the first row based on the filters and ordering.
+ """
+ first: User_FirstRow
+ ): User @fdc_generated(from: "User", purpose: QUERY_SINGLE)
+ """
+ ✨ List `Actor` objects in the table, optionally filtered by `where` conditions.
+ """
+ actors(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Actor_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Actor_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Actor!]! @fdc_generated(from: "Actor", purpose: QUERY_MULTIPLE)
+ """
+ ✨ List `FavoriteMovie` objects in the table, optionally filtered by `where` conditions.
+ """
+ favorite_movies(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: FavoriteMovie_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [FavoriteMovie_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE)
+ """
+ ✨ List `Genre` objects in the table, optionally filtered by `where` conditions.
+ """
+ genres(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Genre_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Genre_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Genre!]! @fdc_generated(from: "Genre", purpose: QUERY_MULTIPLE)
+ """
+ ✨ List `Movie` objects in the table, optionally filtered by `where` conditions.
+ """
+ movies(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Movie_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Movie_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Movie!]! @fdc_generated(from: "Movie", purpose: QUERY_MULTIPLE)
+ """
+ ✨ List `MovieActor` objects in the table, optionally filtered by `where` conditions.
+ """
+ movieActors(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: MovieActor_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [MovieActor_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [MovieActor!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE)
+ """
+ ✨ List `MovieMetadata` objects in the table, optionally filtered by `where` conditions.
+ """
+ movieMetadatas(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: MovieMetadata_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [MovieMetadata_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [MovieMetadata!]! @fdc_generated(from: "MovieMetadata", purpose: QUERY_MULTIPLE)
+ """
+ ✨ List `Review` objects in the table, optionally filtered by `where` conditions.
+ """
+ reviews(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Review_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Review_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Review!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE)
+ """
+ ✨ List `User` objects in the table, optionally filtered by `where` conditions.
+ """
+ users(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: User_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [User_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [User!]! @fdc_generated(from: "User", purpose: QUERY_MULTIPLE)
+}
diff --git a/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/relation.gql b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/relation.gql
new file mode 100644
index 00000000..5b1d7799
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/main/relation.gql
@@ -0,0 +1,318 @@
+extend type Actor {
+ """
+ ✨ List `MovieActor` objects in a one-to-many relationship (where `MovieActor`.`actor` is this object).
+ """
+ movieActors_on_actor(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: MovieActor_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [MovieActor_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [MovieActor!]! @fdc_generated(from: "MovieActor.actor", purpose: QUERY_MULTIPLE_ONE_TO_MANY)
+ """
+ ✨ List `Movie` objects using `MovieActor` as the join table (a `MovieActor` object exists where its `actor` is this and its `movie` is that).
+ """
+ movies_via_MovieActor(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: MovieActor_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [MovieActor_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Movie!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY)
+}
+extend type Movie {
+ """
+ ✨ List `FavoriteMovie` objects in a one-to-many relationship (where `FavoriteMovie`.`movie` is this object).
+ """
+ favorite_movies_on_movie(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: FavoriteMovie_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [FavoriteMovie_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY)
+ """
+ ✨ List `MovieActor` objects in a one-to-many relationship (where `MovieActor`.`movie` is this object).
+ """
+ movieActors_on_movie(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: MovieActor_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [MovieActor_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [MovieActor!]! @fdc_generated(from: "MovieActor.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY)
+ """
+ ✨ List `MovieMetadata` objects in a one-to-many relationship (where `MovieMetadata`.`movie` is this object).
+ """
+ movieMetadatas_on_movie(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: MovieMetadata_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [MovieMetadata_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [MovieMetadata!]! @fdc_generated(from: "MovieMetadata.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY)
+ """
+ ✨ List `Review` objects in a one-to-many relationship (where `Review`.`movie` is this object).
+ """
+ reviews_on_movie(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Review_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Review_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Review!]! @fdc_generated(from: "Review.movie", purpose: QUERY_MULTIPLE_ONE_TO_MANY)
+ """
+ ✨ List `Actor` objects using `MovieActor` as the join table (a `MovieActor` object exists where its `movie` is this and its `actor` is that).
+ """
+ actors_via_MovieActor(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: MovieActor_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [MovieActor_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Actor!]! @fdc_generated(from: "MovieActor", purpose: QUERY_MULTIPLE_MANY_TO_MANY)
+ """
+ ✨ List `User` objects using `FavoriteMovie` as the join table (a `FavoriteMovie` object exists where its `movie` is this and its `user` is that).
+ """
+ users_via_FavoriteMovie(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: FavoriteMovie_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [FavoriteMovie_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [User!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY)
+ """
+ ✨ List `User` objects using `Review` as the join table (a `Review` object exists where its `movie` is this and its `user` is that).
+ """
+ users_via_Review(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Review_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Review_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [User!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY)
+}
+extend type User {
+ """
+ ✨ List `FavoriteMovie` objects in a one-to-many relationship (where `FavoriteMovie`.`user` is this object).
+ """
+ favorite_movies_on_user(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: FavoriteMovie_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [FavoriteMovie_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [FavoriteMovie!]! @fdc_generated(from: "FavoriteMovie.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY)
+ """
+ ✨ List `Review` objects in a one-to-many relationship (where `Review`.`user` is this object).
+ """
+ reviews_on_user(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Review_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Review_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Review!]! @fdc_generated(from: "Review.user", purpose: QUERY_MULTIPLE_ONE_TO_MANY)
+ """
+ ✨ List `Movie` objects using `FavoriteMovie` as the join table (a `FavoriteMovie` object exists where its `user` is this and its `movie` is that).
+ """
+ movies_via_FavoriteMovie(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: FavoriteMovie_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [FavoriteMovie_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Movie!]! @fdc_generated(from: "FavoriteMovie", purpose: QUERY_MULTIPLE_MANY_TO_MANY)
+ """
+ ✨ List `Movie` objects using `Review` as the join table (a `Review` object exists where its `user` is this and its `movie` is that).
+ """
+ movies_via_Review(
+ """
+ Filter condition to narrow down the query results.
+ """
+ where: Review_Filter
+
+ """
+ Order the query results by specific fields.
+ """
+ orderBy: [Review_Order!]
+
+ """
+ Number of rows to skip before starting to return the results.
+ """
+ offset: Int
+
+ """
+ Maximum number of rows to return (defaults to 100 rows).
+ """
+ limit: Int = 100
+ ): [Movie!]! @fdc_generated(from: "Review", purpose: QUERY_MULTIPLE_MANY_TO_MANY)
+}
diff --git a/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/prelude.gql b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/prelude.gql
new file mode 100644
index 00000000..7fac870c
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/.dataconnect/schema/prelude.gql
@@ -0,0 +1,2026 @@
+"AccessLevel specifies coarse access policies for common situations."
+enum AccessLevel {
+ """
+ This operation is accessible to anyone, with or without authentication.
+ Equivalent to: `@auth(expr: "true")`
+ """
+ PUBLIC
+
+ """
+ This operation can be executed only with a valid Firebase Auth ID token.
+ **Note:** This access level allows anonymous and unverified accounts,
+ which may present security and abuse risks.
+ Equivalent to: `@auth(expr: "auth.uid != nil")`
+ """
+ USER_ANON
+
+ """
+ This operation is restricted to non-anonymous Firebase Auth accounts.
+ Equivalent to: `@auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")`
+ """
+ USER
+
+ """
+ This operation is restricted to Firebase Auth accounts with verified email addresses.
+ Equivalent to: `@auth(expr: "auth.uid != nil && auth.token.email_verified")`
+ """
+ USER_EMAIL_VERIFIED
+
+ """
+ This operation cannot be executed by anyone. The operation can only be performed
+ by using the Admin SDK from a privileged environment.
+ Equivalent to: `@auth(expr: "false")`
+ """
+ NO_ACCESS
+}
+
+"""
+The `@auth` directive defines the authentication policy for a query or mutation.
+
+It must be added to any operation that you wish to be accessible from a client
+application. If not specified, the operation defaults to `@auth(level: NO_ACCESS)`.
+
+Refer to [Data Connect Auth Guide](https://firebase.google.com/docs/data-connect/authorization-and-security) for the best practices.
+"""
+directive @auth(
+ """
+ The minimal level of access required to perform this operation.
+ Exactly one of `level` and `expr` should be specified.
+ """
+ level: AccessLevel @fdc_oneOf(required: true)
+ """
+ A CEL expression that grants access to this operation if the expression
+ evaluates to `true`.
+ Exactly one of `level` and `expr` should be specified.
+ """
+ expr: Boolean_Expr @fdc_oneOf(required: true)
+) on QUERY | MUTATION
+
+
+"""
+Require that this mutation always run in a DB transaction.
+
+Mutations with `@transaction` are guaranteed to either fully succeed or fully
+fail. If any of the fields within the transaction fails, the entire transaction
+is rolled back. From a client standpoint, any failure behaves as if the entire
+request had failed with a request error and execution had not begun.
+
+Mutations without `@transaction` would execute each root field one after
+another in sequence. It surfaces any errors as partial [field errors](https://spec.graphql.org/October2021/#sec-Errors.Field-errors),
+but not impacts the subsequent executions.
+
+The `@transaction` directive cannot be added to queries for now.
+Currently, queries cannot fail partially, the response data is not guaranteed
+to be a consistent snapshot.
+"""
+directive @transaction on MUTATION
+
+"Query filter criteria for `String` scalar fields."
+input String_Filter {
+ "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`."
+ isNull: Boolean
+ "Match if field is exactly equal to provided value."
+ eq: String @fdc_oneOf(group: "eq")
+ """
+ Match if field is exactly equal to the result of the provided server value
+ expression. Currently only `auth.uid` is supported as an expression.
+ """
+ eq_expr: String_Expr @fdc_oneOf(group: "eq")
+ "Match if field is not equal to provided value."
+ ne: String @fdc_oneOf(group: "ne")
+ """
+ Match if field is not equal to the result of the provided server value
+ expression. Currently only `auth.uid` is supported as an expression.
+ """
+ ne_expr: String_Expr @fdc_oneOf(group: "ne")
+ "Match if field value is among the provided list of values."
+ in: [String!]
+ "Match if field value is not among the provided list of values."
+ nin: [String!]
+ "Match if field value is greater than the provided value."
+ gt: String
+ "Match if field value is greater than or equal to the provided value."
+ ge: String
+ "Match if field value is less than the provided value."
+ lt: String
+ "Match if field value is less than or equal to the provided value."
+ le: String
+ """
+ Match if field value contains the provided value as a substring. Equivalent
+ to `LIKE '%value%'`
+ """
+ contains: String
+ """
+ Match if field value starts with the provided value. Equivalent to
+ `LIKE 'value%'`
+ """
+ startsWith: String
+ """
+ Match if field value ends with the provided value. Equivalent to
+ `LIKE '%value'`
+ """
+ endsWith: String
+ """
+ Match if field value matches the provided pattern. See `String_Pattern` for
+ more details.
+ """
+ pattern: String_Pattern
+}
+
+"""
+The pattern match condition on a string. Specify either like or regex.
+https://www.postgresql.org/docs/current/functions-matching.html
+"""
+input String_Pattern {
+ "Match using the provided `LIKE` expression."
+ like: String
+ "Match using the provided POSIX regular expression."
+ regex: String
+ "When true, ignore case when matching."
+ ignoreCase: Boolean
+ "When true, invert the match result. Equivalent to `NOT LIKE` or `!~`."
+ invert: Boolean
+}
+
+"Query filter criteris for `[String!]` scalar fields."
+input String_ListFilter {
+ "Match if list field contains the provided value as a member."
+ includes: String
+ "Match if list field does not contain the provided value as a member."
+ excludes: String
+ "Match if list field contains all of the provided values as members."
+ includesAll: [String!]
+ "Match if list field does not contain any of the provided values as members."
+ excludesAll: [String!]
+}
+
+"Query filter criteria for `UUID` scalar fields."
+input UUID_Filter {
+ "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`."
+ isNull: Boolean
+ "Match if field is exactly equal to provided value."
+ eq: UUID
+ "Match if field is not equal to provided value."
+ ne: UUID
+ "Match if field value is among the provided list of values."
+ in: [UUID!]
+ "Match if field value is not among the provided list of values."
+ nin: [UUID!]
+}
+
+"Query filter criteris for `[UUID!]` scalar fields."
+input UUID_ListFilter {
+ "Match if list field contains the provided value as a member."
+ includes: UUID
+ "Match if list field does not contain the provided value as a member."
+ excludes: UUID
+ "Match if list field contains all of the provided values as members."
+ includesAll: [UUID!]
+ "Match if list field does not contain any of the provided values as members."
+ excludesAll: [UUID!]
+}
+
+"Query filter criteria for `Int` scalar fields."
+input Int_Filter {
+ "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`."
+ isNull: Boolean
+ "Match if field is exactly equal to provided value."
+ eq: Int
+ "Match if field is not equal to provided value."
+ ne: Int
+ "Match if field value is among the provided list of values."
+ in: [Int!]
+ "Match if field value is not among the provided list of values."
+ nin: [Int!]
+ "Match if field value is greater than the provided value."
+ gt: Int
+ "Match if field value is greater than or equal to the provided value."
+ ge: Int
+ "Match if field value is less than the provided value."
+ lt: Int
+ "Match if field value is less than or equal to the provided value."
+ le: Int
+}
+
+"Query filter criteris for `[Int!]` scalar fields."
+input Int_ListFilter {
+ "Match if list field contains the provided value as a member."
+ includes: Int
+ "Match if list field does not contain the provided value as a member."
+ excludes: Int
+ "Match if list field contains all of the provided values as members."
+ includesAll: [Int!]
+ "Match if list field does not contain any of the provided values as members."
+ excludesAll: [Int!]
+}
+
+"Query filter criteria for `Int64` scalar fields."
+input Int64_Filter {
+ "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`."
+ isNull: Boolean
+ "Match if field is exactly equal to provided value."
+ eq: Int64
+ "Match if field is not equal to provided value."
+ ne: Int64
+ "Match if field value is among the provided list of values."
+ in: [Int64!]
+ "Match if field value is not among the provided list of values."
+ nin: [Int64!]
+ "Match if field value is greater than the provided value."
+ gt: Int64
+ "Match if field value is greater than or equal to the provided value."
+ ge: Int64
+ "Match if field value is less than the provided value."
+ lt: Int64
+ "Match if field value is less than or equal to the provided value."
+ le: Int64
+}
+
+"Query filter criteria for `[Int64!]` scalar fields."
+input Int64_ListFilter {
+ "Match if list field contains the provided value as a member."
+ includes: Int64
+ "Match if list field does not contain the provided value as a member."
+ excludes: Int64
+ "Match if list field contains all of the provided values as members."
+ includesAll: [Int64!]
+ "Match if list field does not contain any of the provided values as members."
+ excludesAll: [Int64!]
+}
+
+"Query filter criteria for `Float` scalar fields."
+input Float_Filter {
+ "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`."
+ isNull: Boolean
+ "Match if field is exactly equal to provided value."
+ eq: Float
+ "Match if field is not equal to provided value."
+ ne: Float
+ "Match if field value is among the provided list of values."
+ in: [Float!]
+ "Match if field value is not among the provided list of values."
+ nin: [Float!]
+ "Match if field value is greater than the provided value."
+ gt: Float
+ "Match if field value is greater than or equal to the provided value."
+ ge: Float
+ "Match if field value is less than the provided value."
+ lt: Float
+ "Match if field value is less than or equal to the provided value."
+ le: Float
+}
+
+"Query filter criteria for `[Float!]` scalar fields."
+input Float_ListFilter {
+ "Match if list field contains the provided value as a member."
+ includes: Float
+ "Match if list field does not contain the provided value as a member."
+ excludes: Float
+ "Match if list field contains all of the provided values as members."
+ includesAll: [Float!]
+ "Match if list field does not contain any of the provided values as members."
+ excludesAll: [Float!]
+}
+
+"Query filter criteria for `Boolean` scalar fields."
+input Boolean_Filter {
+ "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`."
+ isNull: Boolean
+ "Match if field is exactly equal to provided value."
+ eq: Boolean
+ "Match if field is not equal to provided value."
+ ne: Boolean
+ "Match if field value is among the provided list of values."
+ in: [Boolean!]
+ "Match if field value is not among the provided list of values."
+ nin: [Boolean!]
+}
+
+"Query filter criteria for `[Boolean!]` scalar fields."
+input Boolean_ListFilter {
+ "Match if list field contains the provided value as a member."
+ includes: Boolean
+ "Match if list field does not contain the provided value as a member."
+ excludes: Boolean
+ "Match if list field contains all of the provided values as members."
+ includesAll: [Boolean!]
+ "Match if list field does not contain any of the provided values as members."
+ excludesAll: [Boolean!]
+}
+
+"Query filter criteria for `Any` scalar fields."
+input Any_Filter {
+ "When true, match if field `IS NULL`. When false, match if field is `NOT NULL`."
+ isNull: Boolean
+ "Match if field is exactly equal to provided value."
+ eq: Any
+ "Match if field is not equal to provided value."
+ ne: Any
+ "Match if field value is among the provided list of values."
+ in: [Any!]
+ "Match if field value is not among the provided list of values."
+ nin: [Any!]
+}
+
+"Query filter criteria for `[Any!]` scalar fields."
+input Any_ListFilter {
+ "Match if list field contains the provided value as a member."
+ includes: Any
+ "Match if list field does not contain the provided value as a member."
+ excludes: Any
+ "Match if list field contains all of the provided values as members."
+ includesAll: [Any!]
+ "Match if list field does not contain any of the provided values as members."
+ excludesAll: [Any!]
+}
+
+"""
+(Internal) A string that uniquely identifies a type, field, and so on.
+
+The most common usage in FDC is `SomeType` or `SomeType.someField`. See the
+linked page in the @specifiedBy directive for the GraphQL RFC with more details.
+"""
+scalar SchemaCoordinate
+ @specifiedBy(url: "https://github.com/graphql/graphql-wg/blob/6d02705dea034fb65ebc6799632adb7bd550d0aa/rfcs/SchemaCoordinates.md")
+ @fdc_forbiddenAsFieldType
+ @fdc_forbiddenAsVariableType
+
+"(Internal) The purpose of a generated type or field."
+enum GeneratedPurpose {
+ # Implicit fields added to the table types as columns.
+ IMPLICIT_KEY_FIELD
+ IMPLICIT_REF_FIELD
+
+ # Relational non-column fields extended to table types.
+ QUERY_MULTIPLE_ONE_TO_MANY
+ QUERY_MULTIPLE_MANY_TO_MANY
+
+ # Top-level Query fields.
+ QUERY_SINGLE
+ QUERY_MULTIPLE
+ QUERY_MULTIPLE_BY_SIMILARITY
+
+ # Top-level Mutation fields.
+ INSERT_SINGLE
+ INSERT_MULTIPLE
+ UPSERT_SINGLE
+ UPSERT_MULTIPLE
+ UPDATE_SINGLE
+ UPDATE_MULTIPLE
+ DELETE_SINGLE
+ DELETE_MULTIPLE
+}
+
+"(Internal) Added to definitions generated by FDC."
+directive @fdc_generated(
+ "The source type or field that causes this definition to be generated."
+ from: SchemaCoordinate!
+ "The reason why this definition is generated, such as the intended use case."
+ purpose: GeneratedPurpose!
+) on
+ | SCALAR
+ | OBJECT
+ | FIELD_DEFINITION
+ | ARGUMENT_DEFINITION
+ | INTERFACE
+ | UNION
+ | ENUM
+ | ENUM_VALUE
+ | INPUT_OBJECT
+ | INPUT_FIELD_DEFINITION
+
+type _Service {
+ "Full Service Definition Language of the Frebase Data Connect Schema, including normalized schema, predefined and generated types."
+ sdl(
+ """
+ Whether or not to omit Data Connect builtin GraphQL preludes.
+ They are static GraphQL publically available in the docsite.
+ """
+ omitBuiltin: Boolean = false
+ """
+ Whether or not to omit GQL description in the SDL.
+ We generate description to document generated schema.
+ It may bloat the size of SDL.
+ """
+ omitDescription: Boolean = false
+ ): String!
+ "Orignal Schema Sources in the service."
+ schema: String!
+ "Generated documentation from the schema of the Firebase Data Connect Service."
+ docs: [_Doc!]!
+}
+
+type _Doc {
+ "Name of the Doc Page."
+ page: String!
+ "The markdown content of the doc page."
+ markdown: String!
+}
+
+"(Internal) Added to things that may be removed from FDC and will soon be no longer usable in schema or operations."
+directive @fdc_deprecated(reason: String = "No longer supported") on
+ | SCHEMA
+ | SCALAR
+ | OBJECT
+ | FIELD_DEFINITION
+ | ARGUMENT_DEFINITION
+ | INTERFACE
+ | UNION
+ | ENUM
+ | ENUM_VALUE
+ | INPUT_OBJECT
+ | INPUT_FIELD_DEFINITION
+
+"(Internal) Added to scalars representing quoted CEL expressions."
+directive @fdc_celExpression(
+ "The expected CEL type that the expression should evaluate to."
+ returnType: String
+) on SCALAR
+
+"(Internal) Added to scalars representing quoted SQL expressions."
+directive @fdc_sqlExpression(
+ "The expected SQL type that the expression should evaluate to."
+ dataType: String
+) on SCALAR
+
+"(Internal) Added to types that may not be used as variables."
+directive @fdc_forbiddenAsVariableType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT
+
+"(Internal) Added to types that may not be used as fields in schema."
+directive @fdc_forbiddenAsFieldType on SCALAR | OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT
+
+"Provides a frequently used example for this type / field / argument."
+directive @fdc_example(
+ "A GraphQL literal value (verbatim) whose type matches the target."
+ value: Any
+ "A human-readable text description of what `value` means in this context."
+ description: String
+) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | INPUT_OBJECT | INPUT_FIELD_DEFINITION
+
+"(Internal) Marks this field / argument as conflicting with others in the same group."
+directive @fdc_oneOf(
+ "The group name where fields / arguments conflict with each other."
+ group: String! = ""
+ "If true, exactly one field / argument in the group must be specified."
+ required: Boolean! = false
+) repeatable on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
+
+"""
+`UUID` is a string of hexadecimal digits representing an RFC4122-compliant UUID.
+
+UUIDs are always output as 32 lowercase hexadecimal digits without delimiters or
+curly braces.
+Inputs in the following formats are also accepted (case insensitive):
+
+- `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
+- `urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
+- `{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}`
+
+In the PostgreSQL table, it's stored as [`uuid`](https://www.postgresql.org/docs/current/datatype-uuid.html).
+"""
+scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")
+
+"""
+`Int64` is a scalar that represents a 64-bit signed integer.
+
+In the PostgreSQL table, it's stored as [`bigint`](https://www.postgresql.org/docs/current/datatype-numeric.html).
+
+On the wire, it's encoded as string because 64-bit integer exceeds the range of JSON number.
+"""
+scalar Int64
+
+"""
+The `Any` scalar type accommodates any valid [JSON value](https://www.json.org/json-en.html)
+(e.g., numbers, strings, booleans, arrays, objects). PostgreSQL efficiently
+stores this data as jsonb, providing flexibility for schemas with evolving structures.
+
+Caution: JSON doesn't distinguish Int and Float.
+
+##### Example:
+
+#### Schema
+
+```graphql
+type Movie @table {
+ name: String!
+ metadata: Any!
+}
+```
+
+#### Mutation
+
+Insert a movie with name and metadata from JSON literal.
+
+```graphql
+mutation InsertMovie {
+ movie_insert(
+ data: {
+ name: "The Dark Knight"
+ metadata: {
+ release_year: 2008
+ genre: ["Action", "Adventure", "Superhero"]
+ cast: [
+ { name: "Christopher Bale", age: 31 }
+ { name: "Heath Ledger", age: 28 }
+ ]
+ director: "Christopher Nolan"
+ }
+ }
+ )
+}
+```
+
+Insert a movie with name and metadata that's constructed from a few GQL variables.
+
+```graphql
+mutation InsertMovie($name: String!, $releaseDate: Date!, $genre: [String], $cast: [Any], $director: String!, $boxOfficeInUSD: Int) {
+ movie_insert(data: {
+ name: $name,
+ release_date: $releaseDate,
+ genre: $genre,
+ cast: $cast,
+ director: $director,
+ box_office: $boxOfficeInUSD
+ })
+}
+```
+**Note**:
+
+ - A mix of non-null and nullable variables can be provided.
+
+ - `Date!` can be passed into scalar `Any` as well! It's stored as string.
+
+ - `$cast` is a nested array. `[Any]` can represent an array of arbitrary types, but it won't enforce the input shape.
+
+#### Query
+
+Since `metadata` field has scalar `Any` type, it would return the full JSON in the response.
+
+**Note**: You can't define selection set to scalar based on [GraphQL spec](https://spec.graphql.org/October2021/#sec-Field-Selections).
+
+```graphql
+query GetAllMovies {
+ movies {
+ name
+ metadata
+ }
+}
+```
+
+"""
+scalar Any @specifiedBy(url: "https://www.json.org/json-en.html")
+
+"""
+The `Void` scalar type represents the absence of any value. It is typically used
+in operations where no value is expected in return.
+"""
+scalar Void
+
+"""
+The `True` scalar type only accepts the boolean value `true`.
+
+An optional field/argument typed as `True` may either be set
+to `true` or omitted (not provided at all). The values `false` or `null` are not
+accepted.
+"""
+scalar True
+ @fdc_forbiddenAsFieldType
+ @fdc_forbiddenAsVariableType
+ @fdc_example(value: true, description: "The only allowed value.")
+
+"""
+A Common Expression Language (CEL) expression that returns a boolean at runtime.
+
+This expression can reference the `auth` variable, which is null when Firebase
+Auth is not used. When Firebase Auth is used, the following fields are available:
+
+ - `auth.uid`: The current user ID.
+ - `auth.token`: A map containing all token fields (e.g., claims).
+
+"""
+scalar Boolean_Expr
+ @specifiedBy(url: "https://github.com/google/cel-spec")
+ @fdc_celExpression(returnType: "bool")
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+ @fdc_example(value: "auth != null", description: "Allow only if a Firebase Auth user is present.")
+
+"""
+A Common Expression Language (CEL) expression that returns a string at runtime.
+
+**Limitation**: Currently, only a limited set of expressions are supported.
+"""
+scalar String_Expr
+ @specifiedBy(url: "https://github.com/google/cel-spec")
+ @fdc_celExpression(returnType: "string")
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+ @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)")
+ @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) string, formatted as 32 lower-case hex digits without delimiters.")
+
+"""
+A Common Expression Language (CEL) expression that returns a UUID string at runtime.
+
+**Limitation**: Currently, only a limited set of expressions are supported.
+"""
+scalar UUID_Expr
+ @specifiedBy(url: "https://github.com/google/cel-spec")
+ @fdc_celExpression(returnType: "string")
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+ @fdc_example(value: "uuidV4()", description: "Generates a new random UUID (version 4) every time.")
+
+"""
+A Common Expression Language (CEL) expression whose return type is unspecified.
+
+**Limitation**: Only a limited set of expressions are currently supported for each
+type.
+"""
+scalar Any_Expr
+ @specifiedBy(url: "https://github.com/google/cel-spec")
+ @fdc_celExpression
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+ @fdc_example(value: "auth.uid", description: "The ID of the currently logged in user in Firebase Auth. (Errors if not logged in.)")
+ @fdc_example(value: "uuidV4()", description: "Generates a new random UUID version 4 (formatted as 32 lower-case hex digits without delimiters if result type is String).")
+ @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).")
+
+"""
+A PostgreSQL value expression whose return type is unspecified.
+"""
+scalar Any_SQL
+ @specifiedBy(url: "https://www.postgresql.org/docs/current/sql-expressions.html")
+ @fdc_sqlExpression
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+
+"""
+Defines a relational database table.
+
+In this example, we defined one table with a field named `myField`.
+
+```graphql
+type TableName @table {
+ myField: String
+}
+```
+Data Connect adds an implicit `id` primary key column. So the above schema is equivalent to:
+
+```graphql
+type TableName @table(key: "id") {
+ id: String @default(expr: "uuidV4()")
+ myField: String
+}
+```
+
+Data Connect generates the following SQL table and CRUD operations to use it.
+
+```sql
+CREATE TABLE "public"."table_name" (
+ "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
+ "my_field" text NULL,
+ PRIMARY KEY ("id")
+)
+```
+
+ * You can lookup a row: `query ($id: UUID!) { tableName(id: $id) { myField } } `
+ * You can find rows using: `query tableNames(limit: 20) { myField }`
+ * You can insert a row: `mutation { tableName_insert(data: {myField: "foo"}) }`
+ * You can update a row: `mutation ($id: UUID!) { tableName_update(id: $id, data: {myField: "bar"}) }`
+ * You can delete a row: `mutation ($id: UUID!) { tableName_delete(id: $id) }`
+
+##### Customizations
+
+- `@table(singular)` and `@table(plural)` can customize the singular and plural name.
+- `@table(name)` can customize the Postgres table name.
+- `@table(key)` can customize the primary key field name and type.
+
+For example, the `User` table often has a `uid` as its primary key.
+
+```graphql
+type User @table(key: "uid") {
+ uid: String!
+ name: String
+}
+```
+
+ * You can securely lookup a row: `query { user(key: {uid_expr: "auth.uid"}) { name } } `
+ * You can securely insert a row: `mutation { user_insert(data: {uid_expr: "auth.uid" name: "Fred"}) }`
+ * You can securely update a row: `mutation { user_update(key: {uid_expr: "auth.uid"}, data: {name: "New Name"}) }`
+ * You can securely delete a row: `mutation { user_delete(key: {uid_expr: "auth.uid"}) }`
+
+`@table` type can be configured further with:
+
+ - Custom SQL data types for columns. See `@col`.
+ - Add SQL indexes. See `@index`.
+ - Add SQL unique constraints. See `@unique`.
+ - Add foreign key constraints to define relations. See `@ref`.
+
+"""
+directive @table(
+ """
+ Configures the SQL database table name. Defaults to snake_case like `table_name`.
+ """
+ name: String
+ """
+ Configures the singular name. Defaults to the camelCase like `tableName`.
+ """
+ singular: String
+ """
+ Configures the plural name. Defaults to infer based on English plural pattern like `tableNames`.
+ """
+ plural: String
+ """
+ Defines the primary key of the table. Defaults to a single field named `id`.
+ If not present already, Data Connect adds an implicit field `id: UUID! @default(expr: "uuidV4()")`.
+ """
+ key: [String!]
+) on OBJECT
+
+"""
+Defines a relational database Raw SQLview.
+
+Data Connect generates GraphQL queries with WHERE and ORDER BY clauses.
+However, not all SQL features has native GraphQL equivalent.
+
+You can write **an arbitrary SQL SELECT statement**. Data Connect
+would map Graphql fields on `@view` type to columns in your SELECT statement.
+
+* Scalar GQL fields (camelCase) should match a SQL column (snake_case)
+ in the SQL SELECT statement.
+* Reference GQL field can point to another `@table` type. Similar to foreign key
+ defined with `@ref` on a `@table` type, a `@view` type establishes a relation
+ when `@ref(fields)` match `@ref(references)` on the target table.
+
+In this example, you can use `@view(sql)` to define an aggregation view on existing
+table.
+
+```graphql
+type User @table {
+ name: String
+ score: Int
+}
+type UserAggregation @view(sql: '''
+ SELECT
+ COUNT(*) as count,
+ SUM(score) as sum,
+ AVG(score) as average,
+ PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY score) AS median,
+ (SELECT id FROM "user" LIMIT 1) as example_id
+ FROM "user"
+''') {
+ count: Int
+ sum: Int
+ average: Float
+ median: Float
+ example: User
+ exampleId: UUID
+}
+```
+
+###### Example: Query Raw SQL View
+
+```graphql
+query {
+ userAggregations {
+ count sum average median
+ exampleId example { id }
+ }
+}
+```
+
+##### One-to-One View
+
+An one-to-one companion `@view` can be handy if you want to argument a `@table`
+with additional implied content.
+
+```graphql
+type Restaurant @table {
+ name: String!
+}
+type Review @table {
+ restaurant: Restaurant!
+ rating: Int!
+}
+type RestaurantStats @view(sql: '''
+ SELECT
+ restaurant_id,
+ COUNT(*) AS review_count,
+ AVG(rating) AS average_rating
+ FROM review
+ GROUP BY restaurant_id
+''') {
+ restaurant: Restaurant @unique
+ reviewCount: Int
+ averageRating: Float
+}
+```
+
+In this example, `@unique` convey the assumption that each `Restaurant` should
+have only one `RestaurantStats` object.
+
+###### Example: Query One-to-One View
+
+```graphql
+query ListRestaurants {
+ restaurants {
+ name
+ stats: restaurantStats_on_restaurant {
+ reviewCount
+ averageRating
+ }
+ }
+}
+```
+
+###### Example: Filter based on One-to-One View
+
+```graphql
+query BestRestaurants($minAvgRating: Float, $minReviewCount: Int) {
+ restaurants(where: {
+ restaurantStats_on_restaurant: {
+ averageRating: {ge: $minAvgRating}
+ reviewCount: {ge: $minReviewCount}
+ }
+ }) { name }
+}
+```
+
+##### Customizations
+
+- One of `@view(sql)` or `@view(name)` should be defined.
+ `@view(name)` can refer to a persisted SQL view in the Postgres schema.
+- `@view(singular)` and `@view(plural)` can customize the singular and plural name.
+
+`@view` type can be configured further:
+
+ - `@unique` lets you define one-to-one relation.
+ - `@col` lets you customize SQL column mapping. For example, `@col(name: "column_in_select")`.
+
+##### Limitations
+
+Raw SQL view doesn't have a primary key, so it doesn't support lookup. Other
+`@table` or `@view` cannot have `@ref` to a view either.
+
+View cannot be mutated. You can perform CRUD operations on the underlying
+table to alter its content.
+
+**Important: Data Connect doesn't parse and validate SQL**
+
+- If the SQL view is invalid or undefined, related requests may fail.
+- If the SQL view return incompatible types. Firebase Data Connect may surface
+ errors.
+- If a field doesn't have a corresponding column in the SQL SELECT statement,
+ it will always be `null`.
+- There is no way to ensure VIEW to TABLE `@ref` constraint.
+- All fields must be nullable in case they aren't found in the SELECT statement
+ or in the referenced table.
+
+**Important: You should always test `@view`!**
+
+"""
+directive @view(
+ """
+ The SQL view name. If neither `name` nor `sql` are provided, defaults to the
+ snake_case of the singular type name.
+ `name` and `sql` cannot be specified at the same time.
+ """
+ name: String @fdc_oneOf
+ """
+ SQL `SELECT` statement used as the basis for this type.
+ SQL SELECT columns should use snake_case. GraphQL fields should use camelCase.
+ `name` and `sql` cannot be specified at the same time.
+ """
+ sql: String @fdc_oneOf
+ """
+ Configures the singular name. Defaults to the camelCase like `viewName`.
+ """
+ singular: String
+ """
+ Configures the plural name. Defaults to infer based on English plural pattern like `viewNames`.
+ """
+ plural: String
+) on OBJECT
+
+"""
+Customizes a field that represents a SQL database table column.
+
+Data Connect maps scalar Fields on `@table` type to a SQL column of
+corresponding data type.
+
+- scalar `UUID` maps to [`uuid`](https://www.postgresql.org/docs/current/datatype-uuid.html).
+- scalar `String` maps to [`text`](https://www.postgresql.org/docs/current/datatype-character.html).
+- scalar `Int` maps to [`int`](https://www.postgresql.org/docs/current/datatype-numeric.html).
+- scalar `Int64` maps to [`bigint`](https://www.postgresql.org/docs/current/datatype-numeric.html).
+- scalar `Float` maps to [`double precision`](https://www.postgresql.org/docs/current/datatype-numeric.html).
+- scalar `Boolean` maps to [`boolean`](https://www.postgresql.org/docs/current/datatype-boolean.html).
+- scalar `Date` maps to [`date`](https://www.postgresql.org/docs/current/datatype-datetime.html).
+- scalar `Timestamp` maps to [`timestamptz`](https://www.postgresql.org/docs/current/datatype-datetime.html).
+- scalar `Any` maps to [`jsonb`](https://www.postgresql.org/docs/current/datatype-json.html).
+- scalar `Vector` maps to [`pgvector`](https://github.com/pgvector/pgvector).
+
+Array scalar fields are mapped to [Postgres arrays](https://www.postgresql.org/docs/current/arrays.html).
+
+###### Example: Serial Primary Key
+
+For example, you can define auto-increment primary key.
+
+```graphql
+type Post @table {
+ id: Int! @col(name: "post_id", dataType: "serial")
+}
+```
+
+Data Connect converts it to the following SQL table schema.
+
+```sql
+CREATE TABLE "public"."post" (
+ "post_id" serial NOT NULL,
+ PRIMARY KEY ("id")
+)
+```
+
+###### Example: Vector
+
+```graphql
+type Post @table {
+ content: String! @col(name: "post_content")
+ contentEmbedding: Vector! @col(size:768)
+}
+```
+
+"""
+directive @col(
+ """
+ The SQL database column name. Defaults to snake_case of the field name.
+ """
+ name: String
+ """
+ Configures the custom SQL data type.
+
+ Each GraphQL type can map to multiple SQL data types.
+ Refer to [Postgres supported data types](https://www.postgresql.org/docs/current/datatype.html).
+
+ Incompatible SQL data type will lead to undefined behavior.
+ """
+ dataType: String
+ """
+ Required on `Vector` columns. It specifies the length of the Vector.
+ `textembedding-gecko@003` model generates `Vector` of `@col(size:768)`.
+ """
+ size: Int
+) on FIELD_DEFINITION
+
+
+"""
+Defines a foreign key reference to another table.
+
+For example, we can define a many-to-one relation.
+
+```graphql
+type ManyTable @table {
+ refField: OneTable!
+}
+type OneTable @table {
+ someField: String!
+}
+```
+Data Connect adds implicit foreign key column and relation query field. So the
+above schema is equivalent to the following schema.
+
+```graphql
+type ManyTable @table {
+ id: UUID! @default(expr: "uuidV4()")
+ refField: OneTable! @ref(fields: "refFieldId", references: "id")
+ refFieldId: UUID!
+}
+type OneTable @table {
+ id: UUID! @default(expr: "uuidV4()")
+ someField: UUID!
+ # Generated Fields:
+ # manyTables_on_refField: [ManyTable!]!
+}
+```
+Data Connect generates the necessary foreign key constraint.
+
+```graphql
+CREATE TABLE "public"."many_table" (
+ "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
+ "ref_field_id" uuid NOT NULL,
+ PRIMARY KEY ("id"),
+ CONSTRAINT "many_table_ref_field_id_fkey" FOREIGN KEY ("ref_field_id") REFERENCES "public"."one_table" ("id") ON DELETE CASCADE
+)
+```
+
+###### Example: Traverse the Reference Field
+
+```graphql
+query ($id: UUID!) {
+ manyTable(id: $id) {
+ refField { id }
+ }
+}
+```
+
+###### Example: Reverse Traverse the Reference field
+
+```graphql
+query ($id: UUID!) {
+ oneTable(id: $id) {
+ manyTables_on_refField { id }
+ }
+}
+```
+
+##### Optional Many-to-One Relation
+
+An optional foreign key reference will be set to null if the referenced row is deleted.
+
+In this example, if a `User` is deleted, the `assignee` and `reporter`
+references will be set to null.
+
+```graphql
+type Bug @table {
+ title: String!
+ assignee: User
+ reproter: User
+}
+
+type User @table { name: String! }
+```
+
+##### Required Many-to-One Relation
+
+A required foreign key reference will cascade delete if the referenced row is
+deleted.
+
+In this example, if a `Post` is deleted, associated comments will also be
+deleted.
+
+```graphql
+type Comment @table {
+ post: Post!
+ content: String!
+}
+
+type Post @table { title: String! }
+```
+
+##### Many To Many Relation
+
+You can define a many-to-many relation with a join table.
+
+```graphql
+type Membership @table(key: ["group", "user"]) {
+ group: Group!
+ user: User!
+ role: String! @default(value: "member")
+}
+
+type Group @table { name: String! }
+type User @table { name: String! }
+```
+
+When Data Connect sees a table with two reference field as its primary key, it
+knows this is a join table, so expands the many-to-many query field.
+
+```graphql
+type Group @table {
+ name: String!
+ # Generated Fields:
+ # users_via_Membership: [User!]!
+ # memberships_on_group: [Membership!]!
+}
+type User @table {
+ name: String!
+ # Generated Fields:
+ # groups_via_Membership: [Group!]!
+ # memberships_on_user: [Membership!]!
+}
+```
+
+###### Example: Traverse the Many-To-Many Relation
+
+```graphql
+query ($id: UUID!) {
+ group(id: $id) {
+ users: users_via_Membership {
+ name
+ }
+ }
+}
+```
+
+###### Example: Traverse to the Join Table
+
+```graphql
+query ($id: UUID!) {
+ group(id: $id) {
+ memberships: memberships_on_group {
+ user { name }
+ role
+ }
+ }
+}
+```
+
+##### One To One Relation
+
+You can even define a one-to-one relation with the help of `@unique` or `@table(key)`.
+
+```graphql
+type User @table {
+ name: String
+}
+type Account @table {
+ user: User! @unique
+}
+# Alternatively, use primary key constraint.
+# type Account @table(key: "user") {
+# user: User!
+# }
+```
+
+###### Example: Transerse the Reference Field
+
+```graphql
+query ($id: UUID!) {
+ account(id: $id) {
+ user { id }
+ }
+}
+```
+
+###### Example: Reverse Traverse the Reference field
+
+```graphql
+query ($id: UUID!) {
+ user(id: $id) {
+ account_on_user { id }
+ }
+}
+```
+
+##### Customizations
+
+- `@ref(constraintName)` can customize the SQL foreign key constraint name (`table_name_ref_field_fkey` above).
+- `@ref(fields)` can customize the foreign key field names.
+- `@ref(references)` can customize the constraint to reference other columns.
+ By default, `@ref(references)` is the primary key of the `@ref` table.
+ Other fields with `@unique` may also be referred in the foreign key constraint.
+
+"""
+directive @ref(
+ "The SQL database foreign key constraint name. Defaults to snake_case `{table_name}_{field_name}_fkey`."
+ constraintName: String
+ """
+ Foreign key fields. Defaults to `{tableName}{PrimaryIdName}`.
+ """
+ fields: [String!]
+ "The fields that the foreign key references in the other table. Defaults to its primary key."
+ references: [String!]
+) on FIELD_DEFINITION
+
+"Defines the orderBy direction in a query."
+enum OrderDirection {
+"Results are ordered in ascending order."
+ ASC
+"Results are ordered in descending order."
+ DESC
+}
+
+"""
+Specifies the default value for a column field.
+
+For example:
+
+```graphql
+type User @table(key: "uid") {
+ uid: String! @default(expr: "auth.uid")
+ number: Int! @col(dataType: "serial")
+ createdAt: Date! @default(expr: "request.time")
+ role: String! @default(value: "Member")
+ credit: Int! @default(value: 100)
+}
+```
+
+The supported arguments vary based on the field type.
+"""
+directive @default(
+ "A constant value validated against the field's GraphQL type during compilation."
+ value: Any @fdc_oneOf(required: true)
+ "A CEL expression whose return value must match the field's data type."
+ expr: Any_Expr @fdc_oneOf(required: true)
+ """
+ A raw SQL expression, whose SQL data type must match the underlying column.
+
+ The value is any variable-free expression (in particular, cross-references to
+ other columns in the current table are not allowed). Subqueries are not allowed either.
+ See [PostgreSQL defaults](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-DEFAULT)
+ for more details.
+ """
+ sql: Any_SQL @fdc_oneOf(required: true)
+) on FIELD_DEFINITION
+
+"""
+Defines a database index to optimize query performance.
+
+```graphql
+type User @table @index(fields: ["name", "phoneNumber"], order: [ASC, DESC]) {
+ name: String @index
+ phoneNumber: Int64 @index
+ tags: [String] @index # GIN Index
+}
+```
+
+##### Single Field Index
+
+You can put `@index` on a `@col` field to create a SQL index.
+
+`@index(order)` matters little for single field indexes, as they can be scanned
+in both directions.
+
+##### Composite Index
+
+You can put `@index(fields: [...])` on `@table` type to define composite indexes.
+
+`@index(order: [...])` can customize the index order to satisfy particular
+filter and order requirement.
+
+"""
+directive @index(
+ """
+ Configure the SQL database index id.
+
+ If not overridden, Data Connect generates the index name:
+ - `{table_name}_{first_field}_{second_field}_aa_idx`
+ - `{table_name}_{field_name}_idx`
+ """
+ name: String
+ """
+ Only allowed and required when used on a `@table` type.
+ Specifies the fields to create the index on.
+ """
+ fields: [String!]
+ """
+ Only allowed for `BTREE` `@index` on `@table` type.
+ Specifies the order for each indexed column. Defaults to all `ASC`.
+ """
+ order: [IndexFieldOrder!]
+ """
+ Customize the index type.
+
+ For most index, it defaults to `BTREE`.
+ For array fields, only allowed `IndexType` is `GIN`.
+ For `Vector` fields, defaults to `HNSW`, may configure to `IVFFLAT`.
+ """
+ type: IndexType
+ """
+ Only allowed when used on vector field.
+ Defines the vector similarity method. Defaults to `INNER_PRODUCT`.
+ """
+ vector_method: VectorSimilarityMethod
+) repeatable on FIELD_DEFINITION | OBJECT
+
+"Specifies the sorting order for database indexes."
+enum IndexFieldOrder {
+ "Sorts the field in ascending order (from lowest to highest)."
+ ASC
+ "Sorts the field in descending order (from highest to lowest)."
+ DESC
+}
+
+"Defines the type of index to be used in the database."
+enum IndexType {
+ "A general-purpose index type commonly used for sorting and searching."
+ BTREE
+ "Generalized Inverted Index, optimized for indexing composite values such as arrays."
+ GIN
+ "Hierarchical Navigable Small World graph, used for nearest-neighbor searches on vector fields."
+ HNSW
+ "Inverted File Index, optimized for approximate nearest-neighbor searches in vector databases."
+ IVFFLAT
+}
+
+"""
+Defines unique constraints on `@table`.
+
+For example,
+
+```graphql
+type User @table {
+ phoneNumber: Int64 @unique
+}
+type UserProfile @table {
+ user: User! @unique
+ address: String @unique
+}
+```
+
+- `@unique` on a `@col` field adds a single-column unique constraint.
+- `@unique` on a `@table` type adds a composite unique constraint.
+- `@unique` on a `@ref` defines a one-to-one relation. It adds unique constraint
+ on `@ref(fields)`.
+
+`@unique` ensures those fields can uniquely identify a row, so other `@table`
+type may define `@ref(references)` to refer to fields that has a unique constraint.
+
+"""
+directive @unique(
+ """
+ Configures the SQL database unique constraint name.
+
+ If not overridden, Data Connect generates the unique constraint name:
+ - `table_name_first_field_second_field_uidx`
+ - `table_name_only_field_name_uidx`
+ """
+ indexName: String
+ """
+ Only allowed and required when used on OBJECT,
+ this specifies the fields to create a unique constraint on.
+ """
+ fields: [String!]
+) repeatable on FIELD_DEFINITION | OBJECT
+
+"""
+Date is a string in the YYYY-MM-DD format representing a local-only date.
+
+See the description for Timestamp for range and limitations.
+
+As a FDC-specific extension, inputs that includes time portions (as specified by
+the Timestamp scalar) are accepted but only the date portion is used. In other
+words, only the part before "T" is used and the rest discarded. This effectively
+truncates it to the local date in the specified time-zone.
+
+Outputs will always be in the canonical YYYY-MM-DD format.
+
+In the PostgreSQL table, it's stored as [`date`](https://www.postgresql.org/docs/current/datatype-datetime.html).
+"""
+scalar Date @specifiedBy(url: "https://scalars.graphql.org/andimarek/local-date.html")
+
+"""
+Timestamp is a RFC 3339 string that represents an exact point in time.
+
+The serialization format follows https://scalars.graphql.org/andimarek/date-time
+except the "Non-optional exact milliseconds" Section. As a FDC-specific
+extension, inputs and outputs may contain 0, 3, 6, or 9 fractional digits.
+
+Specifically, output precision varies by server-side factors such as data source
+support and clients must not rely on an exact number of digits. Clients may
+truncate extra digits as fit, with the caveat that there may be information loss
+if the truncated value is subsequently sent back to the server.
+
+FDC only supports year 1583 to 9999 (inclusive) and uses the ISO-8601 calendar
+system for all date-time calculations. Notably, the expanded year representation
+(+/-YYYYY) is rejected and Year 1582 and before may either be rejected or cause
+undefined behavior.
+
+In the PostgreSQL table, it's stored as [`timestamptz`](https://www.postgresql.org/docs/current/datatype-datetime.html).
+"""
+scalar Timestamp @specifiedBy(url: "https://scalars.graphql.org/andimarek/date-time")
+
+"""
+A Common Expression Language (CEL) expression that returns a Timestamp at runtime.
+
+Limitation: Right now, only a few expressions are supported.
+"""
+scalar Timestamp_Expr
+ @specifiedBy(url: "https://github.com/google/cel-spec")
+ @fdc_celExpression(returnType: "google.protobuf.Timestamp")
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+ @fdc_example(value: "request.time", description: "The timestamp when the request is received (with microseconds precision).")
+
+"""
+A Common Expression Language (CEL) expression that returns a Timestamp at runtime,
+which is then truncated to UTC date only. The time-of-day parts are discarded.
+
+Limitation: Right now, only a few expressions are supported.
+"""
+scalar Date_Expr
+ @specifiedBy(url: "https://github.com/google/cel-spec")
+ @fdc_celExpression(returnType: "google.protobuf.Timestamp")
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+ @fdc_example(value: "request.time", description: "The UTC date on which the request is received.")
+
+"Conditions on a `Date` value."
+input Date_Filter {
+ "Match if the field `IS NULL`."
+ isNull: Boolean
+ "Match if the field is exactly equal to the provided value."
+ eq: Date @fdc_oneOf(group: "eq")
+ "Match if the field equals the provided CEL expression."
+ eq_expr: Date_Expr @fdc_oneOf(group: "eq")
+ "Match if the field equals the provided relative date."
+ eq_date: Date_Relative @fdc_oneOf(group: "eq")
+ "Match if the field is not equal to the provided value."
+ ne: Date @fdc_oneOf(group: "ne")
+ "Match if the field is not equal to the provided CEL expression."
+ ne_expr: Date_Expr @fdc_oneOf(group: "ne")
+ "Match if the field is not equal to the provided relative date."
+ ne_date: Date_Relative @fdc_oneOf(group: "ne")
+ "Match if the field value is among the provided list of values."
+ in: [Date!]
+ "Match if the field value is not among the provided list of values."
+ nin: [Date!]
+ "Match if the field value is greater than the provided value."
+ gt: Date @fdc_oneOf(group: "gt")
+ "Match if the field value is greater than the provided CEL expression."
+ gt_expr: Date_Expr @fdc_oneOf(group: "gt")
+ "Match if the field value is greater than the provided relative date."
+ gt_date: Date_Relative @fdc_oneOf(group: "gt")
+ "Match if the field value is greater than or equal to the provided value."
+ ge: Date @fdc_oneOf(group: "ge")
+ "Match if the field value is greater than or equal to the provided CEL expression."
+ ge_expr: Date_Expr @fdc_oneOf(group: "ge")
+ "Match if the field value is greater than or equal to the provided relative date."
+ ge_date: Date_Relative @fdc_oneOf(group: "ge")
+ "Match if the field value is less than the provided value."
+ lt: Date @fdc_oneOf(group: "lt")
+ "Match if the field value is less than the provided CEL expression."
+ lt_expr: Date_Expr @fdc_oneOf(group: "lt")
+ "Match if the field value is less than the provided relative date."
+ lt_date: Date_Relative @fdc_oneOf(group: "lt")
+ "Match if the field value is less than or equal to the provided value."
+ le: Date @fdc_oneOf(group: "le")
+ "Match if the field value is less than or equal to the provided CEL expression."
+ le_expr: Date_Expr @fdc_oneOf(group: "le")
+ "Match if the field value is less than or equal to the provided relative date."
+ le_date: Date_Relative @fdc_oneOf(group: "le")
+}
+
+"Conditions on a`Date` list."
+input Date_ListFilter {
+ "Match if the list contains the provided date."
+ includes: Date @fdc_oneOf(group: "includes")
+ "Match if the list contains the provided date CEL expression."
+ includes_expr: Date_Expr @fdc_oneOf(group: "includes")
+ "Match if the list contains the provided relative date."
+ includes_date: Date_Relative @fdc_oneOf(group: "includes")
+ "Match if the list does not contain the provided date."
+ excludes: Date @fdc_oneOf(group: "excludes")
+ "Match if the list does not contain the provided date CEL expression."
+ excludes_expr: Date_Expr @fdc_oneOf(group: "excludes")
+ "Match if the list does not contain the provided relative date."
+ excludes_date: Date_Relative @fdc_oneOf(group: "excludes")
+ "Match if the list contains all the provided dates."
+ includesAll: [Date!]
+ "Match if the list contains none of the provided dates."
+ excludesAll: [Date!]
+}
+
+"Conditions on a `Timestamp` value."
+input Timestamp_Filter {
+ "Match if the field `IS NULL`."
+ isNull: Boolean
+ "Match if the field is exactly equal to the provided value."
+ eq: Timestamp @fdc_oneOf(group: "eq")
+ "Match if the field equals the provided CEL expression."
+ eq_expr: Timestamp_Expr @fdc_oneOf(group: "eq")
+ "Match if the field equals the provided relative time."
+ eq_time: Timestamp_Relative @fdc_oneOf(group: "eq")
+ "Match if the field is not equal to the provided value."
+ ne: Timestamp @fdc_oneOf(group: "ne")
+ "Match if the field is not equal to the provided CEL expression."
+ ne_expr: Timestamp_Expr @fdc_oneOf(group: "ne")
+ "Match if the field is not equal to the provided relative time."
+ ne_time: Timestamp_Relative @fdc_oneOf(group: "ne")
+ "Match if the field value is among the provided list of values."
+ in: [Timestamp!]
+ "Match if the field value is not among the provided list of values."
+ nin: [Timestamp!]
+ "Match if the field value is greater than the provided value."
+ gt: Timestamp @fdc_oneOf(group: "gt")
+ "Match if the field value is greater than the provided CEL expression."
+ gt_expr: Timestamp_Expr @fdc_oneOf(group: "gt")
+ "Match if the field value is greater than the provided relative time."
+ gt_time: Timestamp_Relative @fdc_oneOf(group: "gt")
+ "Match if the field value is greater than or equal to the provided value."
+ ge: Timestamp @fdc_oneOf(group: "ge")
+ "Match if the field value is greater than or equal to the provided CEL expression."
+ ge_expr: Timestamp_Expr @fdc_oneOf(group: "ge")
+ "Match if the field value is greater than or equal to the provided relative time."
+ ge_time: Timestamp_Relative @fdc_oneOf(group: "ge")
+ "Match if the field value is less than the provided value."
+ lt: Timestamp @fdc_oneOf(group: "lt")
+ "Match if the field value is less than the provided CEL expression."
+ lt_expr: Timestamp_Expr @fdc_oneOf(group: "lt")
+ "Match if the field value is less than the provided relative time."
+ lt_time: Timestamp_Relative @fdc_oneOf(group: "lt")
+ "Match if the field value is less than or equal to the provided value."
+ le: Timestamp @fdc_oneOf(group: "le")
+ "Match if the field value is less than or equal to the provided CEL expression."
+ le_expr: Timestamp_Expr @fdc_oneOf(group: "le")
+ "Match if the field value is less than or equal to the provided relative time."
+ le_time: Timestamp_Relative @fdc_oneOf(group: "le")
+}
+
+"Conditions on a `Timestamp` list."
+input Timestamp_ListFilter {
+ "Match if the list contains the provided timestamp."
+ includes: Timestamp @fdc_oneOf(group: "includes")
+ "Match if the list contains the provided timestamp CEL expression."
+ includes_expr: Timestamp_Expr @fdc_oneOf(group: "includes")
+ "Match if the list contains the provided relative timestamp."
+ includes_time: Timestamp_Relative @fdc_oneOf(group: "includes")
+ "Match if the list does not contain the provided timestamp."
+ excludes: Timestamp @fdc_oneOf(group: "excludes")
+ "Match if the list does not contain the provided timestamp CEL expression."
+ excludes_expr: Timestamp_Expr @fdc_oneOf(group: "excludes")
+ "Match if the list does not contain the provided relative timestamp."
+ excludes_time: Timestamp_Relative @fdc_oneOf(group: "excludes")
+ "Match if the list contains all the provided timestamps."
+ includesAll: [Timestamp!]
+ "Match if the list contains none of the provided timestamps."
+ excludesAll: [Timestamp!]
+}
+
+"Update input of a `Date` value."
+input Date_Update {
+ "Set the field to the provided date."
+ set: Date @fdc_oneOf(group: "set")
+ "Set the field to the provided date CEL expression."
+ set_expr: Date_Expr @fdc_oneOf(group: "set")
+ "Set the field to the provided relative date."
+ set_date: Date_Relative @fdc_oneOf(group: "set")
+}
+
+"Update input of a `Date` list value."
+input Date_ListUpdate {
+ "Replace the current list with the provided list of `Date` values."
+ set: [Date!]
+ "Append the provided `Date` values to the existing list."
+ append: [Date!]
+ "Prepend the provided `Date` values to the existing list."
+ prepend: [Date!]
+ "Remove the date value at the specified index."
+ delete: Int
+ "The index of the list to perform updates."
+ i: Int
+ "Update the date value at the specified index."
+ update: Date
+}
+
+"Update input of a `Timestamp` value."
+input Timestamp_Update {
+ "Set the field to the provided timestamp."
+ set: Timestamp @fdc_oneOf(group: "set")
+ "Set the field to the provided timestamp CEL expression."
+ set_expr: Timestamp_Expr @fdc_oneOf(group: "set")
+ "Set the field to the provided relative timestamp."
+ set_time: Timestamp_Relative @fdc_oneOf(group: "set")
+}
+
+"Update input of an `Timestamp` list value."
+input Timestamp_ListUpdate {
+ "Replace the current list with the provided list of `Timestamp` values."
+ set: [Timestamp!]
+ "Append the provided `Timestamp` values to the existing list."
+ append: [Timestamp!]
+ "Prepend the provided `Timestamp` values to the existing list."
+ prepend: [Timestamp!]
+ "Remove the timestamp value at the specified index."
+ delete: Int
+ "The index of the list to perform updates."
+ i: Int
+ "Update the timestamp value at the specified index."
+ update: Timestamp
+}
+
+
+"A runtime-calculated `Timestamp` value relative to `now` or `at`."
+input Timestamp_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+ "Match for the current time."
+ now: True @fdc_oneOf(group: "from", required: true)
+ "A specific timestamp for matching."
+ at: Timestamp @fdc_oneOf(group: "from", required: true)
+ "Add the provided duration to the base timestamp."
+ add: Timestamp_Duration
+ "Subtract the provided duration from the base timestamp."
+ sub: Timestamp_Duration
+ "Truncate the timestamp to the provided interval."
+ truncateTo: Timestamp_Interval
+}
+
+input Timestamp_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+ "The number of milliseconds for the duration."
+ milliseconds: Int! = 0
+ "The number of seconds for the duration."
+ seconds: Int! = 0
+ "The number of minutes for the duration."
+ minutes: Int! = 0
+ "The number of hours for the duration."
+ hours: Int! = 0
+ "The number of days for the duration."
+ days: Int! = 0
+ "The number of weeks for the duration."
+ weeks: Int! = 0
+ "The number of months for the duration."
+ months: Int! = 0
+ "The number of years for the duration."
+ years: Int! = 0
+}
+
+enum Timestamp_Interval @fdc_forbiddenAsFieldType {
+ "Represents a time interval of one second."
+ SECOND
+ "Represents a time interval of one minute."
+ MINUTE
+ "Represents a time interval of one hour."
+ HOUR
+ "Represents a time interval of one day."
+ DAY
+ "Represents a time interval of one week."
+ WEEK
+ "Represents a time interval of one month."
+ MONTH
+ "Represents a time interval of one year."
+ YEAR
+}
+
+"A runtime-calculated Date value relative to `today` or `on`."
+input Date_Relative @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+ "Match for today’s date."
+ today: True @fdc_oneOf(group: "from", required: true)
+ "A specific date for matching."
+ on: Date @fdc_oneOf(group: "from", required: true)
+ "Add the provided duration to the base date."
+ add: Date_Duration
+ "Subtract the provided duration from the base date."
+ sub: Date_Duration
+ "Truncate the date to the provided interval."
+ truncateTo: Date_Interval
+}
+
+input Date_Duration @fdc_forbiddenAsVariableType @fdc_forbiddenAsFieldType {
+ "The number of days for the duration."
+ days: Int! = 0
+ "The number of weeks for the duration."
+ weeks: Int! = 0
+ "The number of months for the duration."
+ months: Int! = 0
+ "The number of years for the duration."
+ years: Int! = 0
+}
+
+enum Date_Interval @fdc_forbiddenAsFieldType {
+ "Represents a time interval of one week."
+ WEEK
+ "Represents a time interval of one month."
+ MONTH
+ "Represents a time interval of one year."
+ YEAR
+}
+
+"Update input of a `String` value."
+input String_Update {
+ "Set the field to a provided value."
+ set: String @fdc_oneOf(group: "set")
+ "Set the field to a provided server value expression."
+ set_expr: String_Expr @fdc_oneOf(group: "set")
+}
+
+"Update input of a `String` list value."
+input String_ListUpdate {
+ "Set the list with the provided values."
+ set: [String!]
+ "Append the provided values to the existing list."
+ append: [String!]
+ "Prepend the provided values to the existing list."
+ prepend: [String!]
+}
+
+"Update input of a `UUID` value."
+input UUID_Update {
+ "Set the field to a provided UUID."
+ set: UUID @fdc_oneOf(group: "set")
+ "Set the field to a provided UUID expression."
+ set_expr: UUID_Expr @fdc_oneOf(group: "set")
+}
+
+"Update input of an `ID` list value."
+input UUID_ListUpdate {
+ "Set the list with the provided list of UUIDs."
+ set: [UUID!]
+ "Append the provided UUIDs to the existing list."
+ append: [UUID!]
+ "Prepend the provided UUIDs to the existing list."
+ prepend: [UUID!]
+}
+
+"Update input of an `Int` value."
+input Int_Update {
+ "Set the field to a provided value."
+ set: Int
+ "Increment the field by a provided value."
+ inc: Int
+ "Decrement the field by a provided value."
+ dec: Int
+}
+
+"Update input of an `Int` list value."
+input Int_ListUpdate {
+ "Set the list with the provided values."
+ set: [Int!]
+ "Append the provided list of values to the existing list."
+ append: [Int!]
+ "Prepend the provided list of values to the existing list."
+ prepend: [Int!]
+}
+
+"Update input of an `Int64` value."
+input Int64_Update {
+ "Set the field to a provided value."
+ set: Int64
+ "Increment the field by a provided value."
+ inc: Int64
+ "Decrement the field by a provided value."
+ dec: Int64
+}
+
+"Update input of an `Int64` list value."
+input Int64_ListUpdate {
+ "Replace the list with the provided values."
+ set: [Int64!]
+ "Append the provided list of values to the existing list."
+ append: [Int64!]
+ "Prepend the provided list of values to the existing list."
+ prepend: [Int64!]
+}
+
+"Update input of a `Float` value."
+input Float_Update {
+ "Set the field to a provided value."
+ set: Float
+ "Increment the field by a provided value."
+ inc: Float
+ "Decrement the field by a provided value."
+ dec: Float
+}
+
+"Update input of a `Float` list value."
+input Float_ListUpdate {
+ "Set the list with the provided values."
+ set: [Float!]
+ "Append the provided list of values to the existing list."
+ append: [Float!]
+ "Prepend the provided list of values to the existing list."
+ prepend: [Float!]
+}
+
+"Update input of a `Boolean` value."
+input Boolean_Update {
+ "Set the field to a provided value."
+ set: Boolean
+}
+
+"Update input of a `Boolean` list value."
+input Boolean_ListUpdate {
+ "Set the list with the provided values."
+ set: [Boolean!]
+ "Append the provided list of values to the existing list."
+ append: [Boolean!]
+ "Prepend the provided list of values to the existing list."
+ prepend: [Boolean!]
+}
+
+"Update input of an `Any` value."
+input Any_Update {
+ "Set the field to a provided value."
+ set: Any
+}
+
+"Update input of an `Any` list value."
+input Any_ListUpdate {
+ "Set the list with the provided values."
+ set: [Any!]
+ "Append the provided list of values to the existing list."
+ append: [Any!]
+ "Prepend the provided list of values to the existing list."
+ prepend: [Any!]
+}
+
+type Query {
+ """
+ _service provides customized introspection on Firebase Data Connect Sevice.
+ """
+ _service: _Service!
+}
+
+"""
+Vector is an array of single-precision floating-point numbers, serialized
+as a JSON array. All elements must be finite (no NaN, Infinity or -Infinity).
+
+Example: [1.1, 2, 3.3]
+
+In the PostgreSQL table, it's stored as [`pgvector`](https://github.com/pgvector/pgvector).
+
+See `Vector_Embed` for how to generate text embeddings in query and mutations.
+"""
+scalar Vector
+
+"""
+Defines the similarity function to use when comparing vectors in queries.
+
+Defaults to `INNER_PRODUCT`.
+
+View [all vector functions](https://github.com/pgvector/pgvector?tab=readme-ov-file#vector-functions).
+"""
+enum VectorSimilarityMethod {
+ "Measures the Euclidean (L2) distance between two vectors."
+ L2
+ "Measures the cosine similarity between two vectors."
+ COSINE
+ "Measures the inner product(dot product) between two vectors."
+ INNER_PRODUCT
+}
+
+"Conditions on a Vector value."
+input Vector_Filter {
+ "Match if the field is exactly equal to the provided vector."
+ eq: Vector
+ "Match if the field is not equal to the provided vector."
+ ne: Vector
+ "Match if the field value is among the provided list of vectors."
+ in: [Vector!]
+ "Match if the field value is not among the provided list of vectors."
+ nin: [Vector!]
+ "Match if the field is `NULL`."
+ isNull: Boolean
+}
+
+input Vector_ListFilter {
+ "Match if the list includes the supplied vector."
+ includes: Vector
+ "Match if the list does not include the supplied vector."
+ excludes: Vector
+ "Match if the list contains all the provided vectors."
+ includesAll: [Vector!]
+ "Match if the list contains none of the provided vectors."
+ excludesAll: [Vector!]
+}
+
+"Update input of a Vector value."
+input Vector_Update {
+ "Set the field to the provided vector value."
+ set: Vector @fdc_oneOf(group: "set")
+ "Set the field to the vector embedding result from a text input."
+ set_embed: Vector_Embed @fdc_oneOf(group: "set")
+}
+
+
+"Update input of a Vector list value."
+input Vector_ListUpdate {
+ "Replace the current list with the provided list of Vector values."
+ set: [Vector]
+ "Append the provided Vector values to the existing list."
+ append: [Vector]
+ "Prepend the provided Vector values to the existing list."
+ prepend: [Vector]
+ "Delete the vector at the specified index."
+ delete: Int
+ "The index of the vector to be updated."
+ i: Int
+ "Update the vector at the specified index."
+ update: Vector
+}
+
+"""
+Create a vector embedding of text using the given model on Vertex AI.
+
+Cloud SQL for Postgresql natively integrates with [Vertex AI Text embeddings API](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api)
+to effectively generate text embeddings.
+
+If you uses [`Vector`](scalar.md#Vector) in your schema, Firebase Data Connect automatically installs
+[`pgvector`](https://github.com/pgvector/pgvector) and [`google_ml_integration`](https://cloud.google.com/sql/docs/postgres/integrate-cloud-sql-with-vertex-ai)
+Postgres extensions in your Cloud SQL database.
+
+Given a Post table with a `Vector` embedding field.
+
+```graphql
+type Post @table {
+ content: String!
+ contentEmbedding: Vector @col(size:768)
+}
+```
+
+NOTE: All natively supported `Vector_Embed_Model` generates vector of length `768`.
+
+###### Example: Insert embedding
+
+```graphql
+mutation CreatePost($content: String!) {
+ post_insert(data: {
+ content: $content,
+ contentEmbedding_embed: {model: "textembedding-gecko@003", text: $content},
+ })
+}
+```
+
+###### Example: Vector similarity Search
+
+```graphql
+query SearchPost($query: String!) {
+ posts_contentEmbedding_similarity(compare_embed: {model: "textembedding-gecko@003", text: $query}) {
+ id
+ content
+ }
+}
+```
+"""
+input Vector_Embed @fdc_forbiddenAsVariableType {
+ """
+ The model to use for vector embedding.
+ Recommend the latest stable model: `textembedding-gecko@003`.
+ """
+ model: Vector_Embed_Model!
+ "The text to generate the vector embedding from."
+ text: String!
+}
+
+"""
+The Vertex AI model version that is required in input `Vector_Embed`.
+
+It is recommended to use the latest stable model version: `textembedding-gecko@003`.
+
+View all supported [Vertex AI Text embeddings APIs](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/text-embeddings-api).
+"""
+scalar Vector_Embed_Model
+ @specifiedBy(url: "https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versioning")
+ @fdc_forbiddenAsVariableType
+ @fdc_forbiddenAsFieldType
+ @fdc_example(value: "textembedding-gecko@003", description: "A stable version of the textembedding-gecko model")
+ @fdc_example(value: "textembedding-gecko@001", description: "An older version of the textembedding-gecko model")
+ @fdc_example(value: "text-embedding-004", description: "Another text embedding model")
+
+"""
+Redact a part of the response from the client.
+
+Redacted fields are still evaluated for side effects (including data changes and
+`@check`) and the results are still available to later steps in CEL expressions
+(via `response.fieldName`).
+"""
+directive @redact on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
+
+"""
+Ensure this field is present and is not null or `[]`, or abort the request / transaction.
+
+A CEL expression, `expr` is used to test the field value. It defaults to
+rejecting null and `[]` but a custom expression can be provided instead.
+
+If the field occurs multiple times (i.e. directly or indirectly nested under a
+list), `expr` will be executed once for each occurrence and `@check` succeeds if
+all values succeed. `@check` fails when the field is not present at all (i.e.
+all ancestor paths contain `null` or `[]`), unless `optional` is true.
+
+If a `@check` fails in a mutation, the top-level field containing it will be
+replaced with a partial error, whose message can be customzied via the `message`
+argument. Each subsequent top-level fields will return an aborted error (i.e.
+not executed). To rollback previous steps, see `@transaction`.
+"""
+directive @check(
+ """
+ The CEL expression to test the field value (or values if nested under a list).
+
+ Within the CEL expression, a special value `this` evaluates to the field that
+ this directive is attached to. If this field occurs multiple times because
+ any ancestor is a list, each occurrence is tested with `this` bound to each
+ value. When the field itself is a list or object, `this` follows the same
+ structure (including all decendants selected in case of objects).
+
+ For any given path, if an ancestor is `null` or `[]`, the field will not be
+ reached and the CEL evaluation will be skipped for that path. In other words,
+ evaluation only takes place when `this` is `null` or non-null, but never
+ undefined. (See also the `optional` argument.)
+ """
+ expr: Boolean_Expr! = "!(this in [null, []])"
+ """
+ The error message to return to the client if the check fails.
+
+ Defaults to "permission denied" if not specified.
+ """
+ message: String! = "permission denied"
+ """
+ Whether the check should pass or fail (default) when the field is not present.
+
+ A field will not be reached at a given path if its parent or any ancestor is
+ `[]` or `null`. When this happens to all paths, the field will not be present
+ anywhere in the response tree. In other words, `expr` is evaluated 0 times.
+ By default, @check will automatically fail in this case. Set this argument to
+ `true` to make it pass even if no tests are run (a.k.a. "vacuously true").
+ """
+ optional: Boolean = false
+) repeatable on QUERY | MUTATION | FIELD | FRAGMENT_DEFINITION | FRAGMENT_SPREAD | INLINE_FRAGMENT
+
+type Mutation {
+ """
+ Run a query during the mutation and add fields into the response.
+
+ Example: foo: query { users { id } } will add a field foo: {users: [{id: "..."}, …]} into the response JSON.
+
+ Note: Data fetched this way can be handy for permission checks. See @check.
+ """
+ query: Query
+}
+
diff --git a/dataconnect/flutter-movie/dataconnect/connector/connector.yaml b/dataconnect/flutter-movie/dataconnect/connector/connector.yaml
new file mode 100644
index 00000000..b1556370
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/connector/connector.yaml
@@ -0,0 +1,5 @@
+connectorId: movies
+generate:
+ dartSdk:
+ outputDir: ../../lib/movies_connector
+ package: movies_connector
diff --git a/dataconnect/flutter-movie/dataconnect/connector/mutations.gql b/dataconnect/flutter-movie/dataconnect/connector/mutations.gql
new file mode 100644
index 00000000..82a899a7
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/connector/mutations.gql
@@ -0,0 +1,102 @@
+mutation UpsertUser($username: String!) @auth(level: USER) {
+ user_upsert(
+ data: {
+ id_expr: "auth.uid"
+ username: $username
+ }
+ )
+}
+
+# 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 })
+}
+
+# Add a review for a movie
+mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
+@auth(level: USER) {
+ review_upsert(
+ data: {
+ userId_expr: "auth.uid"
+ movieId: $movieId
+ rating: $rating
+ reviewText: $reviewText
+ reviewDate_date: { today: true }
+ }
+ )
+}
+
+# Update a user's review for a movie
+mutation UpdateReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
+@auth(level: USER) {
+ review_update(
+ key: { userId_expr: "auth.uid", movieId: $movieId }
+ 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 })
+}
+
+# The mutations below are unused by the application, but are useful examples for more complex cases
+
+# Create a movie based on user input
+# mutation CreateMovie(
+# $title: String!
+# $releaseYear: Int!
+# $genre: String!
+# $rating: Float
+# $description: String
+# $imageUrl: String!
+# $tags: [String!] = []
+# ) @auth(expr: "auth.token.isAdmin == true") {
+
+# }
+# Update movie information based on the provided ID
+# mutation UpdateMovie(
+# $id: UUID!
+# $title: String
+# $releaseYear: Int
+# $genre: String
+# $rating: Float
+# $description: String
+# $imageUrl: String
+# $tags: [String!] = []
+# ) @auth(level: USER_EMAIL_VERIFIED) {
+# movie_update(
+# id: $id
+# data: {
+# title: $title
+# releaseYear: $releaseYear
+# genre: $genre
+# rating: $rating
+# description: $description
+# imageUrl: $imageUrl
+# tags: $tags
+# }
+# )
+# }
+
+# Delete a movie by its ID
+# mutation DeleteMovie($id: UUID!) @auth(level: USER_EMAIL_VERIFIED) {
+# movie_delete(id: $id)
+# }
+
+# Delete movies with a rating lower than the specified minimum rating
+# mutation DeleteUnpopularMovies($minRating: Float!) @auth(level: USER_EMAIL_VERIFIED) {
+# movie_deleteMany(where: { rating: { le: $minRating } })
+# }
+# End of example mutations
\ No newline at end of file
diff --git a/dataconnect/flutter-movie/dataconnect/connector/queries.gql b/dataconnect/flutter-movie/dataconnect/connector/queries.gql
new file mode 100644
index 00000000..f0904ba0
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/connector/queries.gql
@@ -0,0 +1,357 @@
+# 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
+ }
+}
+query ListMoviesByGenre($genre: String!, $orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
+ movies(where: {
+ genre: {
+ eq: $genre
+ }
+ }, orderBy: [
+ { rating: $orderByRating },
+ { releaseYear: $orderByReleaseYear }
+ ]
+ limit: $limit) {
+ id
+ title
+ imageUrl
+ releaseYear
+ genre
+ rating
+ tags
+ description
+ }
+}
+
+query ListGenres @auth(level: PUBLIC) {
+ genres {
+ genre
+ }
+}
+
+# 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
+ }
+ }
+}
+
+
+# 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
+ }
+ }
+ }
+ }
+}
+
+query GetMovieInfoForUser($movieId: UUID!) @auth(level: USER) {
+ favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
+ movieId
+ }
+}
+
+
+# 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
+ }
+ }
+}
+
+# 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
+# }
+# }
+
+
+
+# # The queries below are unused by the application, but are useful examples for more complex cases
+
+# List movies by partial title match
+query ListMoviesByPartialTitle($input: String!) @auth(level: PUBLIC) {
+ movies(where: { title: { contains: $input } }) {
+ id
+ title
+ genre
+ rating
+ imageUrl
+ description
+ }
+}
+
+# # List movies by tag
+# query ListMoviesByTag($tag: String!) @auth(level: PUBLIC) {
+# movies(where: { tags: { includes: $tag } }) {
+# id
+# title
+# imageUrl
+# genre
+# rating
+# }
+# }
+
+# # List movies by release year range
+# query MoviesByReleaseYear($min: Int, $max: Int) @auth(level: PUBLIC) {
+# movies(
+# where: { releaseYear: { le: $max, ge: $min } }
+# orderBy: { releaseYear: ASC }
+# ) {
+# id
+# rating
+# title
+# imageUrl
+# }
+# }
+
+# # List movies by rating and genre with OR filters
+# query SearchMovieOr(
+# $minRating: Float
+# $maxRating: Float
+# $genre: String
+# $tag: String
+# $input: String
+# ) @auth(level: PUBLIC) {
+# movies(
+# where: {
+# _or: [
+# { rating: { ge: $minRating } }
+# { rating: { le: $maxRating } }
+# { genre: { eq: $genre } }
+# { tags: { includes: $tag } }
+# { title: { contains: $input } }
+# ]
+# }
+# ) {
+# id
+# rating
+# title
+# imageUrl
+# }
+# }
+
+# # List movies by rating and genre with AND filters
+# query SearchMovieAnd(
+# $minRating: Float
+# $maxRating: Float
+# $genre: String
+# $tag: String
+# $input: String
+# ) @auth(level: PUBLIC) {
+# movies(
+# where: {
+# _and: [
+# { rating: { ge: $minRating } }
+# { rating: { le: $maxRating } }
+# { genre: { eq: $genre } }
+# { tags: { includes: $tag } }
+# { title: { contains: $input } }
+# ]
+# }
+# ) {
+# id
+# rating
+# title
+# imageUrl
+# }
+# }
+
+# # Get favorite actors by user ID
+# query GetFavoriteActors @auth(level: USER) {
+# user(key: {id_expr: "auth.uid"}) {
+# favorite_actors_on_user {
+# actor {
+# id
+# name
+# imageUrl
+# }
+# }
+# }
+# }
+
+# # Get favorite movies by user ID
+# query GetUserFavoriteMovies @auth(level: USER) {
+# user(id_expr: "auth.uid") {
+# favorite_movies_on_user {
+# movie {
+# id
+# title
+# genre
+# imageUrl
+# releaseYear
+# rating
+# description
+# }
+# }
+# }
+# }
+# # end of example queries
diff --git a/dataconnect/flutter-movie/dataconnect/dataconnect.yaml b/dataconnect/flutter-movie/dataconnect/dataconnect.yaml
new file mode 100644
index 00000000..300d80b1
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/dataconnect.yaml
@@ -0,0 +1,12 @@
+specVersion: "v1beta"
+serviceId: "dataconnect"
+location: "us-central1"
+schema:
+ source: "./schema"
+ datasource:
+ postgresql:
+ database: "fdcdb"
+ cloudSql:
+ instanceId: "dataconnect-fdc"
+ # schemaValidation: "COMPATIBLE"
+connectorDirs: ["./connector"]
diff --git a/dataconnect/flutter-movie/dataconnect/moviedata_insert.gql b/dataconnect/flutter-movie/dataconnect/moviedata_insert.gql
new file mode 100644
index 00000000..44cdfe00
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/moviedata_insert.gql
@@ -0,0 +1,701 @@
+ # Copyright 2024 Google LLC
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
+mutation {
+ movie_insertMany(
+ data: [
+ {
+ id: "550e8400-e29b-41d4-a716-446655440000"
+ title: "Quantum Paradox"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fquantum_paradox.jpeg?alt=media&token=4142e2a1-bf43-43b5-b7cf-6616be3fd4e3"
+ releaseYear: 2025
+ genre: "sci-fi"
+ rating: 7.9
+ description: "A group of scientists accidentally open a portal to a parallel universe, causing a rift in time. As the team races to close the portal, they encounter alternate versions of themselves, leading to shocking revelations."
+ tags: ["thriller", "adventure"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440001"
+ title: "The Lone Outlaw"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Flone_outlaw.jpeg?alt=media&token=15525ffc-208f-4b59-b506-ae8348e06e85"
+ releaseYear: 2023
+ genre: "western"
+ rating: 8.2
+ description: "In the lawless Wild West, a mysterious gunslinger with a hidden past takes on a corrupt sheriff and his band of outlaws to bring justice to a small town."
+ tags: ["action", "drama"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440002"
+ title: "Celestial Harmony"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fcelestial_harmony.jpeg?alt=media&token=f5fe1845-3fac-4f46-8511-f35f928b6d1d"
+ releaseYear: 2024
+ genre: "romance"
+ rating: 7.5
+ description: "Two astronauts, stationed on a remote space station, fall in love amidst the isolation of deep space. But when a mysterious signal disrupts their communication, they must find a way to reconnect and survive."
+ tags: ["romance", "sci-fi"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440003"
+ title: "Noir Mystique"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fnoir_mystique.jpeg?alt=media&token=3299adba-cb98-4302-8b23-aeb679a4f913"
+ releaseYear: 2022
+ genre: "mystery"
+ rating: 8.0
+ description: "A private detective gets caught up in a web of lies, deception, and betrayal while investigating the disappearance of a famous actress in 1940s Hollywood."
+ tags: ["crime", "thriller"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440004"
+ title: "The Forgotten Island"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fforgotten_island.jpeg?alt=media&token=a6b2d761-2018-48c3-91a1-632d199440d4"
+ releaseYear: 2025
+ genre: "adventure"
+ rating: 7.6
+ description: "An explorer leads an expedition to a remote island rumored to be home to mythical creatures. As the team ventures deeper into the island, they uncover secrets that change the course of history."
+ tags: ["adventure", "fantasy"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440005"
+ title: "Digital Nightmare"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fdigital_nightmare.jpeg?alt=media&token=335ec842-1ca4-4b09-abd1-e96d9f5c0c2f"
+ releaseYear: 2024
+ genre: "horror"
+ rating: 6.9
+ description: "A tech-savvy teenager discovers a cursed app that brings nightmares to life. As the horrors of the digital world cross into reality, she must find a way to break the curse before it's too late."
+ tags: ["horror", "thriller"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440006"
+ title: "Eclipse of Destiny"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Feclipse_destiny.jpeg?alt=media&token=346649b3-cb5c-4d7e-b0d4-6f02e3df5959"
+ releaseYear: 2026
+ genre: "fantasy"
+ rating: 8.1
+ description: "In a kingdom on the brink of war, a prophecy speaks of an eclipse that will grant power to the rightful ruler. As factions vie for control, a young warrior must decide where his true loyalty lies."
+ tags: ["fantasy", "adventure"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440007"
+ title: "Heart of Steel"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fheart_steel.jpeg?alt=media&token=17883d71-329b-415a-86f8-dd4d9e941d7f"
+ releaseYear: 2023
+ genre: "sci-fi"
+ rating: 7.7
+ description: "A brilliant scientist creates a robot with a human heart. As the robot struggles to understand emotions, it becomes entangled in a plot that could change the fate of humanity."
+ tags: ["sci-fi", "drama"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440008"
+ title: "Rise of the Crimson Empire"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Frise_crimson_empire.jpeg?alt=media&token=6faa73ad-7504-4146-8f3a-50b90f607f33"
+ releaseYear: 2025
+ genre: "action"
+ rating: 8.4
+ description: "A legendary warrior rises to challenge the tyrannical rule of a powerful empire. As rebellion brews, the warrior must unite different factions to lead an uprising."
+ tags: ["action", "adventure"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440009"
+ title: "Silent Waves"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fsilent_waves.jpeg?alt=media&token=bd626bf1-ec60-4e57-aa07-87ba14e35bb7"
+ releaseYear: 2024
+ genre: "drama"
+ rating: 8.2
+ description: "A talented pianist, who loses his hearing in a tragic accident, must rediscover his passion for music with the help of a young music teacher who believes in him."
+ tags: ["drama", "music"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440010"
+ title: "Echoes of the Past"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fecho_of_past.jpeg?alt=media&token=d866aa27-8534-4d72-8988-9da4a1b9e452"
+ releaseYear: 2023
+ genre: "historical"
+ rating: 7.8
+ description: "A historian stumbles upon an ancient artifact that reveals hidden truths about an empire long forgotten. As she deciphers the clues, a shadowy organization tries to stop her from unearthing the past."
+ tags: ["drama", "mystery"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440011"
+ title: "Beyond the Horizon"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fbeyond_horizon.jpeg?alt=media&token=9c054b8d-1a63-48f6-b161-fb28e3d15e55"
+ releaseYear: 2026
+ genre: "sci-fi"
+ rating: 8.5
+ description: "In the future, Earth's best pilots are sent on a mission to explore a mysterious planet beyond the solar system. What they find changes humanity's understanding of the universe forever."
+ tags: ["sci-fi", "adventure"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440012"
+ title: "Shadows and Lies"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fshadows_lies.jpeg?alt=media&token=01afb80d-caee-47f8-a00e-aea8b9e459a2"
+ releaseYear: 2022
+ genre: "crime"
+ rating: 7.9
+ description: "A young detective with a dark past investigates a series of mysterious murders in a city plagued by corruption. As she digs deeper, she realizes nothing is as it seems."
+ tags: ["crime", "thriller"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440013"
+ title: "The Last Symphony"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Flast_symphony.jpeg?alt=media&token=f9bf80cd-3d8e-4e24-8503-7feb11f4e397"
+ releaseYear: 2024
+ genre: "drama"
+ rating: 8.0
+ description: "An aging composer struggling with memory loss attempts to complete his final symphony. With the help of a young prodigy, he embarks on an emotional journey through his memories and legacy."
+ tags: ["drama", "music"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440014"
+ title: "Moonlit Crusade"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fmoonlit_crusade.jpeg?alt=media&token=1e2d46e2-6b76-4e20-b656-4b005b37d14b"
+ releaseYear: 2025
+ genre: "fantasy"
+ rating: 8.3
+ description: "A knight is chosen by an ancient order to embark on a quest under the light of the full moon. Facing mythical beasts and treacherous landscapes, he seeks a relic that could save his kingdom."
+ tags: ["fantasy", "adventure"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440015"
+ title: "Abyss of the Deep"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fabyss_deep.jpeg?alt=media&token=2417321d-2451-4ec0-9ed6-6297042170e6"
+ releaseYear: 2023
+ genre: "horror"
+ rating: 7.2
+ description: "When a group of marine biologists descends into the unexplored depths of the ocean, they encounter a terrifying and ancient force. Now, they must survive as the abyss comes alive."
+ tags: ["horror", "thriller"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440016"
+ title: "Phoenix Rising"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fpheonix_rising.jpeg?alt=media&token=7298b1fd-833c-471c-a55d-e8fc798b4ab2"
+ releaseYear: 2025
+ genre: "action"
+ rating: 8.6
+ description: "A special forces operative, presumed dead, returns to avenge his fallen comrades. With nothing to lose, he faces a powerful enemy in a relentless pursuit for justice."
+ tags: ["action", "thriller"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440017"
+ title: "The Infinite Knot"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Finfinite_knot.jpeg?alt=media&token=93d54d93-d933-4663-a6fe-26b707ef823e"
+ releaseYear: 2026
+ genre: "romance"
+ rating: 7.4
+ description: "Two souls destined to meet across multiple lifetimes struggle to find each other in a chaotic world. With each incarnation, they get closer, but time itself becomes their greatest obstacle."
+ tags: ["romance", "fantasy"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440018"
+ title: "Parallel Justice"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fparallel_justice.jpeg?alt=media&token=f975524a-6edf-4d3b-99e1-c99e62a50518"
+ releaseYear: 2024
+ genre: "crime"
+ rating: 8.1
+ description: "A lawyer who can see the outcomes of different timelines must choose between justice and personal gain. When a high-stakes case arises, he faces a moral dilemma that could alter his life forever."
+ tags: ["crime", "thriller"]
+ }
+ {
+ id: "550e8400-e29b-41d4-a716-446655440019"
+ title: "Veil of Illusion"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/movie%2Fveil_illusion.jpeg?alt=media&token=baa02cce-efe8-4c9f-bd9f-65233c6e1ca8"
+ releaseYear: 2022
+ genre: "mystery"
+ rating: 7.8
+ description: "A magician-turned-detective uses his skills in illusion to solve crimes. When a series of murders leaves the city in fear, he must reveal the truth hidden behind a veil of deceit."
+ tags: ["mystery", "crime"]
+ }
+ ]
+ )
+ actor_insertMany(
+ data: [
+ {
+ id: "123e4567-e89b-12d3-a456-426614174020"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Foliver_blackwood.jpeg?alt=media&token=79cdbc29-c2c6-4dc3-b87f-f6dc4f1a8208"
+ name: "Oliver Blackwood"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174021"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Femma_westfield.jpeg?alt=media&token=2991c3c9-cfa8-4067-8b26-c5239b6894c4"
+ name: "Emma Westfield"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174022"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fjack_stone.jpeg?alt=media&token=74a564aa-d840-4bdd-a8a6-c6b17bbde608"
+ name: "Jack Stone"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174023"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fclara_woods.jpeg?alt=media&token=b4ff2a15-ef6d-4f20-86c9-07d67015fb29"
+ name: "Clara Woods"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174024"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fnoah_frost.jpeg?alt=media&token=0d08179a-7778-405e-9501-feac43b77a99"
+ name: "Noah Frost"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174025"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fisabelle_hart.jpeg?alt=media&token=d4fdf896-0f5b-4c32-91a4-7a541a95e77d"
+ name: "Isabella Hart"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174026"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fliam_hale.jpeg?alt=media&token=08e8eeee-b8ef-4e7b-8f97-a1e0b59321cc"
+ name: "Liam Hale"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174027"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fsophia_knight.jpeg?alt=media&token=7a79ef21-93e0-46f9-934c-6bbef7b5d430"
+ name: "Sophia Knight"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174028"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Falex_clay.jpeg?alt=media&token=2a798cdb-f44f-48d5-91bc-9d26a758944e"
+ name: "Alexander Clay"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174029"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Famelia_stone.jpeg?alt=media&token=34f21ba9-9e28-4708-9e55-f123634ab506"
+ name: "Amelia Stone"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174030"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fethan_blake.jpeg?alt=media&token=41352170-a5cd-4088-b8fd-1c4ee0d52cad"
+ name: "Ethan Blake"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174031"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fmia_gray.jpeg?alt=media&token=1ba1831a-3ada-485a-b5c9-2d018bf1862b"
+ name: "Mia Gray"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174032"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flucas_reed.jpeg?alt=media&token=c74f44f3-ae98-4208-8e67-18c2db65a5c1"
+ name: "Lucas Reed"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174033"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fevelyn_harper.jpeg?alt=media&token=b138b308-9589-4dfe-8c50-a6d70f06dfb1"
+ name: "Evelyn Harper"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174034"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Foscar_smith.jpeg?alt=media&token=d493da85-644d-4d45-a09d-ecb5416645e4"
+ name: "Oscar Smith"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174035"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fava_winter.jpeg?alt=media&token=757e4b11-0372-401e-8fa0-61797e90312a"
+ name: "Ava Winter"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174036"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fleo_hunt.jpeg?alt=media&token=2cb14738-b39b-47b1-87f9-b45f38245179"
+ name: "Leo Hunt"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174037"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flucy_walsh.jpeg?alt=media&token=016a216c-f329-4c10-bbe8-b31425f73c69"
+ name: "Lucy Walsh"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174038"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Fmason_ford.jpeg?alt=media&token=55388be9-fdc8-483f-8352-c29755ed3574"
+ name: "Mason Ford"
+ }
+ {
+ id: "123e4567-e89b-12d3-a456-426614174039"
+ imageUrl: "https://firebasestorage.googleapis.com/v0/b/fdc-web-quickstart.appspot.com/o/actor%2Flily_moore.jpeg?alt=media&token=19538aa6-1baf-4033-8fd7-d2a62aa79f51"
+ name: "Lily Moore"
+ }
+ ]
+ )
+ movieMetadata_insertMany(
+ data: [
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440000"
+ director: "Henry Caldwell"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440001"
+ director: "Juliana Mason, Clark Avery"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440002"
+ director: "Diana Rivers"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440003"
+ director: "Liam Thatcher"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440004"
+ director: "Evelyn Hart"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440005"
+ director: "Grayson Brooks"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440006"
+ director: "Isabella Quinn"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440007"
+ director: "Vincent Hale"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440008"
+ director: "Amelia Sutton"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440009"
+ director: "Lucas Stone"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440010"
+ director: "Sophia Langford"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440011"
+ director: "Noah Bennett"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440012"
+ director: "Chloe Armstrong"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440013"
+ director: "Sebastian Crane"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440014"
+ director: "Isla Fitzgerald"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440015"
+ director: "Oliver Hayes"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440016"
+ director: "Mila Donovan"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440017"
+ director: "Carter Monroe, Elise Turner"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440018"
+ director: "Adrian Blake"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440019"
+ director: "Hazel Carter"
+ }
+ ]
+ )
+movieActor_insertMany(
+ data: [
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440000"
+ actorId: "123e4567-e89b-12d3-a456-426614174020"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440000"
+ actorId: "123e4567-e89b-12d3-a456-426614174021"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440001"
+ actorId: "123e4567-e89b-12d3-a456-426614174021"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440001"
+ actorId: "123e4567-e89b-12d3-a456-426614174022"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440002"
+ actorId: "123e4567-e89b-12d3-a456-426614174022"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440002"
+ actorId: "123e4567-e89b-12d3-a456-426614174023"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440003"
+ actorId: "123e4567-e89b-12d3-a456-426614174023"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440003"
+ actorId: "123e4567-e89b-12d3-a456-426614174024"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440004"
+ actorId: "123e4567-e89b-12d3-a456-426614174024"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440004"
+ actorId: "123e4567-e89b-12d3-a456-426614174025"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440005"
+ actorId: "123e4567-e89b-12d3-a456-426614174025"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440005"
+ actorId: "123e4567-e89b-12d3-a456-426614174026"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440006"
+ actorId: "123e4567-e89b-12d3-a456-426614174026"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440006"
+ actorId: "123e4567-e89b-12d3-a456-426614174027"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440007"
+ actorId: "123e4567-e89b-12d3-a456-426614174027"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440007"
+ actorId: "123e4567-e89b-12d3-a456-426614174028"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440008"
+ actorId: "123e4567-e89b-12d3-a456-426614174028"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440008"
+ actorId: "123e4567-e89b-12d3-a456-426614174029"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440009"
+ actorId: "123e4567-e89b-12d3-a456-426614174029"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440009"
+ actorId: "123e4567-e89b-12d3-a456-426614174030"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440010"
+ actorId: "123e4567-e89b-12d3-a456-426614174030"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440010"
+ actorId: "123e4567-e89b-12d3-a456-426614174031"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440011"
+ actorId: "123e4567-e89b-12d3-a456-426614174031"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440011"
+ actorId: "123e4567-e89b-12d3-a456-426614174032"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440012"
+ actorId: "123e4567-e89b-12d3-a456-426614174032"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440012"
+ actorId: "123e4567-e89b-12d3-a456-426614174033"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440013"
+ actorId: "123e4567-e89b-12d3-a456-426614174033"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440013"
+ actorId: "123e4567-e89b-12d3-a456-426614174034"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440014"
+ actorId: "123e4567-e89b-12d3-a456-426614174034"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440014"
+ actorId: "123e4567-e89b-12d3-a456-426614174035"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440015"
+ actorId: "123e4567-e89b-12d3-a456-426614174035"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440015"
+ actorId: "123e4567-e89b-12d3-a456-426614174036"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440016"
+ actorId: "123e4567-e89b-12d3-a456-426614174036"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440016"
+ actorId: "123e4567-e89b-12d3-a456-426614174037"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440017"
+ actorId: "123e4567-e89b-12d3-a456-426614174037"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440017"
+ actorId: "123e4567-e89b-12d3-a456-426614174038"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440018"
+ actorId: "123e4567-e89b-12d3-a456-426614174038"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440018"
+ actorId: "123e4567-e89b-12d3-a456-426614174039"
+ role: "supporting"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440019"
+ actorId: "123e4567-e89b-12d3-a456-426614174039"
+ role: "main"
+ }
+ {
+ movieId: "550e8400-e29b-41d4-a716-446655440019"
+ actorId: "123e4567-e89b-12d3-a456-426614174020"
+ role: "supporting"
+ }
+ ]
+)
+ user_insertMany(
+ data: [
+ { id: "SnLgOC3lN4hcIl69s53cW0Q8R1T2", username: "sherlock_h" }
+ { id: "fep4fXpGWsaRpuphq9CIrBIXQ0S2", username: "hercule_p" }
+ { id: "TBedjwCX0Jf955Uuoxk6k74sY0l1", username: "jane_d" }
+ ]
+ )
+
+ review_insertMany(
+ data: [
+ {
+ id: "345e4567-e89b-12d3-a456-426614174000"
+ userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+ movieId: "550e8400-e29b-41d4-a716-446655440000"
+ rating: 5
+ reviewText: "An incredible movie with a mind-blowing plot!"
+ reviewDate_date: { today: true }
+ }
+ {
+ id: "345e4567-e89b-12d3-a456-426614174001"
+ userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+ movieId: "550e8400-e29b-41d4-a716-446655440001"
+ rating: 5
+ reviewText: "A revolutionary film that changed cinema forever."
+ reviewDate_date: { today: true }
+ }
+ {
+ id: "345e4567-e89b-12d3-a456-426614174002"
+ userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+ movieId: "550e8400-e29b-41d4-a716-446655440002"
+ rating: 5
+ reviewText: "A visually stunning and emotionally impactful movie."
+ reviewDate_date: { today: true }
+ }
+ {
+ id: "345e4567-e89b-12d3-a456-426614174003"
+ userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+ movieId: "550e8400-e29b-41d4-a716-446655440003"
+ rating: 4
+ reviewText: "A fantastic superhero film with great performances."
+ reviewDate_date: { today: true }
+ }
+ {
+ id: "345e4567-e89b-12d3-a456-426614174004"
+ userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+ movieId: "550e8400-e29b-41d4-a716-446655440004"
+ rating: 5
+ reviewText: "An amazing film that keeps you on the edge of your seat."
+ reviewDate_date: { today: true }
+ }
+ {
+ id: "345e4567-e89b-12d3-a456-426614174005"
+ userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+ movieId: "550e8400-e29b-41d4-a716-446655440005"
+ rating: 5
+ reviewText: "An absolute classic with unforgettable dialogue."
+ reviewDate_date: { today: true }
+ }
+ ]
+ )
+
+ favorite_movie_insertMany(
+ data: [
+ {
+ userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+ movieId: "550e8400-e29b-41d4-a716-446655440000"
+ }
+ {
+ userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+ movieId: "550e8400-e29b-41d4-a716-446655440001"
+ }
+ {
+ userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+ movieId: "550e8400-e29b-41d4-a716-446655440002"
+ }
+ {
+ userId: "SnLgOC3lN4hcIl69s53cW0Q8R1T2"
+ movieId: "550e8400-e29b-41d4-a716-446655440003"
+ }
+ {
+ userId: "fep4fXpGWsaRpuphq9CIrBIXQ0S2"
+ movieId: "550e8400-e29b-41d4-a716-446655440004"
+ }
+ {
+ userId: "TBedjwCX0Jf955Uuoxk6k74sY0l1"
+ movieId: "550e8400-e29b-41d4-a716-446655440005"
+ }
+ ]
+ )
+}
diff --git a/dataconnect/flutter-movie/dataconnect/schema/schema.gql b/dataconnect/flutter-movie/dataconnect/schema/schema.gql
new file mode 100644
index 00000000..1eecf54e
--- /dev/null
+++ b/dataconnect/flutter-movie/dataconnect/schema/schema.gql
@@ -0,0 +1,95 @@
+# Movies
+# TODO: Fill out Movie table
+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
+}
+
+# Movie Metadata
+# Movie - MovieMetadata is a one-to-one relationship
+# TODO: Fill out MovieMetadata table
+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
+}
+
+# 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
+# TODO: Fill out Actor table
+type Actor @table {
+ id: UUID!
+ imageUrl: String!
+ name: String! @col(name: "name", dataType: "varchar(30)")
+}
+
+# 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
+# TODO: Fill out User table
+type User
+ @table {
+ id: String! @col(name: "user_auth")
+ username: String! @col(name: "username", dataType: "varchar(50)")
+ # The following are generated from the @ref in the Review table
+ # reviews_on_user
+ # movies_via_Review
+}
+
+# Reviews
+# TODO: Fill out Review table
+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")
+}
+
+# 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]
+# TODO: Fill out MovieActor table
+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"
+}
+
+type Genre @view(sql: """
+SELECT DISTINCT genre from "movie"
+"""
+) {
+ genre: String
+}
+
+# Join table for many-to-many relationship for users and favorite movies
+# TODO: Fill out FavoriteMovie table
+type FavoriteMovie
+ @table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
+ # @ref is implicit
+ user: User!
+ movie: Movie!
+}
diff --git a/dataconnect/flutter-movie/firebase.json b/dataconnect/flutter-movie/firebase.json
new file mode 100644
index 00000000..dd862209
--- /dev/null
+++ b/dataconnect/flutter-movie/firebase.json
@@ -0,0 +1,14 @@
+{
+ "dataconnect": {
+ "source": "dataconnect"
+ },
+ "emulators": {
+ "dataconnect": {
+ "port": 9403
+ },
+ "ui": {
+ "enabled": false
+ },
+ "singleProjectMode": true
+ }
+}
diff --git a/dataconnect/flutter-movie/lib/actor_detail.dart b/dataconnect/flutter-movie/lib/actor_detail.dart
new file mode 100644
index 00000000..a25a0556
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/actor_detail.dart
@@ -0,0 +1,78 @@
+import 'package:flutter/material.dart';
+
+import 'movie_state.dart';
+import 'widgets/list_movies.dart';
+
+class ActorDetail extends StatelessWidget {
+ const ActorDetail({
+ super.key,
+ required this.actorId,
+ });
+
+ final String actorId;
+
+ @override
+ Widget build(BuildContext context) {
+ return FutureBuilder(
+ future: MovieState.getActorById(actorId),
+ builder: (context, snapshot) {
+ final actor = snapshot.data?.data.actor;
+ final loading = snapshot.connectionState == ConnectionState.waiting;
+ return Scaffold(
+ body: SafeArea(
+ child: () {
+ if (actor == null || loading) {
+ return const Center(
+ child: CircularProgressIndicator(),
+ );
+ }
+ return Padding(
+ padding: const EdgeInsets.all(30),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ Align(
+ alignment: Alignment.centerLeft,
+ child: Text(
+ actor.name,
+ style: const TextStyle(fontSize: 30),
+ )),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: AspectRatio(
+ aspectRatio:
+ 9 / 16, // 9:16 aspect ratio for the image
+ child: Image.network(
+ actor.imageUrl,
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ListMovies(
+ movies: MovieState.convertMainActorDetail(
+ actor.mainActors,
+ ),
+ title: "Main Roles",
+ ),
+ ListMovies(
+ movies: MovieState.convertSupportingActorDetail(
+ actor.supportingActors,
+ ),
+ title: "Supporting Roles",
+ ),
+ ],
+ ),
+ ),
+ );
+ }(),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/dataconnect/flutter-movie/lib/destination.dart b/dataconnect/flutter-movie/lib/destination.dart
new file mode 100644
index 00000000..25820bbe
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/destination.dart
@@ -0,0 +1,30 @@
+import 'package:flutter/material.dart';
+
+class Route extends NavigationDestination {
+ Route({
+ super.key,
+ required this.path,
+ required super.label,
+ required this.iconData,
+ }) : super(icon: Icon(iconData));
+ final String path;
+ final IconData iconData;
+}
+
+final homePath = Route(
+ path: '/home',
+ label: 'Home',
+ iconData: Icons.home,
+);
+final searchPath = Route(
+ path: '/search',
+ label: 'Search',
+ iconData: Icons.search,
+);
+final profilePath = Route(
+ path: '/profile',
+ label: 'Profile',
+ iconData: Icons.person,
+);
+
+final paths = [homePath, searchPath, profilePath];
diff --git a/dataconnect/flutter-movie/lib/firebase_options.dart b/dataconnect/flutter-movie/lib/firebase_options.dart
new file mode 100644
index 00000000..9c664017
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/firebase_options.dart
@@ -0,0 +1,57 @@
+// File generated by FlutterFire CLI.
+// ignore_for_file: type=lint
+import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
+import 'package:flutter/foundation.dart'
+ show defaultTargetPlatform, kIsWeb, TargetPlatform;
+
+/// Default [FirebaseOptions] for use with your Firebase apps.
+///
+/// Example:
+/// ```dart
+/// import 'firebase_options.dart';
+/// // ...
+/// await Firebase.initializeApp(
+/// options: DefaultFirebaseOptions.currentPlatform,
+/// );
+/// ```
+class DefaultFirebaseOptions {
+ static FirebaseOptions get currentPlatform {
+ if (kIsWeb) {
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for ios - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ }
+ switch (defaultTargetPlatform) {
+ case TargetPlatform.android:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for ios - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.iOS:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for ios - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.macOS:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for macos - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.windows:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for windows - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ case TargetPlatform.linux:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions have not been configured for linux - '
+ 'you can reconfigure this by running the FlutterFire CLI again.',
+ );
+ default:
+ throw UnsupportedError(
+ 'DefaultFirebaseOptions are not supported for this platform.',
+ );
+ }
+ }
+}
diff --git a/dataconnect/flutter-movie/lib/login.dart b/dataconnect/flutter-movie/lib/login.dart
new file mode 100644
index 00000000..91685bba
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/login.dart
@@ -0,0 +1,114 @@
+import 'package:dataconnect/movies_connector/movies.dart';
+import 'package:dataconnect/widgets/auth_dialog.dart';
+import 'package:firebase_auth/firebase_auth.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+class Login extends StatefulWidget {
+ const Login({super.key});
+
+ @override
+ State createState() => _LoginState();
+}
+
+class _LoginState extends State {
+ final _formKey = GlobalKey();
+ final _username = TextEditingController();
+ final _password = TextEditingController();
+
+ Future logIn() async {
+ final messenger = ScaffoldMessenger.of(context);
+ final navigator = GoRouter.of(context);
+ messenger.showSnackBar(const SnackBar(content: Text('Signing In')));
+ try {
+ await FirebaseAuth.instance.signInWithEmailAndPassword(
+ email: _username.text,
+ password: _password.text,
+ );
+ final isLoggedIn =
+ await MoviesConnector.instance.getCurrentUser().execute();
+ if (isLoggedIn.data.user == null) {
+ await MoviesConnector.instance
+ .upsertUser(username: _username.text)
+ .execute();
+ }
+ if (mounted) {
+ navigator.go('/home');
+ }
+ } on FirebaseAuthException catch (e) {
+ if (mounted) {
+ String message = e.code.contains('configuration-not-found')
+ ? 'Email/Password authentication has not been enabled'
+ : e.message!;
+ bool shouldLaunch = e.code.contains('operation-not-allowed') ||
+ e.code.contains('configuration-not-found');
+ AuthDialog.showAuthDialog(context, message, shouldLaunch);
+ }
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.all(30),
+ child: Center(
+ child: Form(
+ key: _formKey,
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ TextFormField(
+ decoration: const InputDecoration(
+ hintText: "Username",
+ border: OutlineInputBorder(),
+ ),
+ controller: _username,
+ validator: (value) {
+ if (value == null || value.isEmpty) {
+ return 'Please enter some text';
+ }
+ return null;
+ },
+ ),
+ const SizedBox(height: 30),
+ TextFormField(
+ obscureText: true,
+ autocorrect: false,
+ decoration: const InputDecoration(
+ hintText: "Password",
+ border: OutlineInputBorder(),
+ ),
+ controller: _password,
+ validator: (value) {
+ if (value == null || value.isEmpty) {
+ return 'Please enter a password';
+ }
+ return null;
+ },
+ ),
+ ElevatedButton(
+ onPressed: () {
+ if (_formKey.currentState!.validate()) {
+ logIn();
+ }
+ },
+ child: const Text('Sign In')),
+ const Text("Don't have an account?"),
+ ElevatedButton(
+ onPressed: () {
+ context.go('/signup');
+ },
+ child: const Text('Sign Up'),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/dataconnect/flutter-movie/lib/main.dart b/dataconnect/flutter-movie/lib/main.dart
new file mode 100644
index 00000000..3202f6e0
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/main.dart
@@ -0,0 +1,184 @@
+import 'package:dataconnect/models/movie.dart';
+import 'package:dataconnect/movie_state.dart';
+import 'package:dataconnect/router.dart';
+import 'package:dataconnect/widgets/list_movies.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:firebase_core/firebase_core.dart';
+import 'firebase_options.dart';
+import 'package:flutter_web_plugins/url_strategy.dart';
+import 'util/auth.dart';
+import 'movies_connector/movies.dart';
+
+bool isSetup = false;
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ usePathUrlStrategy();
+ try {
+ await Firebase.initializeApp(
+ options: DefaultFirebaseOptions.currentPlatform,
+ );
+ isSetup = true;
+
+ await Auth.instance.init();
+ int port = 443;
+ String hostName = Uri.base.host;
+ bool isSecure = true;
+ if (!kIsWeb) {
+ hostName = '10.0.2.2';
+ port = 9403;
+ isSecure = false;
+ }
+ MoviesConnector.instance.dataConnect
+ .useDataConnectEmulator(hostName, port, isSecure: isSecure);
+ } catch (_) {
+ // The user hasn't run ./installDeps.sh yet
+ }
+
+ runApp(const MyApp());
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ // This widget is the root of your application.
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp.router(
+ theme: ThemeData.dark(),
+ routerConfig: router,
+ );
+ }
+}
+
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({super.key});
+
+ @override
+ State createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State {
+ List _topMovies = [];
+ List _latestMovies = [];
+ bool _showMessage = true;
+
+ @override
+ void initState() {
+ super.initState();
+
+ if (isSetup) {
+ MovieState.getTopTenMovies().then((res) {
+ if (res.data.movies.isNotEmpty) {
+ if (mounted) {
+ setState(() {
+ _showMessage = false;
+ _topMovies = res.data.movies;
+ });
+ }
+ }
+ });
+
+ MovieState.getTopTenMovies().then((res) {
+ setState(() {
+ _latestMovies = res.data.movies;
+ });
+ });
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: SafeArea(
+ child: SingleChildScrollView(
+ child: _showMessage || !isSetup
+ ? Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(30.0),
+ child: isSetup
+ ? Text(
+ 'Go to the Firebase Data Connect extension, and click start Emulators. ${_latestMovies.isEmpty ? 'Then open dataconnect/moviedata_insert.gql and the click "Run(local)".' : ''} Then, refresh the page.')
+ : const NumberedList(bullets: [
+ 'Make sure you already have a Firebase Project',
+ 'In the sidebar, open The Firebase Data Connect Extension',
+ 'Sign into your google account associated with your firebase project',
+ 'Select your firebase project',
+ 'Open a new terminal (by clicking the + icon below) and Run "flutterfire configure -y -a com.example.dataconnect"',
+ 'Refresh this preview page'
+ ]))
+ ],
+ )
+ : Column(
+ children: [
+ ListMovies(
+ title: 'Top 10 Movies',
+ movies: _topMovies
+ .map(
+ (e) => Movie(
+ id: e.id,
+ title: e.title,
+ imageUrl: e.imageUrl,
+ description: e.description),
+ )
+ .toList()),
+ ListMovies(
+ title: 'Latest Movies',
+ movies: _latestMovies
+ .map(
+ (e) => Movie(
+ id: e.id,
+ title: e.title,
+ imageUrl: e.imageUrl,
+ description: e.description),
+ )
+ .toList()),
+ ],
+ ),
+ )),
+ );
+ }
+}
+
+class NumberedList extends StatelessWidget {
+ const NumberedList({super.key, required this.bullets});
+
+ final List bullets;
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ alignment: Alignment.centerLeft,
+ padding: const EdgeInsets.fromLTRB(16, 15, 16, 16),
+ child: Column(
+ children: bullets
+ .asMap()
+ .keys
+ .map((index) => Row(children: [
+ Text(
+ "${index + 1}.",
+ style: const TextStyle(
+ fontSize: 16, height: 1.55, color: Colors.white),
+ ),
+ const SizedBox(
+ width: 5,
+ ),
+ Expanded(
+ child: Text(
+ bullets[index],
+ textAlign: TextAlign.left,
+ softWrap: true,
+ style: const TextStyle(
+ fontSize: 16,
+ color: Colors.white,
+ height: 1.55,
+ ),
+ ),
+ )
+ ]))
+ .toList()));
+ }
+}
diff --git a/dataconnect/flutter-movie/lib/models/movie.dart b/dataconnect/flutter-movie/lib/models/movie.dart
new file mode 100644
index 00000000..7b0ed506
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/models/movie.dart
@@ -0,0 +1,11 @@
+class Movie {
+ Movie(
+ {required this.id,
+ required this.title,
+ required this.imageUrl,
+ this.description});
+ String id;
+ String title;
+ String imageUrl;
+ String? description;
+}
diff --git a/dataconnect/flutter-movie/lib/movie_detail.dart b/dataconnect/flutter-movie/lib/movie_detail.dart
new file mode 100644
index 00000000..0189843c
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movie_detail.dart
@@ -0,0 +1,262 @@
+import 'dart:async';
+
+import 'package:dataconnect/movie_state.dart';
+import 'package:dataconnect/movies_connector/movies.dart';
+import 'package:dataconnect/widgets/list_actors.dart';
+import 'package:dataconnect/widgets/login_guard.dart';
+import 'package:flutter/material.dart';
+import 'package:intl/intl.dart';
+
+class MovieDetail extends StatefulWidget {
+ const MovieDetail({super.key, required this.id});
+
+ final String id;
+
+ @override
+ State createState() => _MovieDetailState();
+}
+
+class _MovieDetailState extends State {
+ double _ratingValue = 0;
+ bool loading = true;
+ GetMovieByIdData? data;
+ bool _favorited = false;
+
+ final _reviewTextController = TextEditingController();
+ StreamSubscription? _movieByIdSub, _movieInfoSub;
+
+ @override
+ void initState() {
+ super.initState();
+ init(widget.id);
+ }
+
+ @override
+ void dispose() {
+ _movieByIdSub?.cancel();
+ _movieInfoSub?.cancel();
+ super.dispose();
+ }
+
+ @override
+ void didUpdateWidget(covariant MovieDetail oldWidget) {
+ super.didUpdateWidget(oldWidget);
+ if (oldWidget.id != widget.id) {
+ init(widget.id);
+ }
+ }
+
+ Future init(String id) async {
+ _movieByIdSub?.cancel();
+ _movieInfoSub?.cancel();
+ _movieByIdSub = MovieState.subscribeToMovieById(widget.id).listen(
+ (value) {
+ if (mounted) {
+ setState(() {
+ loading = false;
+ data = value.data;
+ });
+ }
+ },
+ );
+ _movieInfoSub = MovieState.subscribeToGetMovieInfo(widget.id).listen(
+ (value) {
+ if (mounted) {
+ setState(() {
+ _favorited = value.data.favorite_movie != null;
+ });
+ }
+ },
+ );
+ }
+
+ void _toggleFavorite() {
+ MovieState.toggleFavorite(widget.id, _favorited).then((_) {
+ if (mounted) {
+ setState(() {
+ _favorited = !_favorited;
+ });
+ }
+ });
+ }
+
+ void _refreshData() {
+ MovieState.refreshMovieDetail(widget.id);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: SafeArea(
+ child: () {
+ final movie = data?.movie;
+ if (movie == null) {
+ return const Center(
+ child: CircularProgressIndicator(),
+ );
+ }
+ return Padding(
+ padding: const EdgeInsets.all(30),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ Align(
+ alignment: Alignment.centerLeft,
+ child: Text(
+ movie.title,
+ style: const TextStyle(fontSize: 30),
+ )),
+ Row(
+ children: [
+ Text(movie.releaseYear.toString()),
+ const SizedBox(width: 10),
+ Row(
+ children: [
+ const Icon(Icons.star),
+ Text(movie.rating.toString())
+ ],
+ )
+ ],
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Expanded(
+ child: AspectRatio(
+ aspectRatio:
+ 9 / 16, // 9:16 aspect ratio for the image
+ child: Image.network(
+ movie.imageUrl,
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(15, 0, 0, 0),
+ child: Column(children: [
+ Row(
+ children: movie.tags!.map((tag) {
+ return Chip(
+ label: Text(
+ tag,
+ overflow: TextOverflow.ellipsis,
+ ));
+ }).toList(),
+ ),
+ Text(movie.description!)
+ ]),
+ ))
+ ]),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ LoginGuard(
+ builder: (context) => OutlinedButton.icon(
+ onPressed: () {
+ _toggleFavorite();
+ },
+ icon: Icon(_favorited
+ ? Icons.favorite
+ : Icons.favorite_border),
+ label: Text(
+ _favorited
+ ? 'Remove From Favorites'
+ : 'Add To Favorites',
+ ),
+ ),
+ )
+ ],
+ ),
+ ListActors(
+ actors: data!.movie!.mainActors
+ .map((actor) => Actor(
+ imageUrl: actor.imageUrl,
+ name: actor.name,
+ id: actor.id))
+ .toList(),
+ title: "Main Actors"),
+ ListActors(
+ actors: data!.movie!.supportingActors
+ .map((actor) => Actor(
+ imageUrl: actor.imageUrl,
+ name: actor.name,
+ id: actor.id))
+ .toList(),
+ title: "Supporting Actors"),
+ Text("Rating: $_ratingValue"),
+ Slider(
+ value: _ratingValue,
+ max: 10,
+ divisions: 20,
+ label: _ratingValue.toString(),
+ onChanged: (double value) {
+ setState(() {
+ _ratingValue = value;
+ });
+ },
+ ),
+ LoginGuard(
+ builder: (context) => TextField(
+ decoration: const InputDecoration(
+ hintText: "Write your review",
+ border: OutlineInputBorder(),
+ ),
+ controller: _reviewTextController,
+ ),
+ message: "writing a review",
+ ),
+ LoginGuard(
+ builder: (context) => OutlinedButton.icon(
+ onPressed: () {
+ MoviesConnector.instance
+ .addReview(
+ movieId: widget.id,
+ rating: _ratingValue.toInt(),
+ reviewText: _reviewTextController.text)
+ .execute()
+ .then(
+ (_) {
+ _refreshData();
+ _reviewTextController.clear();
+ MovieState.triggerUpdateFavorite();
+ },
+ );
+ },
+ label: const Text('Submit Review'),
+ ),
+ ),
+ ...data!.movie!.reviews.map((review) {
+ return Card(
+ child: Padding(
+ padding: const EdgeInsets.all(20.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(review.user.username),
+ Row(
+ children: [
+ Text(DateFormat.yMMMd()
+ .format(review.reviewDate)),
+ const SizedBox(
+ width: 10,
+ ),
+ Text("Rating ${review.rating}")
+ ],
+ ),
+ Text(review.reviewText!)
+ ],
+ )),
+ );
+ }),
+ ],
+ ),
+ ),
+ );
+ }(),
+ ),
+ );
+ }
+}
diff --git a/dataconnect/flutter-movie/lib/movie_state.dart b/dataconnect/flutter-movie/lib/movie_state.dart
new file mode 100644
index 00000000..85a5a6d1
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movie_state.dart
@@ -0,0 +1,91 @@
+import 'package:dataconnect/movies_connector/movies.dart';
+import 'package:firebase_data_connect/firebase_data_connect.dart';
+
+import 'models/movie.dart';
+
+class MovieState {
+ static void triggerUpdateFavorite() {
+ MoviesConnector.instance.getCurrentUser().execute();
+ }
+
+ static Future>
+ getTopTenMovies() {
+ return MoviesConnector.instance
+ .listMovies()
+ .orderByRating(OrderDirection.DESC)
+ .limit(10)
+ .execute();
+ }
+
+ static Future>
+ getLatestMovies() {
+ return MoviesConnector.instance
+ .listMovies()
+ .orderByReleaseYear(OrderDirection.DESC)
+ .execute();
+ }
+
+ static searchByPartialTitle(String input) {
+ return MoviesConnector.instance
+ .listMoviesByPartialTitle(input: input)
+ .execute();
+ }
+
+ static Stream>
+ subscribeToMovieById(String id) {
+ return MoviesConnector.instance.getMovieById(id: id).ref().subscribe();
+ }
+
+ static void refreshMovieDetail(String id) {
+ MoviesConnector.instance.getMovieById(id: id).execute();
+ MoviesConnector.instance.getMovieInfoForUser(movieId: id).execute();
+ }
+
+ static Stream<
+ QueryResult>
+ subscribeToGetMovieInfo(String id) {
+ return MoviesConnector.instance
+ .getMovieInfoForUser(movieId: id)
+ .ref()
+ .subscribe();
+ }
+
+ static Future>
+ getActorById(String actorId) {
+ return MoviesConnector.instance.getActorById(id: actorId).execute();
+ }
+
+ static List convertMainActorDetail(
+ List actors) {
+ return actors
+ .map(
+ (e) => Movie(imageUrl: e.imageUrl, id: e.id, title: e.title),
+ )
+ .toList();
+ }
+
+ static List convertSupportingActorDetail(
+ List actors) {
+ return actors
+ .map(
+ (e) => Movie(imageUrl: e.imageUrl, id: e.id, title: e.title),
+ )
+ .toList();
+ }
+
+ static Stream>
+ subscribeToCurrentUser() {
+ return MoviesConnector.instance.getCurrentUser().ref().subscribe();
+ }
+
+ static Future toggleFavorite(String id, bool favorited) async {
+ if (favorited) {
+ await MoviesConnector.instance
+ .deleteFavoritedMovie(movieId: id)
+ .execute();
+ } else {
+ await MoviesConnector.instance.addFavoritedMovie(movieId: id).execute();
+ }
+ triggerUpdateFavorite();
+ }
+}
diff --git a/dataconnect/flutter-movie/lib/movies_connector/add_favorited_movie.dart b/dataconnect/flutter-movie/lib/movies_connector/add_favorited_movie.dart
new file mode 100644
index 00000000..9f2a90b9
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movies_connector/add_favorited_movie.dart
@@ -0,0 +1,192 @@
+part of movies_connector;
+
+class AddFavoritedMovieVariablesBuilder {
+ String movieId;
+
+
+ FirebaseDataConnect _dataConnect;
+
+ AddFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,});
+ Deserializer dataDeserializer = (dynamic json) => AddFavoritedMovieData.fromJson(jsonDecode(json));
+ Serializer varsSerializer = (AddFavoritedMovieVariables vars) => jsonEncode(vars.toJson());
+ Future> execute() {
+ return this.ref().execute();
+ }
+ MutationRef ref() {
+ AddFavoritedMovieVariables vars=AddFavoritedMovieVariables(movieId: movieId,);
+
+ return _dataConnect.mutation("AddFavoritedMovie", dataDeserializer, varsSerializer, vars);
+ }
+}
+
+
+ class AddFavoritedMovieFavoriteMovieUpsert {
+
+ String userId;
+
+
+ String movieId;
+
+
+
+
+
+
+ AddFavoritedMovieFavoriteMovieUpsert.fromJson(dynamic json):
+ userId =
+
+ nativeFromJson(json['userId'])
+
+
+
+ ,
+
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+
+ {
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['userId'] =
+
+ nativeToJson(userId)
+
+;
+
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+ return json;
+ }
+
+ AddFavoritedMovieFavoriteMovieUpsert({
+
+ required this.userId,
+
+ required this.movieId,
+
+ });
+}
+
+
+
+ class AddFavoritedMovieData {
+
+ AddFavoritedMovieFavoriteMovieUpsert favorite_movie_upsert;
+
+
+
+
+
+
+ AddFavoritedMovieData.fromJson(dynamic json):
+ favorite_movie_upsert =
+
+ AddFavoritedMovieFavoriteMovieUpsert.fromJson(json['favorite_movie_upsert'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['favorite_movie_upsert'] =
+
+ favorite_movie_upsert.toJson()
+
+;
+
+
+ return json;
+ }
+
+ AddFavoritedMovieData({
+
+ required this.favorite_movie_upsert,
+
+ });
+}
+
+
+
+ class AddFavoritedMovieVariables {
+
+ String movieId;
+
+
+
+
+
+ @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
+
+
+ AddFavoritedMovieVariables.fromJson(Map json):
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+ return json;
+ }
+
+ AddFavoritedMovieVariables({
+
+ required this.movieId,
+
+ });
+}
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/lib/movies_connector/add_review.dart b/dataconnect/flutter-movie/lib/movies_connector/add_review.dart
new file mode 100644
index 00000000..bbf6f7af
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movies_connector/add_review.dart
@@ -0,0 +1,240 @@
+part of movies_connector;
+
+class AddReviewVariablesBuilder {
+ String movieId;
+int rating;
+String reviewText;
+
+
+ FirebaseDataConnect _dataConnect;
+
+ AddReviewVariablesBuilder(this._dataConnect, {required String this.movieId,required int this.rating,required String this.reviewText,});
+ Deserializer dataDeserializer = (dynamic json) => AddReviewData.fromJson(jsonDecode(json));
+ Serializer varsSerializer = (AddReviewVariables vars) => jsonEncode(vars.toJson());
+ Future> execute() {
+ return this.ref().execute();
+ }
+ MutationRef ref() {
+ AddReviewVariables vars=AddReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,);
+
+ return _dataConnect.mutation("AddReview", dataDeserializer, varsSerializer, vars);
+ }
+}
+
+
+ class AddReviewReviewUpsert {
+
+ String userId;
+
+
+ String movieId;
+
+
+
+
+
+
+ AddReviewReviewUpsert.fromJson(dynamic json):
+ userId =
+
+ nativeFromJson(json['userId'])
+
+
+
+ ,
+
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+
+ {
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['userId'] =
+
+ nativeToJson(userId)
+
+;
+
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+ return json;
+ }
+
+ AddReviewReviewUpsert({
+
+ required this.userId,
+
+ required this.movieId,
+
+ });
+}
+
+
+
+ class AddReviewData {
+
+ AddReviewReviewUpsert review_upsert;
+
+
+
+
+
+
+ AddReviewData.fromJson(dynamic json):
+ review_upsert =
+
+ AddReviewReviewUpsert.fromJson(json['review_upsert'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['review_upsert'] =
+
+ review_upsert.toJson()
+
+;
+
+
+ return json;
+ }
+
+ AddReviewData({
+
+ required this.review_upsert,
+
+ });
+}
+
+
+
+ class AddReviewVariables {
+
+ String movieId;
+
+
+ int rating;
+
+
+ String reviewText;
+
+
+
+
+
+ @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
+
+
+ AddReviewVariables.fromJson(Map json):
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+ ,
+
+ rating =
+
+ nativeFromJson(json['rating'])
+
+
+
+ ,
+
+ reviewText =
+
+ nativeFromJson(json['reviewText'])
+
+
+
+
+ {
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+
+ json['rating'] =
+
+ nativeToJson(rating)
+
+;
+
+
+
+ json['reviewText'] =
+
+ nativeToJson(reviewText)
+
+;
+
+
+ return json;
+ }
+
+ AddReviewVariables({
+
+ required this.movieId,
+
+ required this.rating,
+
+ required this.reviewText,
+
+ });
+}
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/lib/movies_connector/delete_favorited_movie.dart b/dataconnect/flutter-movie/lib/movies_connector/delete_favorited_movie.dart
new file mode 100644
index 00000000..2071ee5d
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movies_connector/delete_favorited_movie.dart
@@ -0,0 +1,194 @@
+part of movies_connector;
+
+class DeleteFavoritedMovieVariablesBuilder {
+ String movieId;
+
+
+ FirebaseDataConnect _dataConnect;
+
+ DeleteFavoritedMovieVariablesBuilder(this._dataConnect, {required String this.movieId,});
+ Deserializer dataDeserializer = (dynamic json) => DeleteFavoritedMovieData.fromJson(jsonDecode(json));
+ Serializer varsSerializer = (DeleteFavoritedMovieVariables vars) => jsonEncode(vars.toJson());
+ Future> execute() {
+ return this.ref().execute();
+ }
+ MutationRef ref() {
+ DeleteFavoritedMovieVariables vars=DeleteFavoritedMovieVariables(movieId: movieId,);
+
+ return _dataConnect.mutation("DeleteFavoritedMovie", dataDeserializer, varsSerializer, vars);
+ }
+}
+
+
+ class DeleteFavoritedMovieFavoriteMovieDelete {
+
+ String userId;
+
+
+ String movieId;
+
+
+
+
+
+
+ DeleteFavoritedMovieFavoriteMovieDelete.fromJson(dynamic json):
+ userId =
+
+ nativeFromJson(json['userId'])
+
+
+
+ ,
+
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+
+ {
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['userId'] =
+
+ nativeToJson(userId)
+
+;
+
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+ return json;
+ }
+
+ DeleteFavoritedMovieFavoriteMovieDelete({
+
+ required this.userId,
+
+ required this.movieId,
+
+ });
+}
+
+
+
+ class DeleteFavoritedMovieData {
+
+ DeleteFavoritedMovieFavoriteMovieDelete? favorite_movie_delete;
+
+
+
+
+
+
+ DeleteFavoritedMovieData.fromJson(dynamic json):
+ favorite_movie_delete = json['favorite_movie_delete'] == null ? null :
+
+ DeleteFavoritedMovieFavoriteMovieDelete.fromJson(json['favorite_movie_delete'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ if (favorite_movie_delete != null) {
+ json['favorite_movie_delete'] =
+
+ favorite_movie_delete!.toJson()
+
+;
+ }
+
+
+ return json;
+ }
+
+ DeleteFavoritedMovieData({
+
+ this.favorite_movie_delete,
+
+ });
+}
+
+
+
+ class DeleteFavoritedMovieVariables {
+
+ String movieId;
+
+
+
+
+
+ @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
+
+
+ DeleteFavoritedMovieVariables.fromJson(Map json):
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+ return json;
+ }
+
+ DeleteFavoritedMovieVariables({
+
+ required this.movieId,
+
+ });
+}
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/lib/movies_connector/delete_review.dart b/dataconnect/flutter-movie/lib/movies_connector/delete_review.dart
new file mode 100644
index 00000000..49fe10cd
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movies_connector/delete_review.dart
@@ -0,0 +1,194 @@
+part of movies_connector;
+
+class DeleteReviewVariablesBuilder {
+ String movieId;
+
+
+ FirebaseDataConnect _dataConnect;
+
+ DeleteReviewVariablesBuilder(this._dataConnect, {required String this.movieId,});
+ Deserializer dataDeserializer = (dynamic json) => DeleteReviewData.fromJson(jsonDecode(json));
+ Serializer varsSerializer = (DeleteReviewVariables vars) => jsonEncode(vars.toJson());
+ Future> execute() {
+ return this.ref().execute();
+ }
+ MutationRef ref() {
+ DeleteReviewVariables vars=DeleteReviewVariables(movieId: movieId,);
+
+ return _dataConnect.mutation("DeleteReview", dataDeserializer, varsSerializer, vars);
+ }
+}
+
+
+ class DeleteReviewReviewDelete {
+
+ String userId;
+
+
+ String movieId;
+
+
+
+
+
+
+ DeleteReviewReviewDelete.fromJson(dynamic json):
+ userId =
+
+ nativeFromJson(json['userId'])
+
+
+
+ ,
+
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+
+ {
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['userId'] =
+
+ nativeToJson(userId)
+
+;
+
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+ return json;
+ }
+
+ DeleteReviewReviewDelete({
+
+ required this.userId,
+
+ required this.movieId,
+
+ });
+}
+
+
+
+ class DeleteReviewData {
+
+ DeleteReviewReviewDelete? review_delete;
+
+
+
+
+
+
+ DeleteReviewData.fromJson(dynamic json):
+ review_delete = json['review_delete'] == null ? null :
+
+ DeleteReviewReviewDelete.fromJson(json['review_delete'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ if (review_delete != null) {
+ json['review_delete'] =
+
+ review_delete!.toJson()
+
+;
+ }
+
+
+ return json;
+ }
+
+ DeleteReviewData({
+
+ this.review_delete,
+
+ });
+}
+
+
+
+ class DeleteReviewVariables {
+
+ String movieId;
+
+
+
+
+
+ @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
+
+
+ DeleteReviewVariables.fromJson(Map json):
+ movieId =
+
+ nativeFromJson(json['movieId'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['movieId'] =
+
+ nativeToJson(movieId)
+
+;
+
+
+ return json;
+ }
+
+ DeleteReviewVariables({
+
+ required this.movieId,
+
+ });
+}
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/lib/movies_connector/get_actor_by_id.dart b/dataconnect/flutter-movie/lib/movies_connector/get_actor_by_id.dart
new file mode 100644
index 00000000..5400fa07
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movies_connector/get_actor_by_id.dart
@@ -0,0 +1,573 @@
+part of movies_connector;
+
+class GetActorByIdVariablesBuilder {
+ String id;
+
+
+ FirebaseDataConnect _dataConnect;
+
+ GetActorByIdVariablesBuilder(this._dataConnect, {required String this.id,});
+ Deserializer dataDeserializer = (dynamic json) => GetActorByIdData.fromJson(jsonDecode(json));
+ Serializer varsSerializer = (GetActorByIdVariables vars) => jsonEncode(vars.toJson());
+ Future> execute() {
+ return this.ref().execute();
+ }
+ QueryRef ref() {
+ GetActorByIdVariables vars=GetActorByIdVariables(id: id,);
+
+ return _dataConnect.query("GetActorById", dataDeserializer, varsSerializer, vars);
+ }
+}
+
+
+ class GetActorByIdActor {
+
+ String id;
+
+
+ String name;
+
+
+ String imageUrl;
+
+
+ List mainActors;
+
+
+ List supportingActors;
+
+
+
+
+
+
+ GetActorByIdActor.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ name =
+
+ nativeFromJson(json['name'])
+
+
+
+ ,
+
+ imageUrl =
+
+ nativeFromJson(json['imageUrl'])
+
+
+
+ ,
+
+ mainActors =
+
+
+ (json['mainActors'] as List)
+ .map((e) => GetActorByIdActorMainActors.fromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ supportingActors =
+
+
+ (json['supportingActors'] as List)
+ .map((e) => GetActorByIdActorSupportingActors.fromJson(e))
+ .toList()
+
+
+
+
+
+ {
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['name'] =
+
+ nativeToJson(name)
+
+;
+
+
+
+ json['imageUrl'] =
+
+ nativeToJson(imageUrl)
+
+;
+
+
+
+ json['mainActors'] =
+
+
+ mainActors.map((e) => e.toJson()).toList()
+
+
+;
+
+
+
+ json['supportingActors'] =
+
+
+ supportingActors.map((e) => e.toJson()).toList()
+
+
+;
+
+
+ return json;
+ }
+
+ GetActorByIdActor({
+
+ required this.id,
+
+ required this.name,
+
+ required this.imageUrl,
+
+ required this.mainActors,
+
+ required this.supportingActors,
+
+ });
+}
+
+
+
+ class GetActorByIdActorMainActors {
+
+ String id;
+
+
+ String title;
+
+
+ String? genre;
+
+
+ List? tags;
+
+
+ String imageUrl;
+
+
+
+
+
+
+ GetActorByIdActorMainActors.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ title =
+
+ nativeFromJson(json['title'])
+
+
+
+ ,
+
+ genre = json['genre'] == null ? null :
+
+ nativeFromJson(json['genre'])
+
+
+
+ ,
+
+ tags = json['tags'] == null ? null :
+
+
+ (json['tags'] as List)
+ .map((e) => nativeFromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ imageUrl =
+
+ nativeFromJson(json['imageUrl'])
+
+
+
+
+ {
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['title'] =
+
+ nativeToJson(title)
+
+;
+
+
+
+ if (genre != null) {
+ json['genre'] =
+
+ nativeToJson(genre)
+
+;
+ }
+
+
+
+ if (tags != null) {
+ json['tags'] =
+
+
+ tags?.map((e) => nativeToJson(e)).toList()
+
+
+;
+ }
+
+
+
+ json['imageUrl'] =
+
+ nativeToJson(imageUrl)
+
+;
+
+
+ return json;
+ }
+
+ GetActorByIdActorMainActors({
+
+ required this.id,
+
+ required this.title,
+
+ this.genre,
+
+ this.tags,
+
+ required this.imageUrl,
+
+ });
+}
+
+
+
+ class GetActorByIdActorSupportingActors {
+
+ String id;
+
+
+ String title;
+
+
+ String? genre;
+
+
+ List? tags;
+
+
+ String imageUrl;
+
+
+
+
+
+
+ GetActorByIdActorSupportingActors.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ title =
+
+ nativeFromJson(json['title'])
+
+
+
+ ,
+
+ genre = json['genre'] == null ? null :
+
+ nativeFromJson(json['genre'])
+
+
+
+ ,
+
+ tags = json['tags'] == null ? null :
+
+
+ (json['tags'] as List)
+ .map((e) => nativeFromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ imageUrl =
+
+ nativeFromJson(json['imageUrl'])
+
+
+
+
+ {
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['title'] =
+
+ nativeToJson(title)
+
+;
+
+
+
+ if (genre != null) {
+ json['genre'] =
+
+ nativeToJson(genre)
+
+;
+ }
+
+
+
+ if (tags != null) {
+ json['tags'] =
+
+
+ tags?.map((e) => nativeToJson(e)).toList()
+
+
+;
+ }
+
+
+
+ json['imageUrl'] =
+
+ nativeToJson(imageUrl)
+
+;
+
+
+ return json;
+ }
+
+ GetActorByIdActorSupportingActors({
+
+ required this.id,
+
+ required this.title,
+
+ this.genre,
+
+ this.tags,
+
+ required this.imageUrl,
+
+ });
+}
+
+
+
+ class GetActorByIdData {
+
+ GetActorByIdActor? actor;
+
+
+
+
+
+
+ GetActorByIdData.fromJson(dynamic json):
+ actor = json['actor'] == null ? null :
+
+ GetActorByIdActor.fromJson(json['actor'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ if (actor != null) {
+ json['actor'] =
+
+ actor!.toJson()
+
+;
+ }
+
+
+ return json;
+ }
+
+ GetActorByIdData({
+
+ this.actor,
+
+ });
+}
+
+
+
+ class GetActorByIdVariables {
+
+ String id;
+
+
+
+
+
+ @Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
+
+
+ GetActorByIdVariables.fromJson(Map json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+ return json;
+ }
+
+ GetActorByIdVariables({
+
+ required this.id,
+
+ });
+}
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/lib/movies_connector/get_current_user.dart b/dataconnect/flutter-movie/lib/movies_connector/get_current_user.dart
new file mode 100644
index 00000000..38a7e191
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movies_connector/get_current_user.dart
@@ -0,0 +1,763 @@
+part of movies_connector;
+
+class GetCurrentUserVariablesBuilder {
+
+
+ FirebaseDataConnect _dataConnect;
+
+ GetCurrentUserVariablesBuilder(this._dataConnect, );
+ Deserializer dataDeserializer = (dynamic json) => GetCurrentUserData.fromJson(jsonDecode(json));
+
+ Future> execute() {
+ return this.ref().execute();
+ }
+ QueryRef ref() {
+
+ return _dataConnect.query("GetCurrentUser", dataDeserializer, emptySerializer, null);
+ }
+}
+
+
+ class GetCurrentUserUser {
+
+ String id;
+
+
+ String username;
+
+
+ List reviews;
+
+
+ List favoriteMovies;
+
+
+
+
+
+
+ GetCurrentUserUser.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ username =
+
+ nativeFromJson(json['username'])
+
+
+
+ ,
+
+ reviews =
+
+
+ (json['reviews'] as List)
+ .map((e) => GetCurrentUserUserReviews.fromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ favoriteMovies =
+
+
+ (json['favoriteMovies'] as List)
+ .map((e) => GetCurrentUserUserFavoriteMovies.fromJson(e))
+ .toList()
+
+
+
+
+
+ {
+
+
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['username'] =
+
+ nativeToJson(username)
+
+;
+
+
+
+ json['reviews'] =
+
+
+ reviews.map((e) => e.toJson()).toList()
+
+
+;
+
+
+
+ json['favoriteMovies'] =
+
+
+ favoriteMovies.map((e) => e.toJson()).toList()
+
+
+;
+
+
+ return json;
+ }
+
+ GetCurrentUserUser({
+
+ required this.id,
+
+ required this.username,
+
+ required this.reviews,
+
+ required this.favoriteMovies,
+
+ });
+}
+
+
+
+ class GetCurrentUserUserReviews {
+
+ String id;
+
+
+ int? rating;
+
+
+ DateTime reviewDate;
+
+
+ String? reviewText;
+
+
+ GetCurrentUserUserReviewsMovie movie;
+
+
+
+
+
+
+ GetCurrentUserUserReviews.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ rating = json['rating'] == null ? null :
+
+ nativeFromJson(json['rating'])
+
+
+
+ ,
+
+ reviewDate =
+
+ nativeFromJson(json['reviewDate'])
+
+
+
+ ,
+
+ reviewText = json['reviewText'] == null ? null :
+
+ nativeFromJson(json['reviewText'])
+
+
+
+ ,
+
+ movie =
+
+ GetCurrentUserUserReviewsMovie.fromJson(json['movie'])
+
+
+
+
+ {
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ if (rating != null) {
+ json['rating'] =
+
+ nativeToJson(rating)
+
+;
+ }
+
+
+
+ json['reviewDate'] =
+
+ nativeToJson(reviewDate)
+
+;
+
+
+
+ if (reviewText != null) {
+ json['reviewText'] =
+
+ nativeToJson(reviewText)
+
+;
+ }
+
+
+
+ json['movie'] =
+
+ movie.toJson()
+
+;
+
+
+ return json;
+ }
+
+ GetCurrentUserUserReviews({
+
+ required this.id,
+
+ this.rating,
+
+ required this.reviewDate,
+
+ this.reviewText,
+
+ required this.movie,
+
+ });
+}
+
+
+
+ class GetCurrentUserUserReviewsMovie {
+
+ String id;
+
+
+ String title;
+
+
+
+
+
+
+ GetCurrentUserUserReviewsMovie.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ title =
+
+ nativeFromJson(json['title'])
+
+
+
+
+ {
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['title'] =
+
+ nativeToJson(title)
+
+;
+
+
+ return json;
+ }
+
+ GetCurrentUserUserReviewsMovie({
+
+ required this.id,
+
+ required this.title,
+
+ });
+}
+
+
+
+ class GetCurrentUserUserFavoriteMovies {
+
+ GetCurrentUserUserFavoriteMoviesMovie movie;
+
+
+
+
+
+
+ GetCurrentUserUserFavoriteMovies.fromJson(dynamic json):
+ movie =
+
+ GetCurrentUserUserFavoriteMoviesMovie.fromJson(json['movie'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['movie'] =
+
+ movie.toJson()
+
+;
+
+
+ return json;
+ }
+
+ GetCurrentUserUserFavoriteMovies({
+
+ required this.movie,
+
+ });
+}
+
+
+
+ class GetCurrentUserUserFavoriteMoviesMovie {
+
+ String id;
+
+
+ String title;
+
+
+ String? genre;
+
+
+ String imageUrl;
+
+
+ int? releaseYear;
+
+
+ double? rating;
+
+
+ String? description;
+
+
+ List? tags;
+
+
+ List metadata;
+
+
+
+
+
+
+ GetCurrentUserUserFavoriteMoviesMovie.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ title =
+
+ nativeFromJson(json['title'])
+
+
+
+ ,
+
+ genre = json['genre'] == null ? null :
+
+ nativeFromJson(json['genre'])
+
+
+
+ ,
+
+ imageUrl =
+
+ nativeFromJson(json['imageUrl'])
+
+
+
+ ,
+
+ releaseYear = json['releaseYear'] == null ? null :
+
+ nativeFromJson(json['releaseYear'])
+
+
+
+ ,
+
+ rating = json['rating'] == null ? null :
+
+ nativeFromJson(json['rating'])
+
+
+
+ ,
+
+ description = json['description'] == null ? null :
+
+ nativeFromJson(json['description'])
+
+
+
+ ,
+
+ tags = json['tags'] == null ? null :
+
+
+ (json['tags'] as List)
+ .map((e) => nativeFromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ metadata =
+
+
+ (json['metadata'] as List)
+ .map((e) => GetCurrentUserUserFavoriteMoviesMovieMetadata.fromJson(e))
+ .toList()
+
+
+
+
+
+ {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['title'] =
+
+ nativeToJson(title)
+
+;
+
+
+
+ if (genre != null) {
+ json['genre'] =
+
+ nativeToJson(genre)
+
+;
+ }
+
+
+
+ json['imageUrl'] =
+
+ nativeToJson(imageUrl)
+
+;
+
+
+
+ if (releaseYear != null) {
+ json['releaseYear'] =
+
+ nativeToJson(releaseYear)
+
+;
+ }
+
+
+
+ if (rating != null) {
+ json['rating'] =
+
+ nativeToJson(rating)
+
+;
+ }
+
+
+
+ if (description != null) {
+ json['description'] =
+
+ nativeToJson(description)
+
+;
+ }
+
+
+
+ if (tags != null) {
+ json['tags'] =
+
+
+ tags?.map((e) => nativeToJson(e)).toList()
+
+
+;
+ }
+
+
+
+ json['metadata'] =
+
+
+ metadata.map((e) => e.toJson()).toList()
+
+
+;
+
+
+ return json;
+ }
+
+ GetCurrentUserUserFavoriteMoviesMovie({
+
+ required this.id,
+
+ required this.title,
+
+ this.genre,
+
+ required this.imageUrl,
+
+ this.releaseYear,
+
+ this.rating,
+
+ this.description,
+
+ this.tags,
+
+ required this.metadata,
+
+ });
+}
+
+
+
+ class GetCurrentUserUserFavoriteMoviesMovieMetadata {
+
+ String? director;
+
+
+
+
+
+
+ GetCurrentUserUserFavoriteMoviesMovieMetadata.fromJson(dynamic json):
+ director = json['director'] == null ? null :
+
+ nativeFromJson(json['director'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ if (director != null) {
+ json['director'] =
+
+ nativeToJson(director)
+
+;
+ }
+
+
+ return json;
+ }
+
+ GetCurrentUserUserFavoriteMoviesMovieMetadata({
+
+ this.director,
+
+ });
+}
+
+
+
+ class GetCurrentUserData {
+
+ GetCurrentUserUser? user;
+
+
+
+
+
+
+ GetCurrentUserData.fromJson(dynamic json):
+ user = json['user'] == null ? null :
+
+ GetCurrentUserUser.fromJson(json['user'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ if (user != null) {
+ json['user'] =
+
+ user!.toJson()
+
+;
+ }
+
+
+ return json;
+ }
+
+ GetCurrentUserData({
+
+ this.user,
+
+ });
+}
+
+
+
+
+
+
+
diff --git a/dataconnect/flutter-movie/lib/movies_connector/get_movie_by_id.dart b/dataconnect/flutter-movie/lib/movies_connector/get_movie_by_id.dart
new file mode 100644
index 00000000..56cc681c
--- /dev/null
+++ b/dataconnect/flutter-movie/lib/movies_connector/get_movie_by_id.dart
@@ -0,0 +1,912 @@
+part of movies_connector;
+
+class GetMovieByIdVariablesBuilder {
+ String id;
+
+
+ FirebaseDataConnect _dataConnect;
+
+ GetMovieByIdVariablesBuilder(this._dataConnect, {required String this.id,});
+ Deserializer dataDeserializer = (dynamic json) => GetMovieByIdData.fromJson(jsonDecode(json));
+ Serializer varsSerializer = (GetMovieByIdVariables vars) => jsonEncode(vars.toJson());
+ Future> execute() {
+ return this.ref().execute();
+ }
+ QueryRef ref() {
+ GetMovieByIdVariables vars=GetMovieByIdVariables(id: id,);
+
+ return _dataConnect.query("GetMovieById", dataDeserializer, varsSerializer, vars);
+ }
+}
+
+
+ class GetMovieByIdMovie {
+
+ String id;
+
+
+ String title;
+
+
+ String imageUrl;
+
+
+ int? releaseYear;
+
+
+ String? genre;
+
+
+ double? rating;
+
+
+ String? description;
+
+
+ List? tags;
+
+
+ List metadata;
+
+
+ List mainActors;
+
+
+ List supportingActors;
+
+
+ List reviews;
+
+
+
+
+
+
+ GetMovieByIdMovie.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ title =
+
+ nativeFromJson(json['title'])
+
+
+
+ ,
+
+ imageUrl =
+
+ nativeFromJson(json['imageUrl'])
+
+
+
+ ,
+
+ releaseYear = json['releaseYear'] == null ? null :
+
+ nativeFromJson(json['releaseYear'])
+
+
+
+ ,
+
+ genre = json['genre'] == null ? null :
+
+ nativeFromJson(json['genre'])
+
+
+
+ ,
+
+ rating = json['rating'] == null ? null :
+
+ nativeFromJson(json['rating'])
+
+
+
+ ,
+
+ description = json['description'] == null ? null :
+
+ nativeFromJson(json['description'])
+
+
+
+ ,
+
+ tags = json['tags'] == null ? null :
+
+
+ (json['tags'] as List)
+ .map((e) => nativeFromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ metadata =
+
+
+ (json['metadata'] as List)
+ .map((e) => GetMovieByIdMovieMetadata.fromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ mainActors =
+
+
+ (json['mainActors'] as List)
+ .map((e) => GetMovieByIdMovieMainActors.fromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ supportingActors =
+
+
+ (json['supportingActors'] as List)
+ .map((e) => GetMovieByIdMovieSupportingActors.fromJson(e))
+ .toList()
+
+
+
+
+ ,
+
+ reviews =
+
+
+ (json['reviews'] as List)
+ .map((e) => GetMovieByIdMovieReviews.fromJson(e))
+ .toList()
+
+
+
+
+
+ {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['title'] =
+
+ nativeToJson(title)
+
+;
+
+
+
+ json['imageUrl'] =
+
+ nativeToJson(imageUrl)
+
+;
+
+
+
+ if (releaseYear != null) {
+ json['releaseYear'] =
+
+ nativeToJson(releaseYear)
+
+;
+ }
+
+
+
+ if (genre != null) {
+ json['genre'] =
+
+ nativeToJson(genre)
+
+;
+ }
+
+
+
+ if (rating != null) {
+ json['rating'] =
+
+ nativeToJson(rating)
+
+;
+ }
+
+
+
+ if (description != null) {
+ json['description'] =
+
+ nativeToJson(description)
+
+;
+ }
+
+
+
+ if (tags != null) {
+ json['tags'] =
+
+
+ tags?.map((e) => nativeToJson(e)).toList()
+
+
+;
+ }
+
+
+
+ json['metadata'] =
+
+
+ metadata.map((e) => e.toJson()).toList()
+
+
+;
+
+
+
+ json['mainActors'] =
+
+
+ mainActors.map((e) => e.toJson()).toList()
+
+
+;
+
+
+
+ json['supportingActors'] =
+
+
+ supportingActors.map((e) => e.toJson()).toList()
+
+
+;
+
+
+
+ json['reviews'] =
+
+
+ reviews.map((e) => e.toJson()).toList()
+
+
+;
+
+
+ return json;
+ }
+
+ GetMovieByIdMovie({
+
+ required this.id,
+
+ required this.title,
+
+ required this.imageUrl,
+
+ this.releaseYear,
+
+ this.genre,
+
+ this.rating,
+
+ this.description,
+
+ this.tags,
+
+ required this.metadata,
+
+ required this.mainActors,
+
+ required this.supportingActors,
+
+ required this.reviews,
+
+ });
+}
+
+
+
+ class GetMovieByIdMovieMetadata {
+
+ String? director;
+
+
+
+
+
+
+ GetMovieByIdMovieMetadata.fromJson(dynamic json):
+ director = json['director'] == null ? null :
+
+ nativeFromJson(json['director'])
+
+
+
+
+ {
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ if (director != null) {
+ json['director'] =
+
+ nativeToJson(director)
+
+;
+ }
+
+
+ return json;
+ }
+
+ GetMovieByIdMovieMetadata({
+
+ this.director,
+
+ });
+}
+
+
+
+ class GetMovieByIdMovieMainActors {
+
+ String id;
+
+
+ String name;
+
+
+ String imageUrl;
+
+
+
+
+
+
+ GetMovieByIdMovieMainActors.fromJson(dynamic json):
+ id =
+
+ nativeFromJson(json['id'])
+
+
+
+ ,
+
+ name =
+
+ nativeFromJson(json['name'])
+
+
+
+ ,
+
+ imageUrl =
+
+ nativeFromJson(json['imageUrl'])
+
+
+
+
+ {
+
+
+
+
+
+
+
+ }
+
+
+ Map toJson() {
+ Map json = {};
+
+
+ json['id'] =
+
+ nativeToJson(id)
+
+;
+
+
+
+ json['name'] =
+
+ nativeToJson(name)
+
+;
+
+
+
+ json['imageUrl'] =
+
+ nativeToJson