├── .env.sample ├── .gitignore ├── .gitpod.yml ├── .vscode └── settings.json ├── README.md ├── astra.json ├── data ├── bonus │ ├── dataset_action.md │ ├── dataset_anime.md │ ├── dataset_awardwinning.md │ ├── dataset_children.md │ ├── dataset_comedies.md │ ├── dataset_documentaries.md │ ├── dataset_dramas.md │ ├── dataset_fantasy.md │ ├── dataset_french.md │ ├── dataset_horror.md │ ├── dataset_independent.md │ ├── dataset_italian.md │ ├── dataset_music.md │ ├── dataset_romance.md │ ├── dataset_scifi.md │ └── dataset_thriller.md └── movies_by_genre.csv ├── functions ├── getGenres.js └── getMovies.js ├── images ├── Filexplorer0.png ├── OpenPorts.png ├── allow.png ├── astra-cli-dsbulk-2.png ├── astra-cli-setup-2.png ├── astra-create-token.gif ├── chrome-logo.svg ├── create_astra_db.png ├── deploy-1.png ├── deploy-2.png ├── deploy-3b.png ├── deploy-4.png ├── deploy-4sitename.png ├── deploy-4skeletal.png ├── deploy-5.png ├── deploy-to-netlify.gif ├── deployed_netflix_clone.png ├── env_file.png ├── firefox-logo.svg ├── gitpod-01-home-annotated.png ├── gitpod-02-url.png ├── gitpod_trick.png ├── graphql-back.png ├── graphql-playground-2.png ├── graphql-playground-3.png ├── graphql-playground-4.png ├── graphql-playground-5.png ├── graphql-playground-6.png ├── graphql-playground.png ├── netflix-badge.png ├── netlify-build.png ├── netlify-connect-01.png ├── netlify-deploy-prod-2.png ├── netlify-install-cli.png ├── netlify-link-2.png ├── netlify-login-2.png ├── netlify-open-site-2.png ├── netlify_env_import.png ├── newbrowser1.png ├── open-playground-2-wh.png ├── open-playground-2.png ├── playground-1.png ├── playground-2.png ├── playground-3.png ├── preview.png ├── tabs-vs-playgroundtabs-labeled-2.png ├── ui.png └── waiting_for_authorization-2.png ├── know_your_gitpod.md ├── netlify.toml ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── slides └── slides.pdf └── src ├── App.css ├── App.js ├── components ├── Card.js ├── HeroSection.js ├── NavBar.js └── Section.js └── index.js /.env.sample: -------------------------------------------------------------------------------- 1 | # Ensure to fully replace "your_token" AND "your_endpoint" with the token 2 | # and endpoint values from your database (keep the quotes). 3 | ASTRA_DB_APPLICATION_TOKEN="your_token" 4 | ASTRA_DB_GRAPHQL_URL="your_endpoint" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | node_modules 3 | .env 4 | .netlify 5 | 6 | # 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - name: workshop-graphql-netflix 3 | before: | 4 | cd /workspace/workshop-graphql-netflix 5 | curl -Ls "https://dtsx.io/get-astra-cli" | bash >> ./install.log 6 | printf 'export PATH="$HOME%s:$PATH"\n' "/.astra/cli" >> $HOME/.bashrc 7 | printf 'unset JAVA_TOOL_OPTIONS\n' >> $HOME/.bashrc 8 | nvm install 16.13.0 9 | npm install -g npm@latest 10 | npm install -g netlify-cli 11 | npm install 12 | command: | 13 | source /home/gitpod/.astra/cli/astra-init.sh 14 | echo -e "\n\n *** Astra DB Netflix Clone READY ... Let's go ! ***\n" 15 | gp open README.md 16 | ports: 17 | - port: 8888 18 | onOpen: open-preview 19 | - port: 3000 20 | onOpen: ignore 21 | github: 22 | prebuilds: 23 | master: true 24 | branches: true 25 | pullRequests: true 26 | pullRequestsFromForks: false 27 | addCheck: true 28 | addComment: false 29 | addBadge: true 30 | addLabel: false 31 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.editor.enablePreviewFromCodeNavigation": true, 3 | "workbench.editor.enablePreviewFromQuickOpen": true, 4 | "workbench.editor.enablePreview": true, 5 | "workbench.editorAssociations": { 6 | "*.md": "vscode.markdown.preview.editor" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # 🎓 Netflix Clone using Astra DB and GraphQL 3 | 4 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/from-referrer/) 5 | [![License Apache2](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0) 6 | [![Discord](https://img.shields.io/discord/685554030159593522)](https://discord.com/widget?id=685554030159593522&theme=dark) 7 | 8 | *50 minutes, Intermediate, [Start Building](#1-login-or-register-to-astradb-and-create-database)* 9 | 10 | A simple **ReactJS** Netflix homepage clone running on *Astra DB* that leverages the GraphQL API with *paging* and *infinite scrolling.* 11 | This application is the result of the collaboration between [Ania Kubow](https://www.youtube.com/channel/UC5DNytAJ6_FISueUfzZCVsw) and the Datastax Developer Advocate team. 12 | 13 | 14 | 15 | See the [Video Demo](https://imgur.com/3ns3UJB) of what you will build! 16 | 17 | ![image](https://github.com/datastaxdevs/workshop-graphql-netflix/raw/master/images/ui.png) 18 | 19 | ## 🎯 Objectives 20 | * Build and run a Netflix clone. 21 | * Learn **GraphQL API** and how to use it with a database to create the tables and navigate the data. 22 | * Learn about **pagination** and **infinite scrolling** in a Web UI. 23 | * Leverage Netlify and DataStax Astra DB. 24 | * Deploy the Netflix clone to production with Netlify. 25 | 26 | ## ℹ️ Frequently asked questions ℹ️ 27 | 28 |
29 | Can I run the workshop on my computer? 30 | 31 | There is nothing preventing you from running the workshop on your own machine. 32 | If you do so, you will need 33 | * git installed on your local system 34 | * [node 15 and npm 7 or later](https://www.whitesourcesoftware.com/free-developer-tools/blog/update-node-js/) 35 | 36 | You will have to adapt commands and paths based on your environment and install the dependencies by yourself. **We won't provide support** to keep on track with schedule. However, we will do our best to give you the info you need to be successful. 37 | 38 |
39 | 40 |
41 | What other prerequisites are there? 42 | 43 | * You will need a github account 44 | * You will also need Netlify and Astra DB accounts, but we'll work through that in the exercises 45 | * Use **Chrome** or **Firefox** for the best experience. Other browsers are great, but don't work well with the GitPod integration we use a bit later. 46 | 47 |
48 | 49 |
50 | Do I need to pay for anything for this workshop? 51 | 52 | **No.** All tools and services we provide here are FREE. 53 | 54 |
55 | 56 |
57 | Will I get a certificate if I attend this workshop? 58 | 59 | Yes, but attending the session is not enough. You need to complete the homeworks detailed below and you will get a participation badge. 60 | 61 |
62 | 63 | 64 | ## Materials for the Session 65 | 66 | It doesn't matter if you join our workshop live or you prefer to do at your own pace, we have you covered. In this repository, you'll find everything you need for this workshop: 67 | 68 | - [Slide deck](slides/slides.pdf) 69 | - [Discord chat](https://dtsx.io/discord) 70 | - ["cassandra" on StackOverflow](https://stackoverflow.com/questions/tagged/cassandra) 71 | - ["cassandra" on DBA StackExchange](https://dba.stackexchange.com/questions/tagged/cassandra) 72 | 73 | 74 | # Let's start 75 | 76 | ## Table of contents 77 | 78 | ### Part I - DB Setup & Data Ingest 79 | 1. [Create Astra DB Instance](#1-login-or-register-to-astradb-and-create-database) 80 | 2. [Create a security token](#2-create-a-security-token) 81 | 3. [Create table for genres with GraphQL](#3-create-table-for-genres-with-graphql) 82 | 4. [Insert genre data with GraphQL](#4-insert-genre-data-with-graphql) 83 | 5. [Retrieve genres with GraphQL](#5-retrieve-genres-with-graphql) 84 | 6. [Create a table for movies](#6-create-a-table-for-movies) 85 | 7. [Insert a few movies](#7-insert-a-few-movies) 86 | 8. [Retrieve movies: Pagination](#8-retrieve-movies-pagination) 87 | 88 | ### Part II - Build and Deploy Front-End 89 | 90 | 1. [Deploy skeletal GUI to Netlify](#1-deploy-skeletal-gui-to-netlify) 91 | 2. [Launch Gitpod from YOUR Github repo](#2-launch-gitpod-from-your-github-repo) 92 | 3. [Set up and use `astra-cli`](#3-set-up-and-use-astra-cli) 93 | 4. [Serverless Functions](#4-serverless-functions) 94 | 5. [Fetching from the Front-End](#5-fetching-from-the-front-end) 95 | 6. [Install the Netlify CLI](#6-install-the-netlify-cli) 96 | 7. [Provide DB connection parameters](#7-provide-db-connection-parameters) 97 | 8. [Run the app in dev mode](#8-run-the-app-in-dev-mode) 98 | 9. [Connect to your Netlify site](#9-connect-to-your-netlify-site) 99 | 10. [Deploy in production!](#10-deploy-in-production) 100 | 101 | [**🎓 Complete the assignment, receive your Badge!**](#homework) 102 | 103 | ### Extra resources 104 | 105 | - [Intro to GraphQL Workshop](https://github.com/datastaxdevs/workshop-intro-to-graphql) 106 | - [React starter using NPX](https://github.com/datastaxdevs/react-basics) 107 | - [React ToDo app](https://github.com/datastaxdevs/appdev-week1-todolist) 108 | - [What is JamStack?](https://github.com/datastaxdevs/workshop-battlestax/blob/master/README_JAM.md) 109 | - [Video tutorial with Ania Kubow](#video-tutorial-with-ania-kubow) 110 | 111 | # Part 1 - DB Setup & Data Ingest 112 | 113 | ## 1. Login or Register to AstraDB and create database 114 | 115 | > 🎁 *When creating your instance, use the promotion code **ANIA200** to get 200$ of additional free credit!* 116 | 117 | _**`ASTRA DB`** is the simplest way to run Cassandra with zero operations at all - just push the button and get your cluster. No credit card required, 40M read/write operations and about 80GB storage monthly for free - sufficient to run small production workloads. If you use up your credits the databases will pause, no charge, and you will be given the option to upgrade to a higher tier._ 118 | 119 | Leveraging [Database creation guide](https://awesome-astra.github.io/docs/pages/astra/create-instance/#c-procedure) create a database. **Right-Click** the following button and *Open in a new TAB.* 120 | 121 | 122 | 123 | |Field|Value| 124 | |---|---| 125 | |**Database Name**| `workshops`| 126 | |**Keyspace Name**| `netflix`| 127 | |**Regions**| Select `GOOGLE CLOUD`, then an Area close to you, then a region with no LOCK 🔒 icons: the LOCKed regions are the region not accessible to the Free Tier.| 128 | 129 | > **ℹ️ Note:** If you already have a database `workshops`, simply add a keyspace `netflix` using the `Add Keyspace` button on the bottom right hand corner of the DB Dashboard page. You may have to "Resume" the database first in case it is in "hibernated" state. 130 | 131 | While the database is being created, you will also get a **Security token** (needed to authenticate with your database and start using it): 132 | **please IGNORE THIS ONE, as we will be soon creating a new, more powerful token for today**. 133 | 134 | The status will change from `Pending` to `Active` when the database is ready, this usually only takes 2-3 minutes. 135 | 136 | 137 | ## 2. Create a security token 138 | 139 | > Note: this step is very important, as the token generated automatically for you with 140 | > the database lacks some permissions we'll use in the workshop. 141 | 142 | [Create a token for your app](https://awesome-astra.github.io/docs/pages/astra/create-token/#c-procedure), _using the **"Database Administrator"** role_. 143 | Keep it handy for later use (best to download it in CSV format, as the values 144 | will not be visible afterward). 145 | This will provide authentication later when interacting with the database. 146 | Today, in particular, you'll need the string labeled "token" (the one starting with `AstraCS:...`). 147 | 148 | > **⚠️ Important** 149 | > The instructor will show the token creation on screen, 150 | > but will then destroy it immediately for security reasons. 151 | 152 | 153 | ## 3. Create table for genres with GraphQL 154 | 155 | ✅ **Step 3a:** Open **GraphQL Playground**: 156 | 157 | 0. Ensure you are logged on to your [Astra](https://astra.datastax.com) account 158 | 1. Click on the "workshops" database on the left (expanding the list if needed) 159 | 2. Click `Connect` TAB 160 | 3. Click the `APIs` connection method 161 | 4. Make sure `GraphQL API` is selected 162 | 5. Locate the link to your GraphQL Playground in the text 163 | 164 | ![Open Astra DB GraphQL Playground image](https://github.com/datastaxdevs/workshop-graphql-netflix/raw/master/images/open-playground-2-wh.png) 165 | 166 |
167 | Click here if you are not using the "New Astra Experience" UI (yet) 168 | 169 | ![Open Astra DB GraphQL Playground image, old Astra UI](images/open-playground-2.png) 170 | 171 |
172 | 173 | **Note**: in the following, we will refer to "playground tabs". These are _not_ the tabs 174 | in your browser, rather they are tabs _within_ the Playground application, 175 | to switch between the (logically distinct) realms of "managing schema" and "managing data in the tables" 176 | (more on that later). 177 | 178 | ![Playground tabs VS Browser tabs](https://github.com/datastaxdevs/workshop-graphql-netflix/raw/master/images/tabs-vs-playgroundtabs-labeled-2.png) 179 | 180 | ✅ **Step 3b:** Provide the database token as header 181 | 182 | In the GraphQL Playground, **Populate HTTP HEADER** variable `x-cassandra-token` on the bottom of the page with your token (including the `AstraCS:` part). 183 | _This is the "Database Administrator" token you created earlier on the Astra DB dashboard (Step 2 above)._ 184 | 185 | 186 |
187 | 188 | Note: make sure you are on the graphql-schema playground tab in this step. Click here to show image. 189 | 190 | 191 | ![GraphQL Playground and token header, Schema playground tab](images/graphql-playground.png) 192 | 193 |
194 | 195 | > Note: the GraphQL Playground starts with a ready-to-use _temporary token_ as the `x-cassandra-token` header. But you want the queries run in the Playground 196 | > to be identical to those that the Netlify functions will run from code, so **please replace the token with your DB token as instructed**. 197 | 198 | ✅ **Step 3c:** In GraphQL Playground, create the `reference_list` table: 199 | 200 | Copy the following **mutation** to the left panel 201 | 202 | ```yaml 203 | mutation createReferenceList { 204 | reference_list: createTable( 205 | keyspaceName:"netflix", 206 | tableName:"reference_list", 207 | ifNotExists:true 208 | partitionKeys: [ 209 | { name: "label", type: {basic: TEXT} } 210 | ] 211 | clusteringKeys: [ 212 | { name: "value", type: {basic: TEXT}, order: "ASC" } 213 | ] 214 | ) 215 | } 216 | ``` 217 | 218 |
219 | and then use the big "play button" arrow in the center to execute it. Click for screenshot. 220 | 221 | ![image](images/playground-1.png) 222 | 223 |
224 | 225 | 226 | **GraphQL Playground troubleshooting** (covers this whole section) 227 | 228 | |Trouble| Shooting| 229 | |---|---| 230 | |Server cannot be reached | Add Astra token to headers (including `AstraCS:...`; check quotes) | 231 | |Server cannot be reached (second playground tab) | Check playground target URL ends with `netflix` | 232 | Response not successful: Received status code 401 | Same as "server cannot be reached" | 233 | | Response not successful: Received status code 404 | Check spelling of keyspace in target URL | 234 | |"Play" button does nothing| Ensure query is syntactically correct | 235 | "Validation error of type FieldUndefined" | Most likely query in the wrong playground tab, or writing to table not created yet | 236 | 237 | ## 4. Insert genre data with GraphQL 238 | 239 | ✅ **Step 4a:** Get to the API URL for your keyspace 240 | 241 | In graphQL playground, **change playground tab** to now use `graphql`. The Playground has its own address bar 242 | (**note**: it's _not_ the address bar of your browser). Edit the ending of the URL shown there, from `system` to the 243 | name of the keyspace: `netflix` 244 | 245 | ✅ **Step 4b:** Repeat the insertion of the `x-cassandra-token` header for this playground tab (as you did for the first one): 246 | 247 |
248 | Show me! 249 | 250 | ![image](images/graphql-playground-2.png) 251 | 252 |
253 | 254 | ✅ **Step 4c:** In the GraphQL Playground, run the mutation that writes genre data: 255 | 256 | Copy the following mutation on the left panel: 257 | 258 | ```yaml 259 | mutation insertGenres { 260 | action: insertreference_list(value: {label:"genre", value:"Action"}) { 261 | value{value} 262 | } 263 | anime: insertreference_list(value: {label:"genre", value:"Anime"}) { 264 | value{value} 265 | } 266 | award: insertreference_list(value: {label:"genre", value:"Award-Winning"}) { 267 | value{value} 268 | } 269 | children: insertreference_list(value: {label:"genre", value:"Children & Family"}) { 270 | value{value} 271 | } 272 | classic: insertreference_list(value: {label:"genre", value:"Classic"}) { 273 | value{value} 274 | } 275 | comedies: insertreference_list(value: {label:"genre", value:"Comedies"}) { 276 | value{value} 277 | } 278 | crime: insertreference_list(value: {label:"genre", value:"Crime"}) { 279 | value{value} 280 | } 281 | cult: insertreference_list(value: {label:"genre", value:"Cult"}) { 282 | value{value} 283 | } 284 | documentaries: insertreference_list(value: {label:"genre", value:"Documentaries"}) { 285 | value{value} 286 | } 287 | drama: insertreference_list(value: {label:"genre", value:"Dramas"}) { 288 | value{value} 289 | } 290 | fantasy: insertreference_list(value: {label:"genre", value:"Fantasy"}) { 291 | value{value} 292 | } 293 | french: insertreference_list(value: {label:"genre", value:"French"}) { 294 | value{value} 295 | } 296 | horror: insertreference_list(value: {label:"genre", value:"Horror"}) { 297 | value{value} 298 | } 299 | independent: insertreference_list(value: {label:"genre", value:"Independent"}) { 300 | value{value} 301 | } 302 | international: insertreference_list(value: {label:"genre", value:"International"}) { 303 | value{value} 304 | } 305 | italian: insertreference_list(value: {label:"genre", value:"Italian"}) { 306 | value{value} 307 | } 308 | musicmusicals: insertreference_list(value: {label:"genre", value:"Music & Musicals"}) { 309 | value{value} 310 | } 311 | realitytv: insertreference_list(value: {label:"genre", value:"Reality TV"}) { 312 | value{value} 313 | } 314 | romance: insertreference_list(value: {label:"genre", value:"Romance"}) { 315 | value{value} 316 | } 317 | scifi: insertreference_list(value: {label:"genre", value:"Sci-Fi"}) { 318 | value{value} 319 | } 320 | thriller: insertreference_list(value: {label:"genre", value:"Thriller"}) { 321 | value{value} 322 | } 323 | tvshow: insertreference_list(value: {label:"genre", value:"TV Show"}) { 324 | value{value} 325 | } 326 | } 327 | ``` 328 | 329 | then click on the big "play button" arrow in the center to execute the mutation 330 | 331 | ## 5. Retrieve genres with GraphQL 332 | 333 | ✅ **Step 5a:** In GraphQL Playground, not changing playground tab (stay on the second: "graphql", yeah) run the following query to read the `value` column of all table rows: 334 | 335 | ```yaml 336 | query getAllGenres { 337 | reference_list (value: {label:"genre"}) { 338 | values { 339 | value 340 | } 341 | } 342 | } 343 | ``` 344 | 345 |
346 | 347 | Show me! 348 | 349 | 350 | ![image](images/graphql-playground-3.png) 351 | 352 |
353 | 354 | ## 6. Create a table for movies 355 | 356 | ✅ **Step 6a:** Switch back to first playground tab ("graphql-schema"; the token header will be already set). 357 | 358 |
359 | 360 | Click for screenshot 361 | 362 | 363 | ![image](images/graphql-back.png) 364 | 365 |
366 | 367 | Use the following mutation to create a new table: 368 | 369 | ```yaml 370 | mutation createMoviesTable { 371 | movies_by_genre: createTable( 372 | keyspaceName:"netflix", 373 | tableName:"movies_by_genre", 374 | ifNotExists: true, 375 | partitionKeys: [ 376 | { name: "genre", type: {basic: TEXT} } 377 | ] 378 | clusteringKeys: [ 379 | { name: "year", type: {basic: INT}, order: "DESC" }, 380 | { name: "title", type: {basic: TEXT}, order: "ASC" } 381 | ] 382 | values: [ 383 | { name: "synopsis", type: {basic: TEXT} }, 384 | { name: "duration", type: {basic: INT} }, 385 | { name: "thumbnail", type: {basic: TEXT} } 386 | ] 387 | ) 388 | } 389 | ``` 390 | 391 |
392 | 393 | Show me! 394 | 395 | 396 | ![image](images/graphql-playground-4.png) 397 | 398 |
399 | 400 | ## 7. Insert a few movies 401 | 402 | ✅ **Step 7a:** Go to playground tab "graphql" again. 403 | 404 |
405 | 406 | Click for screenshot 407 | 408 | 409 | ![image](images/graphql-playground-2.png) 410 | 411 |
412 | 413 | Use the following mutation to populate the `movies_by_genre` table with four movies: 414 | 415 | ```yaml 416 | mutation insertMovies { 417 | inception: insertmovies_by_genre( 418 | value: { 419 | genre:"Sci-Fi", 420 | year:2010, 421 | title:"Inception", 422 | synopsis:"Cobb steals information from his targets by entering their dreams.", 423 | duration:121, 424 | thumbnail:"https://i.imgur.com/RPa4UdO.mp4"}) { 425 | value{title} 426 | } 427 | 428 | prometheus: insertmovies_by_genre(value: { 429 | genre:"Sci-Fi", 430 | year:2012, 431 | title:"Prometheus", 432 | synopsis:"After a clue to mankind's origins is discovered, explorers are sent to the darkest corner of the universe.", 433 | duration:134, 434 | thumbnail:"https://i.imgur.com/L8k6Bau.mp4"}) { 435 | value{title} 436 | } 437 | 438 | aliens: insertmovies_by_genre(value: { 439 | genre:"Sci-Fi", 440 | year:1986, 441 | title:"Aliens", 442 | synopsis:"Ellen Ripley is sent back to the planet LV-426 to establish contact with a terraforming colony.", 443 | duration:134, 444 | thumbnail:"https://i.imgur.com/QvkrnyZ.mp4"}) { 445 | value{title} 446 | } 447 | 448 | bladeRunner: insertmovies_by_genre(value: { 449 | genre:"Sci-Fi", 450 | year:1982, 451 | title:"Blade Runner", 452 | synopsis:"Young Blade Runner K's discovery of a long-buried secret leads him to track down former Blade Runner Rick Deckard.", 453 | duration:145, 454 | thumbnail:"https://i.imgur.com/xhhvmj1.mp4"}) { 455 | value{title} 456 | } 457 | } 458 | ``` 459 | 460 |
461 | 462 | Show me! 463 | 464 | 465 | ![image](images/graphql-playground-5.png) 466 | 467 |
468 | 469 | 470 | ## 8. Retrieve movies: Pagination 471 | 472 | ✅ **Step 8a:** In GraphQL Playground, not changing playground tab (stay on the second tab, "graphql", yeah) list values from the table with the following command: 473 | 474 | ```yaml 475 | query getMovieAction { 476 | movies_by_genre ( 477 | value: {genre:"Sci-Fi"}, 478 | orderBy: [year_DESC] 479 | ) { 480 | values { 481 | year, 482 | title, 483 | duration, 484 | synopsis, 485 | thumbnail 486 | } 487 | } 488 | } 489 | ``` 490 | 491 |
492 | 493 | Show me! 494 | 495 | 496 | ![image](images/graphql-playground-6.png) 497 | 498 |
499 | 500 | 501 | ✅ **Step 8b: Enable pagination:** On a small dataset, you can retrieve all values in the table at once; but in general, for performance or network reasons, you'll need pagination. Run a similar query as before, but this time asking for a _page size of 2_: 502 | 503 | ```yaml 504 | query getMovieActionPag1 { 505 | movies_by_genre ( 506 | value: {genre:"Sci-Fi"}, 507 | options: {pageSize: 2}, 508 | orderBy: [year_DESC] 509 | ) { 510 | values { 511 | year, 512 | title, 513 | duration, 514 | synopsis, 515 | thumbnail 516 | } 517 | pageState 518 | } 519 | } 520 | ``` 521 | 522 |
523 | 524 | Show me! 525 | 526 | 527 | ![image](images/playground-2.png) 528 | 529 |
530 | 531 | 532 | ✅ **Step 8c: Fetch the next page:** 533 | 534 | Notice that `pageState` now is also returned. Use it to fetch the next 2 items (next page): 535 | edit the next query to replace `YOUR_PAGE_STATE` with your own string value: 536 | 537 | ```yaml 538 | query getMovieActionNextPage { 539 | movies_by_genre ( 540 | value: {genre:"Sci-Fi"}, 541 | options: {pageSize: 2, pageState: "YOUR_PAGE_STATE"}, 542 | orderBy: [year_DESC] 543 | ) { 544 | values { 545 | year, 546 | title, 547 | duration, 548 | synopsis, 549 | thumbnail 550 | } 551 | pageState 552 | } 553 | } 554 | ``` 555 | 556 |
557 | 558 | Show me! 559 | 560 | 561 | ![image](images/playground-3.png) 562 | 563 |
564 | 565 | 566 | If you try to paste the _newly-obtained_ value for `pageState` and re-run the query, you get an empty list and a null `pageState` in return. D'oh! You had scrolled through all rows already: 567 | _this is how pagination signals the end of the full results list._ 568 | 569 | # Part 2 - Build and Deploy Front-End 570 | 571 | 572 | ## 1. Deploy skeletal GUI to Netlify 573 | 574 | ✅ **Step 1a: Netlify Button:** Click the following button to deploy the skeletal GUI to Netlify. There is no data since there is no database connected to the app (yet); we will connect the database to the app shortly. 575 | 576 | **Note**: preferrably Ctrl-click for a new tab. 577 | 578 |
579 | 580 | What does the Netlify deploy button do? 581 | 582 | 583 | The Netlify deploy button will: 584 | 585 | - Create a new repository for you on Github (Note: it's an unrelated _copy_, not a fork) 586 | - Create a site on Netlify (and deploy a nonworking build of the app, which lacks the DB connection parameters still) 587 | - Link the two together. 588 | 589 |
590 | 591 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/datastaxdevs/workshop-graphql-netflix) 592 | 593 |
Show me! 594 | 595 | ![Netlify button in action](images/deploy-to-netlify.gif) 596 | 597 |
598 | 599 | This will take a few minutes: 600 | 601 | - you may have to authenticate through Github in the process; 602 | - confirm the repo name and "Save & Deploy" when asked. 603 | 604 | _Note: if there is an existing account in Netlify, check the settings to make sure the Netlify account is connected to your Github account._ 605 | 606 |
Show me! 607 | 608 | ![Deploy to Netlify, "connected accounts"](images/netlify-connect-01.png) 609 | 610 |
611 | 612 | ✅ **Step 1b: Check the deploy logs:** Click on `Site deploy in progress` within the Netlify UI. 613 | 614 |
Show me! 615 | 616 | ![Deploy to Netlify, "site deploy in progress"](images/deploy-1.png) 617 | 618 |
619 | 620 | Then click the top deploy link to see the build process. 621 | 622 |
Show me! 623 | 624 | ![Deploy to Netlify, "Production/Building"](images/deploy-2.png) 625 | 626 |
627 | 628 | ✅ **Step 1c: Complete the build:** Wait until the build shows `Netlify Build Complete`, **When you see "_Pushing to repository..._"** you're ready to move on. 629 | 630 |
Show me! 631 | 632 | ![Deploy to Netlify, logs showing build finishing](images/deploy-3b.png) 633 | 634 |
635 | 636 | ✅ **Step 1d: Get back to your new site:** Scroll up to the top and click on the site name (it'll be after "_[your login]_'s Team" next to the Netlify button). Then locate your app's full URL and click to open it. 637 | 638 |
Show me! 639 | 640 | ![Deploy to Netlify, site name next to your team's name](images/deploy-4.png) 641 | 642 | Clicking on the full URL (something like `https://YOUR-SITE-NAME.netlify.app`) you will see the skeletal GUI (without the data from the database) in a new tab. Here is where to click: 643 | 644 | ![Deploy to Netlify, access the skeletal GUI](images/deploy-4sitename.png) 645 | 646 | and here, finally, your skeletal GUI in its full splendour: 647 | 648 | ![Netlify site, no data yet (skeletal GUI)](images/deploy-4skeletal.png) 649 | 650 |
651 | 652 | ## 2. Launch Gitpod from YOUR Github repo 653 | 654 | ✅ **Step 2a: Jump to YOUR repo:** Click on the `GitHub` in `Deploys from GitHub` to get to your new repository on Github. 655 | Scroll to where you were in the README. 656 | 657 |
Show me! 658 | 659 | ![Deploy to Netlify, ](images/deploy-5.png) 660 | 661 |
662 | 663 | > **Note** At this point, you MUST be reading this README from **YOUR** Github repository. 664 | > That is, if the address bar still says `https://github.com/datastaxdevs/...` please 665 | > head over to YOUR copy of the repo before going the Gitpod route! 666 | 667 | ✅ **Step 2b: Launch Gitpod:** 668 | 669 | Use this link to open Gitpod from **YOUR** repository! (_Tip: Ctrl-click on the button to open in new tab._) 670 | 671 | [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/from-referrer/) 672 | 673 | _Note: the button works on Chrome and Firefox._ 674 | 675 |
676 | Click to troubleshoot if you have another browser 677 | 678 | 679 | 680 |
681 | 682 | ℹ️ _It may take a few minutes (approx. 3-5) for GitPod to fully initialize. 683 | Please wait until the console in the lower half of Gitpod is responsive._ 684 | 685 | > You may see a dialog about "opening this workspace in VS Code Desktop": you can safely dismiss it. 686 | 687 | Gitpod will be your IDE from now on. If you are familiar with VSCode, you can probably 688 | just use it. Otherwise, take a moment to review a separate page 689 | ["Know your Gitpod"](know_your_gitpod.md) 690 | and then come back here. 691 | 692 | ## 3. Set up and use `astra-cli` 693 | 694 | You are going to use a CLI tool to simplify operations with Astra DB. The tool 695 | is [preinstalled](https://docs.datastax.com/en/astra-classic/docs/astra-cli/installation.html) 696 | on your Gitpod. 697 | 698 | ✅ **Step 3a: Set up the CLI:** 699 | 700 | Run the following in the Gitpod terminal and, 701 | when prompted, enter the `AstraCS:...` you obtained at the beginning. 702 | 703 | ``` bash 704 | astra setup 705 | ``` 706 | 707 |
708 | 709 | Show me! 710 | 711 | 712 | ![astra-cli](images/astra-cli-setup-2.png) 713 | 714 |
715 | 716 | 717 | ✅ **Step 3b: Bulk data load:** Load a large movie dataset in the database. 718 | This command installs and properly launches the `DSBulk` tool ([docs](https://docs.datastax.com/en/dsbulk/docs/dsbulkAbout.html)): 719 | 720 | ``` bash 721 | astra db load workshops \ 722 | -url data/movies_by_genre.csv \ 723 | -k netflix \ 724 | -t movies_by_genre 725 | ``` 726 | 727 |
728 | 729 | Show me! 730 | 731 | 732 | ![astra-cli](images/astra-cli-dsbulk-2.png) 733 | 734 |
735 | 736 |
Show the syntax for old versions of astra-cli (click here) 737 | 738 | Note: you should not need this. 739 | 740 | ```bash 741 | astra db dsbulk workshops load \ 742 | -url data/movies_by_genre.csv \ 743 | -k netflix \ 744 | -t movies_by_genre 745 | ``` 746 | 747 |
748 | 749 | > *Note*: we mock the trailers for these thousands of movies by using a handful 750 | > of them over and over. Don't be surprised if you'll see the wrong trailers 751 | > for your favorite movie! 752 | 753 | That's it! All 6000+ movies are now loaded and ready to go! 754 | 755 | ## 4. Serverless Functions 756 | 757 | > _Note_: this section and the next one ("Fetching from the Front-End") 758 | > are not steps to "perform", rather suggestions to dive in the app 759 | > code and figure out how the various parts (React components, Netlify 760 | > functions and finally the GraphQL server in Astra DB) fit together. 761 | > **You can skip these and jump to the [next practical step](#6-install-the-netlify-cli)** 762 | > if you are in a hurry, but please come back to these 763 | > for reference if you want to dissect the code! 764 | 765 |
Show me this section 766 | 767 | Take a look at `functions/getGenres.js` 768 | 769 | ```javascript 770 | const fetch = require('node-fetch') 771 | 772 | exports.handler = async function (event) { 773 | 774 | const body = JSON.parse(event.body) 775 | const url = process.env.ASTRA_DB_GRAPHQL_URL 776 | const query = ` 777 | query getAllGenres { 778 | reference_list ( 779 | value: { label: "genre"}, 780 | options: { 781 | pageSize: ${JSON.stringify(body.pageSize)}, 782 | pageState: ${JSON.stringify(body.pageState)} 783 | } 784 | ) { 785 | values { 786 | value 787 | } 788 | pageState 789 | } 790 | } 791 | ` 792 | 793 | const response = await fetch(url, { 794 | method: 'POST', 795 | headers: { 796 | "Content-Type": "application/json", 797 | "x-cassandra-token": process.env.ASTRA_DB_APPLICATION_TOKEN 798 | }, 799 | body: JSON.stringify({ query }) 800 | }) 801 | 802 | try { 803 | const responseBody = await response.json() 804 | return { 805 | statusCode: 200, 806 | body: JSON.stringify(responseBody) 807 | } 808 | } catch (e) { 809 | console.log(e) 810 | return { 811 | statusCode: 500, 812 | body: JSON.stringify(e) 813 | } 814 | } 815 | } 816 | ``` 817 | 818 | You'll notice the familiar GraphQL query "getAllGenres" you used previously in the playground. 819 | It's been modified a bit to utilize pagination. 820 | When building the GraphQL query, you pass the desired page size and state to the GraphQL API: 821 | 822 | ```javascript 823 | options: { 824 | pageSize: ${JSON.stringify(body.pageSize)}, 825 | pageState: ${JSON.stringify(body.pageState)} 826 | } 827 | ``` 828 | 829 | You ask the API server to give us back the table column "value" (containing the genre name), but also the page state 830 | for when you'll need the next page: 831 | 832 | ```javascript 833 | { 834 | values { 835 | value 836 | } 837 | pageState 838 | } 839 | ``` 840 | 841 | The serverless function `functions/getMovies.js` works in much the same way, but you provide the specific genre you want and the page size is hardcoded: 842 | 843 | ```javascript 844 | query { 845 | movies_by_genre ( 846 | value: { genre: ${JSON.stringify(genre)}}, 847 | orderBy: [year_DESC], 848 | options: { pageSize: 6, pageState: ${JSON.stringify(pageState)} } 849 | ) { 850 | values { 851 | year, 852 | title, 853 | duration, 854 | synopsis, 855 | thumbnail 856 | } 857 | pageState 858 | } 859 | } 860 | ``` 861 | 862 |
863 | 864 | ## 5. Fetching from the Front-End 865 | 866 |
Show me this section 867 | 868 | Take a look at how you fetch from these serverless functions from the front-end. Start in `src/App.js` 869 | 870 | There is a fetch method defined, that will retrieve a page of genres by calling the `getGenres` serverless function. 871 | 872 | ```javascript 873 | const fetchData = async () => { 874 | if (! isFetching) { 875 | setIsFetching(true) 876 | const response = await fetch("/.netlify/functions/getGenres", { 877 | method: "POST", 878 | body: JSON.stringify({pageState, pageSize}), 879 | }) 880 | const responseBody = await response.json() 881 | setPageState(responseBody.data.reference_list.pageState) 882 | setGenres(gs => (gs || []).concat(responseBody.data.reference_list.values)) 883 | setIsFetching(false) 884 | } 885 | } 886 | ``` 887 | 888 | You pass in the current `pageState` and `pageSize` state variables and receive a response from the serverless function. You then set the `pageState` var to the new pagestate, and set the `genres` state variable to the received data. (Note that you are concatenating the new data to the var, since you want to keep all previously fetched data, not replace). 889 | 890 | When rendering the page, you generate a `
` component for each genre, plus a `
` at the bottom, which will detect a `mouseEnter` event and trigger the loading of a new pageful of genres: 891 | 892 | ```javascript 893 | <> 894 | 895 | 896 | {genres && ( 897 |
898 | {Object.values(genres).map((genre) => ( 899 |
900 | ))} 901 |
902 | )} 903 |
{ 906 | setRequestedPage( np => np + 1 ) 907 | }} 908 | /> 909 | 910 | ``` 911 | 912 | The `
` component works in the same way, but you will fully replace the data in the `movies` variable this time. 913 | 914 | ```javascript 915 | const fetchData = async () => { 916 | const response = await fetch("/.netlify/functions/getMovies", { 917 | method: "POST", 918 | body: JSON.stringify({ genre: genre, pageState: pageState }), 919 | }) 920 | const responseBody = await response.json() 921 | setMovies(responseBody.data.movies_by_genre.values) 922 | setPageState(responseBody.data.movies_by_genre.pageState) 923 | } 924 | ``` 925 | 926 | Now that you know how the front-end works, launch the app! 927 | 928 |
929 | 930 | ## 6. Install the Netlify CLI 931 | 932 | In the `workshop-graphql-netflix` directory, run the following: 933 | 934 | ``` 935 | npm install -g netlify-cli 936 | ``` 937 | 938 |
Show me! 939 | 940 | ![Install Netlify CLI](images/netlify-install-cli.png) 941 | 942 |
943 | 944 | With the Netlify command-line interface you will build and deploy 945 | the application directly from the Gitpod terminal. 946 | 947 | ## 7. Provide DB connection parameters 948 | 949 | The "serverless functions" part of your app, in order to speak to 950 | your DB through GraphQL, needs two important pieces of information: 951 | the API endpoint and the token. You will now create a `.env` file which 952 | defines them as environment variables. 953 | 954 | The quickest way is to have `astra-cli` generate one for you: 955 | 956 | ``` 957 | astra db create-dotenv -k netflix workshops 958 | ``` 959 | 960 |
I want to do it manually 961 | 962 | If for some reason you don't use `astra-cli`, follow these steps: 963 | 964 | - copy `cp .env.sample .env` and open it: `gp open .env`; 965 | - `.env` is now open in the IDE editor and has two placeholders to replace: 966 | - insert the `AstraCS:...` database token (keep the quotes); 967 | - insert the GraphQL API address (it will look something like `https://b2f[...]/graphql/netflix`). 968 | 969 | You can generate a new database token if you want. The GraphQL address 970 | can be found in the playground: it is the URL you have edited to end in `netflix` 971 | in the second playground tab ([Part 1, step 4a](#4-insert-genre-data-with-graphql)). 972 | 973 |
974 | 975 | ## 8. Run the app in dev mode 976 | 977 | ✅ **Step 8a: Install dependencies:** 978 | 979 | ```bash 980 | npm install 981 | ``` 982 | 983 | ✅ **Step 8b: Start the app:** With the command 984 | 985 | ``` 986 | netlify dev 987 | ``` 988 | 989 | the application should automatically be displayed in GitPod's "simple browser". 990 | Note that in this **dev-mode run** everything is local to your Gitpod instance: 991 | _the "serverless functions", in particular, are actually running there, 992 | alongside the rest of the application!_ 993 | 994 |
Show me! 995 | 996 | ![run-in-preview-pane](images/preview.png) 997 | 998 |
999 | 1000 | You can copy the URL found in Gitpod's simple browser and open in a new tab 1001 | (of your real browser, that is) for a 1002 | better experience. But now it's time to move to the actual deploy phase. 1003 | 1004 | ## 9. Connect to your Netlify site 1005 | 1006 | ✅ **Step 9a:** Stop the dev run with `Ctrl-C`. 1007 | 1008 | ✅ **Step 9b:** Authenticate with Netlify: run 1009 | 1010 | ``` 1011 | netlify login 1012 | ``` 1013 | 1014 | then grab the URL printed on the console 1015 | (something like `https://app.netlify.com/authorize?response[...]`) 1016 | and manually **open it in a new tab** (Gitpod blocks it for security). 1017 | You will be asked to authorize "netlify-cli" to access your Netlify account 1018 | in the process. 1019 | 1020 |
Show me! 1021 | 1022 | ![Netlify login](images/waiting_for_authorization-2.png) 1023 | 1024 |
1025 | 1026 | Once you complete the login, you will see a console output like this: 1027 | 1028 | ![Netlify login](images/netlify-login-2.png) 1029 | 1030 | ✅ **Step 9c:** Associate to your Netlify site: run 1031 | 1032 | ``` 1033 | netlify link 1034 | ``` 1035 | 1036 | and make sure you confirm the choice of associating to 1037 | "current git remote origin". 1038 | 1039 |
Show me! 1040 | 1041 | ![Netlify link](images/netlify-link-2.png) 1042 | 1043 |
1044 | 1045 | ## 10. Deploy in production! 1046 | 1047 | ✅ **Step 10a:** Inject secrets to the Netlify site 1048 | 1049 | ``` 1050 | netlify env:import .env 1051 | ``` 1052 | 1053 | Now the (actually) serverless functions in Netlify have the connection 1054 | parameters they need. 1055 | 1056 |
Show me! 1057 | 1058 | _Note: If you generated the `.env` with 1059 | `astra-cli`, the actual output is much more verbose._ 1060 | 1061 | ![image](images/netlify_env_import.png) 1062 | 1063 |
1064 | 1065 | ✅ **Step 10b:** Build the app 1066 | 1067 | Run 1068 | 1069 | ``` 1070 | netlify build 1071 | ``` 1072 | 1073 |
Show me! 1074 | 1075 | ![Netlify build](images/netlify-build.png) 1076 | 1077 |
1078 | 1079 | ✅ **Step 10c:** Deploy! 1080 | 1081 | ``` 1082 | netlify deploy --prod 1083 | ``` 1084 | 1085 |
Show me! 1086 | 1087 | ![Netlify deploy in prod](images/netlify-deploy-prod-2.png) 1088 | 1089 |
1090 | 1091 | ✅ **Step 10d:** Visit your site. 1092 | 1093 | ``` 1094 | netlify open:site 1095 | ``` 1096 | 1097 |
Show me! 1098 | 1099 | ![Netlify Open site](images/netlify-open-site-2.png) 1100 | 1101 |
1102 | 1103 | If needed, manually copy-paste your site URL in a new browser tab... and enjoy 1104 | your work! 1105 | 1106 | ![Netlify Setup Example](images/deployed_netflix_clone.png) 1107 | 1108 | ## The END 1109 | 1110 | Congratulations, you made it! 1111 | 1112 | Now don't forget to complete your assignment and [submit it](#homework) 1113 | to get your badge of completion! 1114 | 1115 | ``` 1116 | ██╗ ██╗███████╗██╗ ██╗ 1117 | ██║ ██║██╔════╝██║ ██║ 1118 | ██║ █╗ ██║█████╗ ██║ ██║ 1119 | ██║███╗██║██╔══╝ ██║ ██║ 1120 | ╚███╔███╔╝███████╗███████╗███████╗ 1121 | ╚══╝╚══╝ ╚══════╝╚══════╝╚══════╝ 1122 | 1123 | ██████╗ ██████╗ ███╗ ██╗███████╗██╗ 1124 | ██╔══██╗██╔═══██╗████╗ ██║██╔════╝██║ 1125 | ██║ ██║██║ ██║██╔██╗ ██║█████╗ ██║ 1126 | ██║ ██║██║ ██║██║╚██╗██║██╔══╝ ╚═╝ 1127 | ██████╔╝╚██████╔╝██║ ╚████║███████╗██╗ 1128 | ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚═╝ 1129 | ``` 1130 | 1131 | ## Homework 1132 | 1133 | 1134 | 1135 | 🎓 Complete your upgrade and get your verified skill badge! Do the assignment and submit your homework! 1136 | 1137 | 1. Complete the practice steps from this repository as described below. 1138 | 2. Insert a movie OR genre of your choice in the database (It's OK to re-use the trailer file URL from another movie! Just make the title recognizable as yours). 1139 | 3. Take a screenshot of your Netflix clone running either from your Gitpod or (better) deployed to production in Netlify (in this case, you could also give us the Netlify URL). 1140 | 4. The screenshot should clearly show the movie/genre you added (make sure you tell us its name when submitting). 1141 | 5. (Optional for extra wisdom) Watch the 2-hour video by Ania [HERE](#video-tutorial-with-ania-kubow), build the app yourself, and show us the running final result. 1142 | 6. Submit your homework [here](https://dtsx.io/homework-graphql-netflix). 1143 | 1144 | That's it, you are done: expect an email in the next days! 1145 | 1146 | # Extra resources 1147 | 1148 | ## Video tutorial with Ania Kubow 1149 | Thank you to our wonderful friend Ania Kubow for producing the Netflix clone. If you are not aware of Ania and love learning about coding you should absolutely check out her YouTube channel listed below. 1150 | 1151 | While we focused on getting you up and running to production with Astra DB and Netlify, Ania's video will dig into more details on the app itself. Check it out to dig in more. 1152 | 1153 | [Ania's Netflix Video](https://www.youtube.com/watch?v=g8COh40v2jU) 1154 | -------------------------------------------------------------------------------- /astra.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GraphQL Netflix Workshop", 3 | "description": "A simple ReactJS Netflix homepage clone running on Astra DB that leverages the GraphQL API with paging and infinite scrolling. This application is the result of the collaboration between Ania Kubow and the Datastax Developer Advocate team.", "duration": "50 minutes", 4 | "skillLevel": "Intermediate", 5 | "language":["javascript"], 6 | "stack":["react"], 7 | "heroImage": "https://github.com/datastaxdevs/workshop-graphql-netflix/raw/master/images/ui.png", 8 | "githubUrl": "https://github.com/datastaxdevs/workshop-graphql-netflix", 9 | "youTubeUrl": [ "https://www.youtube.com/watch?v=g8COh40v2jU"], 10 | "tags": [ 11 | { "name": "react" }, 12 | { "name": "javascript" } 13 | ], 14 | "category": "workshop", 15 | "usecases": [] 16 | } 17 | -------------------------------------------------------------------------------- /data/bonus/dataset_action.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_actions { 3 | 4 | creed_1: insertmovies_by_genre( 5 | value: { 6 | genre:"Action", 7 | year:2015, 8 | title:"Creed", 9 | synopsis:"The former World Heavyweight Champion Rocky Balboa serves as a trainer and mentor to Adonis Johnson, the son of his late friend and former rival Apollo Creed.", 10 | duration:133, 11 | thumbnail:"https://i.imgur.com/NQTuLtb.mp4"}) { 12 | value{title} 13 | } 14 | 15 | creed_2: insertmovies_by_genre( 16 | value: { 17 | genre:"Action", 18 | year:2005, 19 | title:"Creed", 20 | synopsis:"The former World Heavyweight Champion Rocky Balboa serves as a trainer and mentor to Adonis Johnson, the son of his late friend and former rival Apollo Creed.", 21 | duration:133, 22 | thumbnail:"https://i.imgur.com/NQTuLtb.mp4"}) { 23 | value{title} 24 | } 25 | 26 | creed_3: insertmovies_by_genre( 27 | value: { 28 | genre:"Action", 29 | year:1995, 30 | title:"Creed", 31 | synopsis:"The former World Heavyweight Champion Rocky Balboa serves as a trainer and mentor to Adonis Johnson, the son of his late friend and former rival Apollo Creed.", 32 | duration:133, 33 | thumbnail:"https://i.imgur.com/NQTuLtb.mp4"}) { 34 | value{title} 35 | } 36 | 37 | furious7_1: insertmovies_by_genre( 38 | value: { 39 | genre:"Action", 40 | year:2015, 41 | title:"Furious7", 42 | synopsis:"Deckard Shaw seeks revenge against Dominic Toretto and his family for his comatose brother.", 43 | duration:137, 44 | thumbnail:"https://i.imgur.com/7ax74eb.mp4"}) { 45 | value{title} 46 | } 47 | 48 | furious7_2: insertmovies_by_genre( 49 | value: { 50 | genre:"Action", 51 | year:2005, 52 | title:"Furious7", 53 | synopsis:"Deckard Shaw seeks revenge against Dominic Toretto and his family for his comatose brother.", 54 | duration:137, 55 | thumbnail:"https://i.imgur.com/7ax74eb.mp4"}) { 56 | value{title} 57 | } 58 | 59 | furious7_3: insertmovies_by_genre( 60 | value: { 61 | genre:"Action", 62 | year:1995, 63 | title:"Furious7", 64 | synopsis:"Deckard Shaw seeks revenge against Dominic Toretto and his family for his comatose brother.", 65 | duration:137, 66 | thumbnail:"https://i.imgur.com/7ax74eb.mp4"}) { 67 | value{title} 68 | } 69 | 70 | guardian_1: insertmovies_by_genre( 71 | value: { 72 | genre:"Action", 73 | year:2014, 74 | title:"Guardians of the Galaxy", 75 | synopsis:"A group of intergalactic criminals must pull together to stop a fanatical warrior with plans to purge the universe.", 76 | duration:121, 77 | thumbnail:"https://i.imgur.com/AylKL2G.mp4"}) { 78 | value{title} 79 | } 80 | 81 | guardian_2: insertmovies_by_genre( 82 | value: { 83 | genre:"Action", 84 | year:2004, 85 | title:"Guardians of the Galaxy", 86 | synopsis:"A group of intergalactic criminals must pull together to stop a fanatical warrior with plans to purge the universe.", 87 | duration:121, 88 | thumbnail:"https://i.imgur.com/AylKL2G.mp4"}) { 89 | value{title} 90 | } 91 | 92 | guardian_3: insertmovies_by_genre( 93 | value: { 94 | genre:"Action", 95 | year:1994, 96 | title:"Guardians of the Galaxy", 97 | synopsis:"A group of intergalactic criminals must pull together to stop a fanatical warrior with plans to purge the universe.", 98 | duration:121, 99 | thumbnail:"https://i.imgur.com/AylKL2G.mp4"}) { 100 | value{title} 101 | } 102 | 103 | suicide_1: insertmovies_by_genre( 104 | value: { 105 | genre:"Action", 106 | year:2016, 107 | title:"Suicide Squad", 108 | synopsis:"A secret government agency recruits some of the most dangerous incarcerated super-villains to form a defensive task force. Their first mission: save the world from the apocalypse.", 109 | duration:123, 110 | thumbnail:"https://i.imgur.com/hwUzoyu.mp4"}) { 111 | value{title} 112 | } 113 | 114 | suicide_2: insertmovies_by_genre( 115 | value: { 116 | genre:"Action", 117 | year:2006, 118 | title:"Suicide Squad", 119 | synopsis:"A secret government agency recruits some of the most dangerous incarcerated super-villains to form a defensive task force. Their first mission: save the world from the apocalypse.", 120 | duration:123, 121 | thumbnail:"https://i.imgur.com/hwUzoyu.mp4"}) { 122 | value{title} 123 | } 124 | suicide_3: insertmovies_by_genre( 125 | value: { 126 | genre:"Action", 127 | year:1996, 128 | title:"Suicide Squad", 129 | synopsis:"A secret government agency recruits some of the most dangerous incarcerated super-villains to form a defensive task force. Their first mission: save the world from the apocalypse.", 130 | duration:123, 131 | thumbnail:"https://i.imgur.com/hwUzoyu.mp4"}) { 132 | value{title} 133 | } 134 | 135 | } 136 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_anime.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_animes { 3 | 4 | gundamn_1: insertmovies_by_genre( 5 | value: { 6 | genre:"Anime", 7 | year:2007, 8 | title:"Gundam 00", 9 | synopsis:"In the distant future, mankind has used up all of its fossil fuels, forcing them to turn to Solar Power as an alternate energy source. As a result, this causes a rift to form between richer and poorer nations, eventually leading to war. In the midst of this conflict, a mysterious military group known as 'Celestial Being' aims to use force to bring peace to the world, by using special humanoid weapons known as Gundams.", 10 | duration:100, 11 | thumbnail:"https://i.imgur.com/BR9EUGh.mp4"}) { 12 | value{title} 13 | } 14 | 15 | gundamn_2: insertmovies_by_genre( 16 | value: { 17 | genre:"Anime", 18 | year:2017, 19 | title:"Gundam 00", 20 | synopsis:"In the distant future, mankind has used up all of its fossil fuels, forcing them to turn to Solar Power as an alternate energy source. As a result, this causes a rift to form between richer and poorer nations, eventually leading to war. In the midst of this conflict, a mysterious military group known as 'Celestial Being' aims to use force to bring peace to the world, by using special humanoid weapons known as Gundams.", 21 | duration:100, 22 | thumbnail:"https://i.imgur.com/BR9EUGh.mp4"}) { 23 | value{title} 24 | } 25 | 26 | gundamn_3: insertmovies_by_genre( 27 | value: { 28 | genre:"Anime", 29 | year:1997, 30 | title:"Gundam 00", 31 | synopsis:"In the distant future, mankind has used up all of its fossil fuels, forcing them to turn to Solar Power as an alternate energy source. As a result, this causes a rift to form between richer and poorer nations, eventually leading to war. In the midst of this conflict, a mysterious military group known as 'Celestial Being' aims to use force to bring peace to the world, by using special humanoid weapons known as Gundams.", 32 | duration:100, 33 | thumbnail:"https://i.imgur.com/BR9EUGh.mp4"}) { 34 | value{title} 35 | } 36 | 37 | dbs_1: insertmovies_by_genre( 38 | value: { 39 | genre:"Anime", 40 | year:2015, 41 | title:"Dragon Ball Super", 42 | synopsis:"Six months after the defeat of Majin Buu, The mighty Saiyan Son Goku continues his quest on becoming stronger.", 43 | duration:100, 44 | thumbnail:"https://i.imgur.com/6u0PCQK.mp4"}) { 45 | value{title} 46 | } 47 | 48 | dbs_2: insertmovies_by_genre( 49 | value: { 50 | genre:"Anime", 51 | year:2005, 52 | title:"Dragon Ball Super", 53 | synopsis:"Six months after the defeat of Majin Buu, The mighty Saiyan Son Goku continues his quest on becoming stronger.", 54 | duration:100, 55 | thumbnail:"https://i.imgur.com/6u0PCQK.mp4"}) { 56 | value{title} 57 | } 58 | 59 | dbs_3: insertmovies_by_genre( 60 | value: { 61 | genre:"Anime", 62 | year:1995, 63 | title:"Dragon Ball Super", 64 | synopsis:"Six months after the defeat of Majin Buu, The mighty Saiyan Son Goku continues his quest on becoming stronger.", 65 | duration:100, 66 | thumbnail:"https://i.imgur.com/6u0PCQK.mp4"}) { 67 | value{title} 68 | } 69 | 70 | aot_1: insertmovies_by_genre( 71 | value: { 72 | genre:"Anime", 73 | year:2015, 74 | title:"Attack on Titan", 75 | synopsis:"After his hometown is destroyed and his mother is killed, young Eren Jaeger vows to cleanse the earth of the giant humanoid Titans that have brought humanity to the brink of extinction.", 76 | duration:100, 77 | thumbnail:"https://i.imgur.com/LItJ5qS.mp4"}) { 78 | value{title} 79 | } 80 | 81 | aot_2: insertmovies_by_genre( 82 | value: { 83 | genre:"Anime", 84 | year:2005, 85 | title:"Attack on Titan", 86 | synopsis:"After his hometown is destroyed and his mother is killed, young Eren Jaeger vows to cleanse the earth of the giant humanoid Titans that have brought humanity to the brink of extinction.", 87 | duration:100, 88 | thumbnail:"https://i.imgur.com/LItJ5qS.mp4"}) { 89 | value{title} 90 | } 91 | 92 | aot_3: insertmovies_by_genre( 93 | value: { 94 | genre:"Anime", 95 | year:1995, 96 | title:"Attack on Titan", 97 | synopsis:"After his hometown is destroyed and his mother is killed, young Eren Jaeger vows to cleanse the earth of the giant humanoid Titans that have brought humanity to the brink of extinction.", 98 | duration:100, 99 | thumbnail:"https://i.imgur.com/LItJ5qS.mp4"}) { 100 | value{title} 101 | } 102 | 103 | bleach_1: insertmovies_by_genre( 104 | value: { 105 | genre:"Anime", 106 | year:2004, 107 | title:"Bleach", 108 | synopsis:"High school student Ichigo Kurosaki, who has the ability to see ghosts, gains soul reaper powers from Rukia Kuchiki and sets out to save the world from 'Hollows'.", 109 | duration:100, 110 | thumbnail:"https://i.imgur.com/W3fTtFS.mp4"}) { 111 | value{title} 112 | } 113 | 114 | bleach_2: insertmovies_by_genre( 115 | value: { 116 | genre:"Anime", 117 | year:1994, 118 | title:"Bleach", 119 | synopsis:"High school student Ichigo Kurosaki, who has the ability to see ghosts, gains soul reaper powers from Rukia Kuchiki and sets out to save the world from 'Hollows'.", 120 | duration:100, 121 | thumbnail:"https://i.imgur.com/W3fTtFS.mp4"}) { 122 | value{title} 123 | } 124 | 125 | bleach_3: insertmovies_by_genre( 126 | value: { 127 | genre:"Anime", 128 | year:2014, 129 | title:"Bleach", 130 | synopsis:"High school student Ichigo Kurosaki, who has the ability to see ghosts, gains soul reaper powers from Rukia Kuchiki and sets out to save the world from 'Hollows'.", 131 | duration:100, 132 | thumbnail:"https://i.imgur.com/W3fTtFS.mp4"}) { 133 | value{title} 134 | } 135 | 136 | } 137 | 138 | ``` 139 | -------------------------------------------------------------------------------- /data/bonus/dataset_awardwinning.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_awardwinning { 3 | 4 | forest1: insertmovies_by_genre( 5 | value: { 6 | genre:"Award-Winning", 7 | year:1994, 8 | title:"Forest Gump", 9 | synopsis:"The presidencies of Kennedy and Johnson, the Vietnam War, the Watergate scandal and other historical events unfold from the perspective of an Alabama man with an IQ of 75, whose only desire is to be reunited with his childhood sweetheart.", 10 | duration:142, 11 | thumbnail:"https://i.imgur.com/V6WMXYx.mp4"}) { 12 | value{title} 13 | } 14 | 15 | forest2: insertmovies_by_genre( 16 | value: { 17 | genre:"Award-Winning", 18 | year:2004, 19 | title:"Forest Gump", 20 | synopsis:"The presidencies of Kennedy and Johnson, the Vietnam War, the Watergate scandal and other historical events unfold from the perspective of an Alabama man with an IQ of 75, whose only desire is to be reunited with his childhood sweetheart.", 21 | duration:142, 22 | thumbnail:"https://i.imgur.com/V6WMXYx.mp4"}) { 23 | value{title} 24 | } 25 | 26 | forest3: insertmovies_by_genre( 27 | value: { 28 | genre:"Award-Winning", 29 | year:2014, 30 | title:"Forest Gump", 31 | synopsis:"The presidencies of Kennedy and Johnson, the Vietnam War, the Watergate scandal and other historical events unfold from the perspective of an Alabama man with an IQ of 75, whose only desire is to be reunited with his childhood sweetheart.", 32 | duration:142, 33 | thumbnail:"https://i.imgur.com/V6WMXYx.mp4"}) { 34 | value{title} 35 | } 36 | 37 | matrix1: insertmovies_by_genre( 38 | value: { 39 | genre:"Award-Winning", 40 | year:1999, 41 | title:"The Matrix", 42 | synopsis:"When a beautiful stranger leads computer hacker Neo to a forbidding underworld, he discovers the shocking truth--the life he knows is the elaborate deception of an evil cyber-intelligence.", 43 | duration:136, 44 | thumbnail:"https://i.imgur.com/QzJe4nJ.mp4"}) { 45 | value{title} 46 | } 47 | 48 | matrix2: insertmovies_by_genre( 49 | value: { 50 | genre:"Award-Winning", 51 | year:2009, 52 | title:"The Matrix", 53 | synopsis:"When a beautiful stranger leads computer hacker Neo to a forbidding underworld, he discovers the shocking truth--the life he knows is the elaborate deception of an evil cyber-intelligence.", 54 | duration:136, 55 | thumbnail:"https://i.imgur.com/QzJe4nJ.mp4"}) { 56 | value{title} 57 | } 58 | 59 | matrix3: insertmovies_by_genre( 60 | value: { 61 | genre:"Award-Winning", 62 | year:2019, 63 | title:"The Matrix", 64 | synopsis:"When a beautiful stranger leads computer hacker Neo to a forbidding underworld, he discovers the shocking truth--the life he knows is the elaborate deception of an evil cyber-intelligence.", 65 | duration:136, 66 | thumbnail:"https://i.imgur.com/QzJe4nJ.mp4"}) { 67 | value{title} 68 | } 69 | 70 | pulpfiction1: insertmovies_by_genre( 71 | value: { 72 | genre:"Award-Winning", 73 | year:1994, 74 | title:"Pulp Fiction", 75 | synopsis:"The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption.", 76 | duration:154, 77 | thumbnail:"https://i.imgur.com/8xf630M.mp4"}) { 78 | value{title} 79 | } 80 | 81 | pulpfiction2: insertmovies_by_genre( 82 | value: { 83 | genre:"Award-Winning", 84 | year:2004, 85 | title:"Pulp Fiction", 86 | synopsis:"The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption.", 87 | duration:154, 88 | thumbnail:"https://i.imgur.com/8xf630M.mp4"}) { 89 | value{title} 90 | } 91 | 92 | pulpfiction3: insertmovies_by_genre( 93 | value: { 94 | genre:"Award-Winning", 95 | year:2014, 96 | title:"Pulp Fiction", 97 | synopsis:"The lives of two mob hitmen, a boxer, a gangster and his wife, and a pair of diner bandits intertwine in four tales of violence and redemption.", 98 | duration:154, 99 | thumbnail:"https://i.imgur.com/8xf630M.mp4"}) { 100 | value{title} 101 | } 102 | 103 | miamadre1: insertmovies_by_genre( 104 | value: { 105 | genre:"Award-Winning", 106 | year:2015, 107 | title:"Mia Madre", 108 | synopsis:"Margherita, a director in the middle of an existential crisis, has to deal with the inevitable and still unacceptable loss of her mother.", 109 | duration:106, 110 | thumbnail:"https://i.imgur.com/mRz7x3g.mp4"}) { 111 | value{title} 112 | } 113 | 114 | miamadre2: insertmovies_by_genre( 115 | value: { 116 | genre:"Award-Winning", 117 | year:2005, 118 | title:"Mia Madre", 119 | synopsis:"Margherita, a director in the middle of an existential crisis, has to deal with the inevitable and still unacceptable loss of her mother.", 120 | duration:106, 121 | thumbnail:"https://i.imgur.com/mRz7x3g.mp4"}) { 122 | value{title} 123 | } 124 | 125 | miamadre3: insertmovies_by_genre( 126 | value: { 127 | genre:"Award-Winning", 128 | year:1995, 129 | title:"Mia Madre", 130 | synopsis:"Margherita, a director in the middle of an existential crisis, has to deal with the inevitable and still unacceptable loss of her mother.", 131 | duration:106, 132 | thumbnail:"https://i.imgur.com/mRz7x3g.mp4"}) { 133 | value{title} 134 | } 135 | 136 | } 137 | 138 | ``` 139 | -------------------------------------------------------------------------------- /data/bonus/dataset_children.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_children { 3 | 4 | nemo1: insertmovies_by_genre( 5 | value: { 6 | genre:"Children & Family", 7 | year:2003, 8 | title:"Finding Nemo", 9 | synopsis:"After his son is captured in the Great Barrier Reef and taken to Sydney, a timid clownfish sets out on a journey to bring him home.", 10 | duration:100, 11 | thumbnail:"https://i.imgur.com/HtjzC5p.mp4"}) { 12 | value{title} 13 | } 14 | 15 | nemo2: insertmovies_by_genre( 16 | value: { 17 | genre:"Children & Family", 18 | year:2013, 19 | title:"Finding Nemo", 20 | synopsis:"After his son is captured in the Great Barrier Reef and taken to Sydney, a timid clownfish sets out on a journey to bring him home.", 21 | duration:100, 22 | thumbnail:"https://i.imgur.com/HtjzC5p.mp4"}) { 23 | value{title} 24 | } 25 | 26 | nemo3: insertmovies_by_genre( 27 | value: { 28 | genre:"Children & Family", 29 | year:1993, 30 | title:"Finding Nemo", 31 | synopsis:"After his son is captured in the Great Barrier Reef and taken to Sydney, a timid clownfish sets out on a journey to bring him home.", 32 | duration:100, 33 | thumbnail:"https://i.imgur.com/HtjzC5p.mp4"}) { 34 | value{title} 35 | } 36 | 37 | frog1: insertmovies_by_genre( 38 | value: { 39 | genre:"Children & Family", 40 | year:2013, 41 | title:"Frog Kingdom", 42 | synopsis:"Princess Froglegs goes undercover to compete in her father's Froglympics in order to avoid being married off to a male suitor.", 43 | duration:86, 44 | thumbnail:"https://i.imgur.com/TYDj9ud.mp4"}) { 45 | value{title} 46 | } 47 | 48 | frog2: insertmovies_by_genre( 49 | value: { 50 | genre:"Children & Family", 51 | year:2003, 52 | title:"Frog Kingdom", 53 | synopsis:"Princess Froglegs goes undercover to compete in her father's Froglympics in order to avoid being married off to a male suitor.", 54 | duration:86, 55 | thumbnail:"https://i.imgur.com/TYDj9ud.mp4"}) { 56 | value{title} 57 | } 58 | 59 | frog3: insertmovies_by_genre( 60 | value: { 61 | genre:"Children & Family", 62 | year:1993, 63 | title:"Frog Kingdom", 64 | synopsis:"Princess Froglegs goes undercover to compete in her father's Froglympics in order to avoid being married off to a male suitor.", 65 | duration:86, 66 | thumbnail:"https://i.imgur.com/TYDj9ud.mp4"}) { 67 | value{title} 68 | } 69 | 70 | turtle1: insertmovies_by_genre( 71 | value: { 72 | genre:"Children & Family", 73 | year:2016, 74 | title:"Teenage Mutant Ninja Turtles 2", 75 | synopsis:"The Turtles get into another battle with their enemy the Shredder, who has acquired new allies: the mutant thugs Bebop and Rocksteady and the alien being Krang.", 76 | duration:116, 77 | thumbnail:"https://i.imgur.com/KNgrqaP.mp4"}) { 78 | value{title} 79 | } 80 | 81 | turtle2: insertmovies_by_genre( 82 | value: { 83 | genre:"Children & Family", 84 | year:2006, 85 | title:"Teenage Mutant Ninja Turtles 2", 86 | synopsis:"The Turtles get into another battle with their enemy the Shredder, who has acquired new allies: the mutant thugs Bebop and Rocksteady and the alien being Krang.", 87 | duration:116, 88 | thumbnail:"https://i.imgur.com/KNgrqaP.mp4"}) { 89 | value{title} 90 | } 91 | 92 | turtle3: insertmovies_by_genre( 93 | value: { 94 | genre:"Children & Family", 95 | year:1996, 96 | title:"Teenage Mutant Ninja Turtles 2", 97 | synopsis:"The Turtles get into another battle with their enemy the Shredder, who has acquired new allies: the mutant thugs Bebop and Rocksteady and the alien being Krang.", 98 | duration:116, 99 | thumbnail:"https://i.imgur.com/KNgrqaP.mp4"}) { 100 | value{title} 101 | } 102 | 103 | incredible1: insertmovies_by_genre( 104 | value: { 105 | genre:"Children & Family", 106 | year:2004, 107 | title:"The incredibles", 108 | synopsis:"A family of undercover superheroes, while trying to live the quiet suburban life, are forced into action to save the world.", 109 | duration:105, 110 | thumbnail:"https://i.imgur.com/eThziEz.mp4"}) { 111 | value{title} 112 | } 113 | 114 | incredible2: insertmovies_by_genre( 115 | value: { 116 | genre:"Children & Family", 117 | year:2014, 118 | title:"The incredibles", 119 | synopsis:"A family of undercover superheroes, while trying to live the quiet suburban life, are forced into action to save the world.", 120 | duration:105, 121 | thumbnail:"https://i.imgur.com/eThziEz.mp4"}) { 122 | value{title} 123 | } 124 | 125 | incredible3: insertmovies_by_genre( 126 | value: { 127 | genre:"Children & Family", 128 | year:1994, 129 | title:"The incredibles", 130 | synopsis:"A family of undercover superheroes, while trying to live the quiet suburban life, are forced into action to save the world.", 131 | duration:105, 132 | thumbnail:"https://i.imgur.com/eThziEz.mp4"}) { 133 | value{title} 134 | } 135 | 136 | toystory1: insertmovies_by_genre( 137 | value: { 138 | genre:"Children & Family", 139 | year:1995, 140 | title:"Toy Story", 141 | synopsis:"A cowboy doll is profoundly threatened and jealous when a new spaceman figure supplants him as top toy in a boy's room.", 142 | duration:81, 143 | thumbnail:"https://i.imgur.com/8kisA8v.mp4"}) { 144 | value{title} 145 | } 146 | 147 | toystory2: insertmovies_by_genre( 148 | value: { 149 | genre:"Children & Family", 150 | year:2005, 151 | title:"Toy Story", 152 | synopsis:"A cowboy doll is profoundly threatened and jealous when a new spaceman figure supplants him as top toy in a boy's room.", 153 | duration:81, 154 | thumbnail:"https://i.imgur.com/8kisA8v.mp4"}) { 155 | value{title} 156 | } 157 | 158 | toystory3: insertmovies_by_genre( 159 | value: { 160 | genre:"Children & Family", 161 | year:2015, 162 | title:"Toy Story", 163 | synopsis:"A cowboy doll is profoundly threatened and jealous when a new spaceman figure supplants him as top toy in a boy's room.", 164 | duration:81, 165 | thumbnail:"https://i.imgur.com/8kisA8v.mp4"}) { 166 | value{title} 167 | } 168 | 169 | } 170 | ``` 171 | -------------------------------------------------------------------------------- /data/bonus/dataset_comedies.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_comedies { 3 | 4 | bridget1: insertmovies_by_genre( 5 | value: { 6 | genre:"Comedies", 7 | year:2016, 8 | title:"Bridget Jones's Baby", 9 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 10 | duration:123, 11 | thumbnail:"https://i.imgur.com/O6XpreV.mp4"}) { 12 | value{title} 13 | } 14 | 15 | bridget2: insertmovies_by_genre( 16 | value: { 17 | genre:"Comedies", 18 | year:2006, 19 | title:"Bridget Jones's Baby", 20 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 21 | duration:123, 22 | thumbnail:"https://i.imgur.com/O6XpreV.mp4"}) { 23 | value{title} 24 | } 25 | 26 | bridget3: insertmovies_by_genre( 27 | value: { 28 | genre:"Comedies", 29 | year:1996, 30 | title:"Bridget Jones's Baby", 31 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 32 | duration:123, 33 | thumbnail:"https://i.imgur.com/O6XpreV.mp4"}) { 34 | value{title} 35 | } 36 | 37 | bridget4: insertmovies_by_genre( 38 | value: { 39 | genre:"Comedies", 40 | year:1986, 41 | title:"Bridget Jones's Baby", 42 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 43 | duration:123, 44 | thumbnail:"https://i.imgur.com/O6XpreV.mp4"}) { 45 | value{title} 46 | } 47 | 48 | ninelives1: insertmovies_by_genre( 49 | value: { 50 | genre:"Comedies", 51 | year:2016, 52 | title:"Nine Lives", 53 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 54 | duration:87, 55 | thumbnail:"https://i.imgur.com/u24oIR1.mp4"}) { 56 | value{title} 57 | } 58 | 59 | ninelives2: insertmovies_by_genre( 60 | value: { 61 | genre:"Comedies", 62 | year:2006, 63 | title:"Nine Lives", 64 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 65 | duration:87, 66 | thumbnail:"https://i.imgur.com/u24oIR1.mp4"}) { 67 | value{title} 68 | } 69 | 70 | ninelives3: insertmovies_by_genre( 71 | value: { 72 | genre:"Comedies", 73 | year:1996, 74 | title:"Nine Lives", 75 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 76 | duration:87, 77 | thumbnail:"https://i.imgur.com/u24oIR1.mp4"}) { 78 | value{title} 79 | } 80 | 81 | ninelives4: insertmovies_by_genre( 82 | value: { 83 | genre:"Comedies", 84 | year:1986, 85 | title:"Nine Lives", 86 | synopsis:"Forty-something and single again, Bridget decides to focus on her job and surround herself with friends. In a twist, she finds herself pregnant, but with one hitch - she can only be fifty percent sure of the identity of her baby's father.", 87 | duration:87, 88 | thumbnail:"https://i.imgur.com/u24oIR1.mp4"}) { 89 | value{title} 90 | } 91 | 92 | mike1: insertmovies_by_genre( 93 | value: { 94 | genre:"Comedies", 95 | year:2016, 96 | title:"Mike and Dave Need Wedding Dates", 97 | synopsis:"Two hard-partying brothers place an online ad to find the perfect dates for their sister's Hawaiian wedding. Hoping for a wild getaway, the boys instead find themselves out-hustled by an uncontrollable duo.", 98 | duration:88, 99 | thumbnail:"https://i.imgur.com/4nlbiGT.mp4"}) { 100 | value{title} 101 | } 102 | 103 | mike2: insertmovies_by_genre( 104 | value: { 105 | genre:"Comedies", 106 | year:2006, 107 | title:"Mike and Dave Need Wedding Dates", 108 | synopsis:"Two hard-partying brothers place an online ad to find the perfect dates for their sister's Hawaiian wedding. Hoping for a wild getaway, the boys instead find themselves out-hustled by an uncontrollable duo.", 109 | duration:88, 110 | thumbnail:"https://i.imgur.com/4nlbiGT.mp4"}) { 111 | value{title} 112 | } 113 | 114 | mike3: insertmovies_by_genre( 115 | value: { 116 | genre:"Comedies", 117 | year:1996, 118 | title:"Mike and Dave Need Wedding Dates", 119 | synopsis:"Two hard-partying brothers place an online ad to find the perfect dates for their sister's Hawaiian wedding. Hoping for a wild getaway, the boys instead find themselves out-hustled by an uncontrollable duo.", 120 | duration:88, 121 | thumbnail:"https://i.imgur.com/4nlbiGT.mp4"}) { 122 | value{title} 123 | } 124 | 125 | mike4: insertmovies_by_genre( 126 | value: { 127 | genre:"Comedies", 128 | year:1986, 129 | title:"Mike and Dave Need Wedding Dates", 130 | synopsis:"Two hard-partying brothers place an online ad to find the perfect dates for their sister's Hawaiian wedding. Hoping for a wild getaway, the boys instead find themselves out-hustled by an uncontrollable duo.", 131 | duration:88, 132 | thumbnail:"https://i.imgur.com/4nlbiGT.mp4"}) { 133 | value{title} 134 | } 135 | 136 | } 137 | ``` 138 | -------------------------------------------------------------------------------- /data/bonus/dataset_documentaries.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_documentaries { 3 | 4 | firstp1: insertmovies_by_genre( 5 | value: { 6 | genre:"Documentaries", 7 | year:2011, 8 | title:"First Position", 9 | synopsis:"A documentary that follows six young dancers from around the world as they prepare for the Youth America Grand Prix, one of the most prestigious ballet competitions in the world.", 10 | duration:95, 11 | thumbnail:"https://i.imgur.com/Coz5yzb.mp4"}) { 12 | value{title} 13 | } 14 | 15 | firstp2: insertmovies_by_genre( 16 | value: { 17 | genre:"Documentaries", 18 | year:2001, 19 | title:"First Position", 20 | synopsis:"A documentary that follows six young dancers from around the world as they prepare for the Youth America Grand Prix, one of the most prestigious ballet competitions in the world.", 21 | duration:95, 22 | thumbnail:"https://i.imgur.com/Coz5yzb.mp4"}) { 23 | value{title} 24 | } 25 | 26 | firstp3: insertmovies_by_genre( 27 | value: { 28 | genre:"Documentaries", 29 | year:1991, 30 | title:"First Position", 31 | synopsis:"A documentary that follows six young dancers from around the world as they prepare for the Youth America Grand Prix, one of the most prestigious ballet competitions in the world.", 32 | duration:95, 33 | thumbnail:"https://i.imgur.com/Coz5yzb.mp4"}) { 34 | value{title} 35 | } 36 | 37 | firstp4: insertmovies_by_genre( 38 | value: { 39 | genre:"Documentaries", 40 | year:1981, 41 | title:"First Position", 42 | synopsis:"A documentary that follows six young dancers from around the world as they prepare for the Youth America Grand Prix, one of the most prestigious ballet competitions in the world.", 43 | duration:95, 44 | thumbnail:"https://i.imgur.com/Coz5yzb.mp4"}) { 45 | value{title} 46 | } 47 | 48 | path1: insertmovies_by_genre( 49 | value: { 50 | genre:"Documentaries", 51 | year:2007, 52 | title:"Path of glory", 53 | synopsis:"After refusing to attack an enemy position, a general accuses the soldiers of cowardice and their commanding officer must defend them.", 54 | duration:88, 55 | thumbnail:"https://i.imgur.com/xZid5oj.mp4"}) { 56 | value{title} 57 | } 58 | 59 | path2: insertmovies_by_genre( 60 | value: { 61 | genre:"Documentaries", 62 | year:1997, 63 | title:"Path of glory", 64 | synopsis:"After refusing to attack an enemy position, a general accuses the soldiers of cowardice and their commanding officer must defend them.", 65 | duration:88, 66 | thumbnail:"https://i.imgur.com/xZid5oj.mp4"}) { 67 | value{title} 68 | } 69 | 70 | path3: insertmovies_by_genre( 71 | value: { 72 | genre:"Documentaries", 73 | year:1987, 74 | title:"Path of glory", 75 | synopsis:"After refusing to attack an enemy position, a general accuses the soldiers of cowardice and their commanding officer must defend them.", 76 | duration:88, 77 | thumbnail:"https://i.imgur.com/xZid5oj.mp4"}) { 78 | value{title} 79 | } 80 | 81 | path4: insertmovies_by_genre( 82 | value: { 83 | genre:"Documentaries", 84 | year:2017, 85 | title:"Path of glory", 86 | synopsis:"After refusing to attack an enemy position, a general accuses the soldiers of cowardice and their commanding officer must defend them.", 87 | duration:88, 88 | thumbnail:"https://i.imgur.com/xZid5oj.mp4"}) { 89 | value{title} 90 | } 91 | 92 | 93 | } 94 | ``` 95 | -------------------------------------------------------------------------------- /data/bonus/dataset_dramas.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_dramas { 3 | 4 | girl1: insertmovies_by_genre( 5 | value: { 6 | genre:"Dramas", 7 | year:2016, 8 | title:"The girl on the Train", 9 | synopsis:"A divorcee becomes entangled in a missing persons investigation that promises to send shockwaves throughout her life.", 10 | duration:112, 11 | thumbnail:"https://i.imgur.com/yinQyyT.mp4"}) { 12 | value{title} 13 | } 14 | 15 | } 16 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_fantasy.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_fantasy { 3 | 4 | doctorstrange1: insertmovies_by_genre( 5 | value: { 6 | genre:"Fantasy", 7 | year:2016, 8 | title:"Doctor Strange", 9 | synopsis:"While on a journey of physical and spiritual healing, a brilliant neurosurgeon is drawn into the world of the mystic arts.", 10 | duration:115, 11 | thumbnail:"https://i.imgur.com/AARIL26.mp4"}) { 12 | value{title} 13 | } 14 | 15 | fantastic_beast1: insertmovies_by_genre( 16 | value: { 17 | genre:"Fantasy", 18 | year:2016, 19 | title:"Fantastic Beasts and Where to Find Them", 20 | synopsis:"The adventures of writer Newt Scamander in New York's secret community of witches and wizards seventy years before Harry Potter reads his book in school.", 21 | duration:132, 22 | thumbnail:"https://i.imgur.com/NhenJym.mp4"}) { 23 | value{title} 24 | } 25 | 26 | sleeping_beauty1: insertmovies_by_genre( 27 | value: { 28 | genre:"Fantasy", 29 | year:2016, 30 | title:"The Curse of Sleeping Beauty", 31 | synopsis:"Thomas unexpectedly inherits a property with a mysterious curse.", 32 | duration:132, 33 | thumbnail:"https://i.imgur.com/LcqMMwG.mp4"}) { 34 | value{title} 35 | } 36 | 37 | lotr1: insertmovies_by_genre( 38 | value: { 39 | genre:"Fantasy", 40 | year:2001, 41 | title:"The Fellowship of the Ring", 42 | synopsis:"A meek Hobbit from the Shire and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron.", 43 | duration:178, 44 | thumbnail:"https://i.imgur.com/YdhTLqF.mp4"}) { 45 | value{title} 46 | } 47 | 48 | mummy1: insertmovies_by_genre( 49 | value: { 50 | genre:"Fantasy", 51 | year:1999, 52 | title:"The Mummy", 53 | synopsis:"At an archaeological dig in the ancient city of Hamunaptra, an American serving in the French Foreign Legion accidentally awakens a mummy who begins to wreak havoc as he searches for the reincarnation of his long-lost love.", 54 | duration:124, 55 | thumbnail:"https://i.imgur.com/62tJ58E.mp4"}) { 56 | value{title} 57 | } 58 | 59 | } 60 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_french.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_french { 3 | 4 | amelie1: insertmovies_by_genre( 5 | value: { 6 | genre:"French", 7 | year:2001, 8 | title:"Amelie", 9 | synopsis:"Amélie is an innocent and naive girl in Paris with her own sense of justice. She decides to help those around her and, along the way, discovers love.", 10 | duration:122, 11 | thumbnail:"https://i.imgur.com/fan0H9k.mp4"}) { 12 | value{title} 13 | } 14 | 15 | } 16 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_horror.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_horror { 3 | 4 | ava1: insertmovies_by_genre( 5 | value: { 6 | genre:"Horror", 7 | year:2015, 8 | title:"Ava's possession.", 9 | synopsis:"A young woman recovers from a demonic possession.", 10 | duration:89, 11 | thumbnail:"https://i.imgur.com/l6krM70.mp4"}) { 12 | value{title} 13 | } 14 | 15 | rotting1: insertmovies_by_genre( 16 | value: { 17 | genre:"Horror", 18 | year:2016, 19 | title:"Little Dead Rotting Hood", 20 | synopsis:"The residents of a small town discover that something more sinister than killer wolves is lurking in the backwoods: first the wolves start turning up dead...then people.", 21 | duration:88, 22 | thumbnail:"https://i.imgur.com/C2XcrZJ.mp4"}) { 23 | value{title} 24 | } 25 | 26 | room1: insertmovies_by_genre( 27 | value: { 28 | genre:"Horror", 29 | year:2015, 30 | title:"Room", 31 | synopsis:"Held captive for 7 years in an enclosed space, a woman and her young son finally gain their freedom, allowing the boy to experience the outside world for the first time.", 32 | duration:118, 33 | thumbnail:"https://i.imgur.com/Fx5iKwZ.mp4"}) { 34 | value{title} 35 | } 36 | 37 | conjuring1: insertmovies_by_genre( 38 | value: { 39 | genre:"Horror", 40 | year:2016, 41 | title:"The Conjuring 2", 42 | synopsis:"Ed and Lorraine Warren travel to North London to help a single mother raising four children alone in a house plagued by a supernatural spirit.", 43 | duration:134, 44 | thumbnail:"https://i.imgur.com/j3qBgq8.mp4"}) { 45 | value{title} 46 | } 47 | 48 | } 49 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_independent.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_independent { 3 | 4 | enteringred1: insertmovies_by_genre( 5 | value: { 6 | genre:"Independent", 7 | year:2019, 8 | title:"Entering red", 9 | synopsis:"A woman walks into a bar and is sold the life of her dreams.", 10 | duration:12, 11 | thumbnail:"https://i.imgur.com/K7ERYIB.mp4"}) { 12 | value{title} 13 | } 14 | 15 | warroom1: insertmovies_by_genre( 16 | value: { 17 | genre:"Independent", 18 | year:2019, 19 | title:"War Room", 20 | synopsis:"A seemingly perfect family looks to fix their problems with the help of Miss Clara, an older, wiser woman.", 21 | duration:120, 22 | thumbnail:"https://i.imgur.com/ZFFosSD.mp4"}) { 23 | value{title} 24 | } 25 | 26 | } 27 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_italian.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_italian { 3 | 4 | ottoemezzo: insertmovies_by_genre( 5 | value: { 6 | genre:"Italian", 7 | year:1963, 8 | title:"8 1/2", 9 | synopsis:"A harried movie director retreats into his memories and fantasies.", 10 | duration:138, 11 | thumbnail:"https://i.imgur.com/KeF2Cr9.mp4"}) { 12 | value{title} 13 | } 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /data/bonus/dataset_music.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_music { 3 | 4 | goldenage1: insertmovies_by_genre( 5 | value: { 6 | genre:"Music & Musicals", 7 | year:2004, 8 | title:"The Golden Age", 9 | synopsis:"A seemingly perfect family looks to fix their problems with the help of Miss Clara, an older, wiser woman.", 10 | duration:114, 11 | thumbnail:"https://i.imgur.com/SQyPd7N.mp4"}) { 12 | value{title} 13 | } 14 | 15 | whiplash1: insertmovies_by_genre( 16 | value: { 17 | genre:"Music & Musicals", 18 | year:2014, 19 | title:"Whiplash", 20 | synopsis:"A promising young drummer enrolls at a cut-throat music conservatory where his dreams of greatness are mentored by an instructor who will stop at nothing to realize a student's potential.", 21 | duration:106, 22 | thumbnail:"https://i.imgur.com/ZTOIYrc.mp4"}) { 23 | value{title} 24 | } 25 | 26 | } 27 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_romance.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_romance { 3 | 4 | lovemercy1: insertmovies_by_genre( 5 | value: { 6 | genre:"Romance", 7 | year:2014, 8 | title:"Love and Mercy", 9 | synopsis:"In the 60s, Beach Boys leader Brian Wilson struggles with emerging psychosis as he attempts to craft his avant-garde pop masterpiece. In the 80s, he is a broken, confused man under the 24-hour watch of shady therapist Dr. Eugene Landy.", 10 | duration:121, 11 | thumbnail:"https://i.imgur.com/tZtTkBf.mp4"}) { 12 | value{title} 13 | } 14 | 15 | perfectmatch1: insertmovies_by_genre( 16 | value: { 17 | genre:"Romance", 18 | year:2016, 19 | title:"The perfect match", 20 | synopsis:"A playboy named Charlie, convinced that all his relationships are dead, meets the beautiful and mysterious Eva. Agreeing to a casual affair, Charlie then wants a bit more from their relationship.", 21 | duration:96, 22 | thumbnail:"https://i.imgur.com/XqSrnvi.mp4"}) { 23 | value{title} 24 | } 25 | 26 | } 27 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_scifi.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_scifi { 3 | 4 | terminator2: insertmovies_by_genre( 5 | value: { 6 | genre:"Sci-Fi", 7 | year:1991, 8 | title:"Terminator 2", 9 | synopsis:"A cyborg, identical to the one who failed to kill Sarah Connor, must now protect her ten year old son, John Connor, from a more advanced and powerful cyborg.", 10 | duration:137, 11 | thumbnail:"https://i.imgur.com/0RworbR.mp4"}) { 12 | value{title} 13 | } 14 | 15 | inception: insertmovies_by_genre( 16 | value: { 17 | genre:"Sci-Fi", 18 | year:2010, 19 | title:"Inception", 20 | synopsis:"Cobb steals information from his targets by entering their dreams.", 21 | duration:121, 22 | thumbnail:"https://i.imgur.com/RPa4UdO.mp4"}) { 23 | value{title} 24 | } 25 | 26 | prometheus: insertmovies_by_genre(value: { 27 | genre:"Sci-Fi", 28 | year:2012, 29 | title:"Prometheus", 30 | synopsis:"After a clue to mankind's origins is discovered, explorers are sent to the darkest corner of the universe.", 31 | duration:134, 32 | thumbnail:"https://i.imgur.com/L8k6Bau.mp4"}) { 33 | value{title} 34 | } 35 | 36 | aliens: insertmovies_by_genre(value: { 37 | genre:"Sci-Fi", 38 | year:1986, 39 | title:"Aliens", 40 | synopsis:"Ellen Ripley is sent back to the planet LV-426 to establish contact with a terraforming colony.", 41 | duration:134, 42 | thumbnail:"https://i.imgur.com/QvkrnyZ.mp4"}) { 43 | value{title} 44 | } 45 | 46 | bladeRunner: insertmovies_by_genre(value: { 47 | genre:"Sci-Fi", 48 | year:1982, 49 | title:"Blade Runner", 50 | synopsis:"Young Blade Runner K's discovery of a long-buried secret leads him to track down former Blade Runner Rick Deckard.", 51 | duration:145, 52 | thumbnail:"https://i.imgur.com/xhhvmj1.mp4"}) { 53 | value{title} 54 | } 55 | 56 | starTrek: insertmovies_by_genre(value: { 57 | genre:"Sci-Fi", 58 | year:1995, 59 | title:"Star Trek", 60 | synopsis:"Star trek, the next generation", 61 | duration:134, 62 | thumbnail:"https://i.imgur.com/CyBAqqD.mp4"}) { 63 | value{title} 64 | } 65 | 66 | wonderWoman: insertmovies_by_genre(value: { 67 | genre:"Sci-Fi", 68 | year:2017, 69 | title:"Wonder Woman", 70 | synopsis:"When a pilot crashes and tells of conflict in the outside world, Diana, an Amazonian warrior in training, leaves home.", 71 | duration:134, 72 | thumbnail:"https://i.imgur.com/WHf4VQf.mp4"}) { 73 | value{title} 74 | } 75 | 76 | looper: insertmovies_by_genre(value: { 77 | genre:"Sci-Fi", 78 | year:2012, 79 | title:"Looper", 80 | synopsis:"In the near future, the mob sends their victims back in time to get them executed by the loopers.", 81 | duration:156, 82 | thumbnail:"https://i.imgur.com/B1v1FRi.mp4"}) { 83 | value{title} 84 | } 85 | 86 | exMachina: insertmovies_by_genre(value: { 87 | genre:"Sci-Fi", 88 | year: 2015, 89 | title:"Ex machina", 90 | synopsis:"Caleb Smith, a young programmer, gets a chance to become a part of a strange scientific experiment.", 91 | duration:134, 92 | thumbnail:"https://i.imgur.com/CeFGCCH.mp4"}) { 93 | value{title} 94 | } 95 | 96 | doctorStrange: insertmovies_by_genre(value: { 97 | genre:"Sci-Fi", 98 | year:2016, 99 | title:"Doctor Strange", 100 | synopsis:"In an accident, Stephen Strange, a famous neurosurgeon, loses the ability to use his hands.", 101 | duration:156, 102 | thumbnail:"https://i.imgur.com/VAiM0Pr.mp4"}) { 103 | value{title} 104 | } 105 | 106 | her: insertmovies_by_genre(value: { 107 | genre:"Sci-Fi", 108 | year:2013, 109 | title:"Her", 110 | synopsis:" A sensitive and soulful man earns a living by writing personal letters for other people.", 111 | duration:134, 112 | thumbnail:"https://i.imgur.com/y3NCz30.mp4"}) { 113 | value{title} 114 | } 115 | 116 | theMartian: insertmovies_by_genre(value: { 117 | genre:"Sci-Fi", 118 | year:2015, 119 | title:"The Martian", 120 | synopsis:"During a manned mission to Mars, Astronaut Mark Watney is presumed dead after a fierce storm and left behind by his crew.", 121 | duration:134, 122 | thumbnail:"https://i.imgur.com/DffSwK0.mp4"}) { 123 | value{title} 124 | } 125 | 126 | deadpool: insertmovies_by_genre(value: { 127 | genre:"Sci-Fi", 128 | year:2016, 129 | title:"Deadpool", 130 | synopsis:"A wisecracking mercenary gets experimented on and becomes immortal but ugly, and sets out to track down the man who ruined his looks.", 131 | duration:156, 132 | thumbnail:"https://i.imgur.com/BmasM7v.mp4"}) { 133 | value{title} 134 | } 135 | 136 | upgrade: insertmovies_by_genre(value: { 137 | genre:"Sci-Fi", 138 | year: 2018, 139 | title:"Upgrade", 140 | synopsis:"Grey, a technophobe, suffers paralysis and loses his wife during an attack.", 141 | duration:123, 142 | thumbnail:"https://i.imgur.com/UgnxAc5.mp4"}) { 143 | value{title} 144 | } 145 | 146 | okra: insertmovies_by_genre(value: { 147 | genre:"Sci-Fi", 148 | year:2018, 149 | title:"Okra", 150 | synopsis:"For 10 idyllic years, young Mija has been caretaker and constant companion to Okja - a massive animal and an even bigger friend.", 151 | duration:123, 152 | thumbnail:"https://i.imgur.com/ieICjCJ.mp4"}) { 153 | value{title} 154 | } 155 | 156 | xMen: insertmovies_by_genre(value: { 157 | genre:"Sci-Fi", 158 | year:2000, 159 | title:"X-men", 160 | synopsis:"X-Men is an American superhero film based on the fictional superhero team of the same name", 161 | duration:134, 162 | thumbnail:"https://i.imgur.com/8Fj0T1U.mp4"}) { 163 | value{title} 164 | } 165 | 166 | batmanBegins: insertmovies_by_genre(value: { 167 | genre:"Sci-Fi", 168 | year:2005, 169 | title:"Batman Begins", 170 | synopsis:"After witnessing his parents' death, Bruce learns the art of fighting to confront injustice.", 171 | duration:125, 172 | thumbnail:"https://i.imgur.com/f5mRd6r.mp4"}) { 173 | value{title} 174 | } 175 | 176 | ironMan: insertmovies_by_genre(value: { 177 | genre:"Sci-Fi", 178 | year:2008, 179 | title:"Iron Man", 180 | synopsis:"After being held captive in an Afghan cave, billionaire engineer Tony Stark creates a unique weaponized suit of armor to fight evil.", 181 | duration:132, 182 | thumbnail:"https://i.imgur.com/Y9pEiJH.mp4"}) { 183 | value{title} 184 | } 185 | 186 | kong: insertmovies_by_genre(value: { 187 | genre:"Sci-Fi", 188 | year:2017, 189 | title:"Kong: Skull Island", 190 | synopsis:"A crew that reaches Skull Island to map it, is attacked by a humongous ape.", 191 | duration:145, 192 | thumbnail:"https://i.imgur.com/rXA51dG.mp4"}) { 193 | value{title} 194 | } 195 | 196 | aliens3: insertmovies_by_genre(value: { 197 | genre:"Sci-Fi", 198 | year:1992, 199 | title:"aliens 3", 200 | synopsis:"Ellen Ripley's escape pod crash-lands on Fiorina 161, a penal colony planet terrorised by an alien.", 201 | duration:145, 202 | thumbnail:"https://i.imgur.com/HrChN9I.mp4"}) { 203 | value{title} 204 | } 205 | 206 | avatar: insertmovies_by_genre(value: { 207 | genre:"Sci-Fi", 208 | year:2009, 209 | title:"Avatar", 210 | synopsis:"A paraplegic Marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world.", 211 | duration:134, 212 | thumbnail:"https://i.imgur.com/lrAI1jQ.mp4"}) { 213 | value{title} 214 | } 215 | } 216 | ``` -------------------------------------------------------------------------------- /data/bonus/dataset_thriller.md: -------------------------------------------------------------------------------- 1 | ``` 2 | mutation movies_dramas { 3 | 4 | girl1: insertmovies_by_genre( 5 | value: { 6 | genre:"Dramas", 7 | year:2016, 8 | title:"The girl on the Train", 9 | synopsis:"A divorcee becomes entangled in a missing persons investigation that promises to send shockwaves throughout her life.", 10 | duration:112, 11 | thumbnail:"https://i.imgur.com/yinQyyT.mp4"}) { 12 | value{title} 13 | } 14 | 15 | } 16 | ``` 17 | -------------------------------------------------------------------------------- /functions/getGenres.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | 3 | exports.handler = async function (event) { 4 | 5 | const body = JSON.parse(event.body) 6 | const url = process.env.ASTRA_DB_GRAPHQL_URL 7 | const query = ` 8 | query getAllGenres { 9 | reference_list ( 10 | value: { label: "genre"}, 11 | options: { 12 | pageSize: ${JSON.stringify(body.pageSize)}, 13 | pageState: ${JSON.stringify(body.pageState)} 14 | } 15 | ) { 16 | values { 17 | value 18 | } 19 | pageState 20 | } 21 | } 22 | ` 23 | 24 | const response = await fetch(url, { 25 | method: 'POST', 26 | headers: { 27 | "Content-Type": "application/json", 28 | "x-cassandra-token": process.env.ASTRA_DB_APPLICATION_TOKEN 29 | }, 30 | body: JSON.stringify({ query }) 31 | }) 32 | 33 | try { 34 | const responseBody = await response.json() 35 | return { 36 | statusCode: 200, 37 | body: JSON.stringify(responseBody) 38 | } 39 | } catch (e) { 40 | console.log(e) 41 | return { 42 | statusCode: 500, 43 | body: JSON.stringify(e) 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /functions/getMovies.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | 3 | exports.handler = async function (event) { 4 | const body = JSON.parse(event.body) 5 | const genre = body.genre 6 | const pageState = body.pageState 7 | const url = process.env.ASTRA_DB_GRAPHQL_URL 8 | const query = ` 9 | query { 10 | movies_by_genre ( 11 | value: { genre: ${JSON.stringify(genre)}}, 12 | orderBy: [year_DESC], 13 | options: { pageSize: 6, pageState: ${JSON.stringify(pageState)} } 14 | ) { 15 | values { 16 | year, 17 | title, 18 | duration, 19 | synopsis, 20 | thumbnail 21 | } 22 | pageState 23 | } 24 | } 25 | ` 26 | const response = await fetch(url, { 27 | method: 'POST', 28 | headers: { 29 | "Content-Type": "application/json", 30 | "x-cassandra-token": process.env.ASTRA_DB_APPLICATION_TOKEN 31 | }, 32 | body: JSON.stringify({ query }) 33 | }) 34 | 35 | try { 36 | const responseBody = await response.json() 37 | return { 38 | statusCode: 200, 39 | body: JSON.stringify(responseBody) 40 | } 41 | } catch (e) { 42 | console.log(e) 43 | return { 44 | statusCode: 500, 45 | body: JSON.stringify(e) 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /images/Filexplorer0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/Filexplorer0.png -------------------------------------------------------------------------------- /images/OpenPorts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/OpenPorts.png -------------------------------------------------------------------------------- /images/allow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/allow.png -------------------------------------------------------------------------------- /images/astra-cli-dsbulk-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/astra-cli-dsbulk-2.png -------------------------------------------------------------------------------- /images/astra-cli-setup-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/astra-cli-setup-2.png -------------------------------------------------------------------------------- /images/astra-create-token.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/astra-create-token.gif -------------------------------------------------------------------------------- /images/chrome-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/create_astra_db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/create_astra_db.png -------------------------------------------------------------------------------- /images/deploy-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-1.png -------------------------------------------------------------------------------- /images/deploy-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-2.png -------------------------------------------------------------------------------- /images/deploy-3b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-3b.png -------------------------------------------------------------------------------- /images/deploy-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-4.png -------------------------------------------------------------------------------- /images/deploy-4sitename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-4sitename.png -------------------------------------------------------------------------------- /images/deploy-4skeletal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-4skeletal.png -------------------------------------------------------------------------------- /images/deploy-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-5.png -------------------------------------------------------------------------------- /images/deploy-to-netlify.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deploy-to-netlify.gif -------------------------------------------------------------------------------- /images/deployed_netflix_clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/deployed_netflix_clone.png -------------------------------------------------------------------------------- /images/env_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/env_file.png -------------------------------------------------------------------------------- /images/firefox-logo.svg: -------------------------------------------------------------------------------- 1 | firefox-logo -------------------------------------------------------------------------------- /images/gitpod-01-home-annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/gitpod-01-home-annotated.png -------------------------------------------------------------------------------- /images/gitpod-02-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/gitpod-02-url.png -------------------------------------------------------------------------------- /images/gitpod_trick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/gitpod_trick.png -------------------------------------------------------------------------------- /images/graphql-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/graphql-back.png -------------------------------------------------------------------------------- /images/graphql-playground-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/graphql-playground-2.png -------------------------------------------------------------------------------- /images/graphql-playground-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/graphql-playground-3.png -------------------------------------------------------------------------------- /images/graphql-playground-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/graphql-playground-4.png -------------------------------------------------------------------------------- /images/graphql-playground-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/graphql-playground-5.png -------------------------------------------------------------------------------- /images/graphql-playground-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/graphql-playground-6.png -------------------------------------------------------------------------------- /images/graphql-playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/graphql-playground.png -------------------------------------------------------------------------------- /images/netflix-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netflix-badge.png -------------------------------------------------------------------------------- /images/netlify-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify-build.png -------------------------------------------------------------------------------- /images/netlify-connect-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify-connect-01.png -------------------------------------------------------------------------------- /images/netlify-deploy-prod-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify-deploy-prod-2.png -------------------------------------------------------------------------------- /images/netlify-install-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify-install-cli.png -------------------------------------------------------------------------------- /images/netlify-link-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify-link-2.png -------------------------------------------------------------------------------- /images/netlify-login-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify-login-2.png -------------------------------------------------------------------------------- /images/netlify-open-site-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify-open-site-2.png -------------------------------------------------------------------------------- /images/netlify_env_import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/netlify_env_import.png -------------------------------------------------------------------------------- /images/newbrowser1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/newbrowser1.png -------------------------------------------------------------------------------- /images/open-playground-2-wh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/open-playground-2-wh.png -------------------------------------------------------------------------------- /images/open-playground-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/open-playground-2.png -------------------------------------------------------------------------------- /images/playground-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/playground-1.png -------------------------------------------------------------------------------- /images/playground-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/playground-2.png -------------------------------------------------------------------------------- /images/playground-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/playground-3.png -------------------------------------------------------------------------------- /images/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/preview.png -------------------------------------------------------------------------------- /images/tabs-vs-playgroundtabs-labeled-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/tabs-vs-playgroundtabs-labeled-2.png -------------------------------------------------------------------------------- /images/ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/ui.png -------------------------------------------------------------------------------- /images/waiting_for_authorization-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/images/waiting_for_authorization-2.png -------------------------------------------------------------------------------- /know_your_gitpod.md: -------------------------------------------------------------------------------- 1 | # Know your gitpod 2 | 3 | Take a moment to read this entire section since it'll help you with the rest of the workshop as you'll be spending lot of your time in Gitpod. If you're familiar with Gitpod, you can easily skip this entire section. 4 | 5 | ### Appearance 6 | 7 | The extreme left side has the explorer view(1). The top left, middle to right is where you'll be editing files(2), etc. and the bottom left, middle to right is what we will refer to as the Gitpod terminal window(3) as shown below. 8 | 9 | ![gitpod](images/gitpod-01-home-annotated.png?raw=true) 10 | 11 | ### Get to the file explorer 12 | 13 | You can always get back to the file explorer view whenever by clicking on the hamburger menu on the top left followed by `View` and `Explorer` as shown below. 14 | 15 | ![gitpod](images/Filexplorer0.png?raw=true) 16 | 17 | ### Your public URL 18 | 19 | The workshop application has opened with an ephemeral URL. 20 | To know the URL where your application endpoint will be exposed you can run the following command in the terminal after the build has completed. 21 | **Please note this URL and open this up in a new browser window as shown below**. 22 | 23 | ```bash 24 | gp url 8888 25 | ``` 26 | 27 | ![gitpod](images/gitpod-02-url.png?raw=true) 28 | 29 | 30 | You can launch a new browser window and keep it open for the rest of the workshop, even in case the application is not running yet (in which case you can always refresh the tab later, after starting the app). 31 | 32 | ![gitpod](images/newbrowser1.png?raw=true) 33 | 34 | ### Enable clipboard usage 35 | 36 | You can allow cutting and pasting into the window by clicking on `Allow` as shown below. 37 | 38 | ![gitpod](images/allow.png?raw=true) 39 | 40 | ### Controlling routing of opened ports 41 | 42 | Or allow ports to be opened by just exiting windows that are informational messages about ports like below. 43 | 44 | ![gitpod](images/OpenPorts.png?raw=true) 45 | 46 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | functions = "functions" 4 | "publish" = "build" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netflix-datastax-clone", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.11.10", 7 | "@testing-library/react": "^11.2.6", 8 | "@testing-library/user-event": "^12.8.3", 9 | "netlify-cli": "^3.31.14", 10 | "node-fetch": "^2.6.1", 11 | "react": "^17.0.2", 12 | "react-dom": "^17.0.2", 13 | "react-router-dom": "^5.2.0", 14 | "react-scripts": "4.0.3", 15 | "web-vitals": "^1.1.1" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject", 22 | "dev": "netlify dev" 23 | }, 24 | "eslintConfig": { 25 | "extends": [ 26 | "react-app", 27 | "react-app/jest" 28 | ] 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 18 | 19 | 28 | Netflix Clone using Astra DB and GraphQL 29 | 30 | 31 | 32 |
33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /slides/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-graphql-netflix/eb087e639090e1b017889b871f2db9b6820ccb08/slides/slides.pdf -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #141414; 3 | color: #fff; 4 | font-family: "Helvetica Neue", sans-serif; 5 | } 6 | 7 | .container { 8 | margin: 0 50px; 9 | } 10 | 11 | .navbar { 12 | height: 50px; 13 | width: 100%; 14 | position: sticky; 15 | top: 0; 16 | } 17 | 18 | .hero { 19 | width: 100%; 20 | margin-top: -100px; 21 | padding: 0; 22 | } 23 | 24 | .info-section { 25 | position: absolute; 26 | margin-top: 30%; 27 | margin-left: 50px; 28 | width: 600px; 29 | } 30 | 31 | .movie-section { 32 | display: flex; 33 | } 34 | 35 | .button-section { 36 | display: flex; 37 | } 38 | 39 | .button { 40 | border-radius: 10px; 41 | background-color: #fff; 42 | color: #000; 43 | padding: 10px 20px; 44 | margin: 3px; 45 | } 46 | 47 | .more { 48 | background-color: rgba(255,255,255, 0.5); 49 | } 50 | 51 | .card { 52 | width: 230px; 53 | border-radius: 5px; 54 | margin: 2px; 55 | transition: transform 500ms; 56 | position: relative; 57 | display: block; 58 | } 59 | 60 | video { 61 | width: 100%; 62 | border-radius: 5px; 63 | } 64 | 65 | .hero-video { 66 | width: 100%; 67 | float: left; 68 | top: 0; 69 | padding: none; 70 | margin-bottom: 30px; 71 | } 72 | 73 | video::-webkit-media-controls { 74 | display: none; 75 | } 76 | 77 | .movie-section:focus-within .card, 78 | .movie-section:focus, .card { 79 | transform: translate(-25%); 80 | z-index: 1; 81 | } 82 | 83 | .card:focus ~ .card, 84 | .card:hover ~ .card { 85 | transform: translateX(25%) 86 | } 87 | 88 | .movie-section .card:focus, 89 | .movie-section .card:hover { 90 | transform: scale(1.5); 91 | z-index: 1; 92 | background-color: #212121; 93 | box-shadow: 0 2.8px 2.2px rgba(0, 0, 0, 0.034), 94 | 0 6.7px 5.3px rgba(0, 0, 0, 0.048), 0 12.5px 10px rgba(0, 0, 0, 0.5), 95 | 0 22.3px 17.9px rgba(0, 0, 0, 0.072), 0 41.8px 33.4px rgba(0, 0, 0, 0.086), 96 | 0 100px 80px rgba(0, 0, 0, 0.5); 97 | } 98 | 99 | .more-button { 100 | height: 100%; 101 | display: flex; 102 | padding: 40px 10px; 103 | border-radius: 0 10px 10px 0; 104 | } 105 | 106 | .fas { 107 | margin: 0 5px; 108 | } 109 | 110 | .logo { 111 | width: 88px; 112 | height: 22px; 113 | background-image: url('https://i.imgur.com/Y9dwM3s.png'); 114 | background-size: 88px; 115 | margin: 5px; 116 | } 117 | 118 | a { 119 | text-decoration: none; 120 | color: #fff; 121 | } 122 | 123 | .more-button:hover { 124 | background-color: rgb(255,255,255, 0.5); 125 | } 126 | 127 | .page-end { 128 | width: 100%; 129 | height: 300px; 130 | } 131 | 132 | ul { 133 | display: flex; 134 | list-style-type: none; 135 | } 136 | 137 | li { 138 | margin: 0 10px; 139 | } 140 | 141 | .info-box { 142 | width: 100%; 143 | z-index: 5; 144 | padding: 10px; 145 | } 146 | 147 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css" 2 | import { useEffect, useState } from "react" 3 | import Section from "./components/Section" 4 | import HeroSection from "./components/HeroSection" 5 | import NavBar from "./components/NavBar" 6 | 7 | const App = () => { 8 | const pageSize = 4 9 | const [requestedPage, setRequestedPage] = useState(0) 10 | const [pageState, setPageState] = useState(null) 11 | const [genres, setGenres] = useState(null) 12 | const [isFetching, setIsFetching] = useState(false) 13 | 14 | const fetchData = async () => { 15 | if (! isFetching) { 16 | setIsFetching(true) 17 | const response = await fetch("/.netlify/functions/getGenres", { 18 | method: "POST", 19 | body: JSON.stringify({pageState, pageSize}), 20 | }) 21 | const responseBody = await response.json() 22 | setPageState(responseBody.data.reference_list.pageState) 23 | setGenres(gs => (gs || []).concat(responseBody.data.reference_list.values)) 24 | setIsFetching(false) 25 | } 26 | } 27 | 28 | useEffect(() => { 29 | // we trigger the first page of genres at the beginning 30 | setRequestedPage(1) 31 | }, []) 32 | 33 | useEffect(() => { 34 | const goalItems = pageSize * requestedPage 35 | const currentItems = (genres || []).length 36 | const bottomReached = currentItems > 0 && pageState === null 37 | // we ask for more genres if we are not at bottom of infinite scroll 38 | // (and if there are less items than the nominally requested pages) 39 | if ((goalItems > currentItems) && !bottomReached){ 40 | fetchData() 41 | } 42 | // eslint-disable-next-line react-hooks/exhaustive-deps 43 | }, [requestedPage]) 44 | 45 | return ( 46 | <> 47 | 48 | 49 | {genres && ( 50 |
51 | {Object.values(genres).map((genre) => ( 52 |
53 | ))} 54 |
55 | )} 56 |
{ 59 | setRequestedPage( np => np + 1 ) 60 | }} 61 | /> 62 | 63 | ) 64 | } 65 | 66 | export default App 67 | -------------------------------------------------------------------------------- /src/components/Card.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | const Card = ({ movie }) => { 4 | const [isShown, setIsShown] = useState(false) 5 | 6 | return ( 7 |
setIsShown(true)} 10 | onMouseLeave={() => setIsShown(false)} 11 | > 12 | {!isShown && ( 13 | 16 | )} 17 | 18 | {isShown && ( 19 | <> 20 | 23 |
24 |

{movie.title}

25 |
26 | 27 | )} 28 |
29 | ) 30 | } 31 | 32 | export default Card 33 | -------------------------------------------------------------------------------- /src/components/HeroSection.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react" 2 | 3 | const HeroSection = () => { 4 | const [movie, setMovie] = useState(null) 5 | const pageState = null 6 | 7 | const fetchData = async () => { 8 | const response = await fetch("/.netlify/functions/getMovies", { 9 | method: "POST", 10 | body: JSON.stringify({ genre: "Sci-Fi", pageState: pageState }), 11 | }) 12 | const responseBody = await response.json() 13 | const movies = responseBody.data.movies_by_genre.values 14 | setMovie(movies[Math.floor(Math.random() * movies.length)]) 15 | } 16 | 17 | useEffect(() => { 18 | fetchData() 19 | }, []) 20 | 21 | return ( 22 | <> 23 | {movie && ( 24 |
25 | 28 | 29 |
30 |

{movie.synopsis}

31 |
32 |
33 | 34 | 35 | 36 | Play 37 |
38 |
39 | 40 | 41 | 42 | More info 43 |
44 |
45 |
46 |
47 | )} 48 | 49 | ) 50 | } 51 | 52 | export default HeroSection 53 | -------------------------------------------------------------------------------- /src/components/NavBar.js: -------------------------------------------------------------------------------- 1 | const NavBar = () => { 2 | return ( 3 |
4 |
    5 |
  • 6 |
    7 |
  • 8 |
  • 9 | Home 10 |
  • 11 |
12 |
13 | ) 14 | } 15 | 16 | export default NavBar 17 | -------------------------------------------------------------------------------- /src/components/Section.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | import Card from "./Card" 3 | 4 | const Section = ({ genre }) => { 5 | const [movies, setMovies] = useState(null) 6 | const [pageState, setPageState] = useState(null) 7 | 8 | const fetchData = async () => { 9 | const response = await fetch("/.netlify/functions/getMovies", { 10 | method: "POST", 11 | body: JSON.stringify({ genre: genre, pageState: pageState }), 12 | }) 13 | const responseBody = await response.json() 14 | setMovies(responseBody.data.movies_by_genre.values) 15 | setPageState(responseBody.data.movies_by_genre.pageState) 16 | } 17 | 18 | useEffect(() => { 19 | fetchData() 20 | // eslint-disable-next-line react-hooks/exhaustive-deps 21 | }, []) 22 | 23 | return ( 24 | <> 25 |

{genre}

26 | {movies && ( 27 |
28 | {movies.map((movie, index) => ( 29 | 30 | ))} 31 |
{ 34 | setPageState(pageState) 35 | fetchData() 36 | }} 37 | > 38 | 39 |
40 |
41 | )} 42 | 43 | ) 44 | } 45 | 46 | export default Section 47 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ) 12 | --------------------------------------------------------------------------------