├── .gitignore ├── Dockerfile ├── README.md ├── app-services └── production-app │ ├── auth │ ├── custom_user_data.json │ └── providers.json │ ├── data_sources │ └── mongodb-atlas │ │ ├── config.json │ │ └── northwind │ │ ├── categories │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── customers │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── employeeTerritories │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── employees │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── orders │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── products │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── region │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── shippers │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── suppliers │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ ├── territories │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ │ └── usStates │ │ ├── relationships.json │ │ ├── rules.json │ │ └── schema.json │ ├── environments │ ├── development.json │ ├── no-environment.json │ ├── production.json │ ├── qa.json │ └── testing.json │ ├── functions │ ├── config.json │ ├── funcDescribeSalesOrderViaChatGPT35Turbo.js │ ├── funcEmbedNorthwindOrders.js │ ├── funcSearchOrders.js │ ├── funcVectorSearchOrders.js │ ├── funcVectorizeStrings.js │ ├── funcVectorizeWithOpenAI.js │ └── resetFunc.js │ ├── graphql │ ├── config.json │ └── custom_resolvers │ │ ├── query_searchOrders.json │ │ └── query_vectorSearchOrders.json │ ├── hosting │ └── metadata.json │ ├── http_endpoints │ └── config.json │ ├── realm_config.json │ ├── sync │ └── config.json │ ├── triggers │ ├── trgEmbedNorthwindOrders.json │ └── trgVectorizeStrings.json │ └── values │ └── openAI_value.json ├── app-swift ├── App.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcshareddata │ │ └── xcschemes │ │ └── App.xcscheme ├── App │ ├── AppConfig.swift │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── Realm.plist │ ├── Views │ │ ├── ContentView.swift │ │ ├── CreateItemView.swift │ │ ├── ErrorView.swift │ │ ├── ItemDetail.swift │ │ ├── ItemList.swift │ │ ├── ItemRow.swift │ │ ├── ItemsView.swift │ │ ├── LoginView.swift │ │ ├── LogoutButton.swift │ │ ├── OpenRealmView.swift │ │ ├── OrderDetailsDetails.swift │ │ ├── OrderDetailsDetailsView.swift │ │ ├── OrderDetailsList.swift │ │ └── OrderDetailsRow.swift │ ├── order.swift │ ├── order_customer.swift │ ├── order_employee.swift │ ├── order_orderDetails.swift │ ├── order_orderDetails_product.swift │ └── realmApp.swift └── README.md ├── atlas ├── clean-colls.js └── search-indexes.json ├── img ├── app-svc-key.gif ├── categories-index.gif ├── create-keypair.gif ├── demo-components.jpg ├── orders-index.gif ├── orders_mappings.jpg ├── postman-variables.jpg ├── save-vars.gif └── swift-app-config.jpg ├── postgres ├── backup.sh └── northwind.sql ├── postman └── liberate-data - GraphQL.postman_collection.json └── relational-migrator └── liberate-data.relmig /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | app-swift/App.xcodeproj/project.xcworkspace/xcuserdata/mark.franklin.xcuserdatad/UserInterfaceState.xcuserstate 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:14 2 | COPY /postgres/northwind.sql /docker-entrypoint-initdb.d 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Notice: Repository Deprecation 2 | This repository is deprecated and no longer actively maintained. It contains outdated code examples or practices that do not align with current MongoDB best practices. While the repository remains accessible for reference purposes, we strongly discourage its use in production environments. 3 | Users should be aware that this repository will not receive any further updates, bug fixes, or security patches. This code may expose you to security vulnerabilities, compatibility issues with current MongoDB versions, and potential performance problems. Any implementation based on this repository is at the user's own risk. 4 | For up-to-date resources, please refer to the [MongoDB Developer Center](https://mongodb.com/developer). 5 | 6 | # Liberate your data: From RDBMS to Vector Search, GraphQL & Mobile ... in minutes! 7 | 8 | Reduce the time it takes to modernize your applications by freeing the data trapped in your relational database and migrating to the next-gen fully transactional DB of MongoDB Atlas. 9 | 10 | Power it with advanced vector and textual search, enable consumption via a fully-managed GraphQL API, and expose data to mobile and edge consumers via the Realm mobile DB and SDKs. 11 | 12 | ![Demo Architecture](./img/demo-components.jpg) 13 | 14 | Watch a walkthrough of this demo here 15 | [![walkthrough](https://img.youtube.com/vi/OZZJ5RJKtCU/default.jpg)](https://www.youtube.com/watch?v=OZZJ5RJKtCU) 16 | 17 | ## Prerequisites 18 | 19 | * A target DB environment - MongoDB Atlas Cluster 20 | - [Sign up for Atlas](https://www.mongodb.com/cloud/atlas/signup) 21 | * A source DB environment - PostGreSQL 22 | - Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) 23 | * The new MongoDB Relational Migrator - see [Info](https://www.mongodb.com/products/relational-migrator) for details. 24 | - Install a [Migrator Release](https://www.mongodb.com/products/relational-migrator) 25 | * An OpenAI Account with an API Key generated 26 | - Consult the [OpenAI API reference](https://platform.openai.com/docs/api-reference) 27 | * A tool to generate API calls - Postman 28 | - Install [Postman](https://www.postman.com/downloads/) 29 | * Upfront setup of the [Production Atlas App](./app-services/production-app/) is required as this contains triggers to automatically embed data as it is being migrated into the Atlas cluster. 30 | * A mobile application coding environment - Xcode with Swift 31 | - Install [Xcode](https://apps.apple.com/us/app/xcode/id497799835?mt=12#:~:text=View%20in-,Mac,-App%20Store) using App Store - see here for details on the how to download the SDK [Swift](https://developer.apple.com/swift/) 32 | * Download and install the realm-cli by running: 33 | * ```npm install -g mongodb-realm-cli``` 34 | 35 | 36 | ## Steps to Show the Migration and Mobile Deployment 37 | ### Clone the Github Repo 38 | Clone the repo and change to the Repo directory 39 | 40 | * ```git clone https://github.com/mongodb-developer/liberate-data.git && cd liberate-data``` 41 | 42 | ### Create a PostgreSQL instance in Docker 43 | * Build the image: 44 | 45 | ``` 46 | docker build -t liberate-data-postgres . 47 | ``` 48 | * Launch a docker container for the Postgres instance by: 49 | 50 | ``` 51 | docker run -d --name my-postgres -p "5432:5432" -e POSTGRES_PASSWORD=password --rm liberate-data-postgres -c wal_level=logical 52 | ``` 53 | * Validate the Northwind schema by running this command: 54 | 55 | ```shell 56 | docker exec -i my-postgres psql -U postgres < 146 | export PRIV_KEY= 147 | ``` 148 | ![Save Vars](./img/save-vars.gif) 149 | 150 | ### Setup MongoDB Atlas App Services 151 | In this section, you will deploy an Atlas Application [production-app](./app-services/) from your local machine to Atlas. [production-app](./app-services/) contains all the preconfigured Linked Data Sources, Rules, Schema, Device Sync, GraphQL, Functions and Custom Resolvers you will need to complete this demo. 152 | 153 | * In a terminal shell, authenticate to the realm-cli by running this: 154 | ``` 155 | realm-cli login --api-key $PUB_KEY --private-api-key $PRIV_KEY 156 | ``` 157 | * If prompted with `This action will terminate blah blah blah`, just proceed with `y` 158 | * When you see `Successfully logged in`, chances are you're successfully logged in. 159 | * Deploy the production-app from the root of this repo project. 160 | * NOTE: If your cluster is not named `production` this command will fail. Either create a new cluster named `production`, or update the `config.clusterName` in the [config.json](./app-services/production-app/data_sources/mongodb-atlas/config.json) 161 | 162 | * Then run this: 163 | ``` 164 | realm-cli push --local app-services/production-app 165 | ``` 166 | * Accept all the default prompts. The following message indicates success: 167 | 168 | ``` 169 | Creating draft 170 | Pushing changes 171 | Deploying draft 172 | Deployment complete 173 | Successfully pushed app up: production 174 | ``` 175 | #### Configure the App Service 176 | Now finalize the application setup by creating an application API key which will be used in the next steps. 177 | * In the browser for your MongoDB Cluster, click on the App Services Tab. 178 | * Click on the Production App item. 179 | * Grab the App Id value - should be something like: production-app-*xxxxx* 180 | * Now, go to Authentication from the left panel 181 | * Click on the `EDIT` button for the API Keys row and `Click create API Key` - capturing this value too. 182 | * Now click on GraphQL from the left panel and capture GraphQL Endpoint value. 183 | ![App services key](./img/app-svc-key.gif) 184 | * Add your OpenAI API Key in the `openAI_secret` in the `Values` section 185 | 186 | #### Validate the App Service Deployment 187 | Walk through the following steps to show that the app service is configured properly. 188 | 189 | * Linked Data Sources: Inspect that the `production` cluster is linked as the data source. 190 | * Rules: The `orders` collection should have the `readAndWriteAll` role. All other collections should have the `readAll` role. 191 | * Schema: Ensure the schema for all collections is defined. The schema for the `orders` collection should define required fields as below in addition to their bson types: 192 | ``` 193 | { 194 | "title": "order", 195 | "required": [ 196 | "_id", 197 | "customerId", 198 | "employeeId", 199 | "freight", 200 | "orderDate", 201 | "shipAddress", 202 | "shipCity", 203 | "shipCountry", 204 | "shipName", 205 | "shipPostalCode", 206 | "shipRegion", 207 | "shipVia", 208 | "shippedDate" 209 | ], 210 | ... 211 | } 212 | ``` 213 | * Authentication: Two authentication providers should be enabled: `email/password` and `API Keys`. The API key named `demo` was created by you. 214 | * Device Sync: Flexible device sync should be enabled, set to the linked atlas cluster and the northwind database. 215 | * GraphQL: All entity types should be defined along with two custom resolvers named `searchOrders` and `vectorSearchOrders` which are linked to the Atlas Functions named `funcSearchOrders` and `funcVectorSearchOrders` respectively. 216 | 217 | ### Use Postman for API testing 218 | This step will allow one to run queries via GraphQL. This will show that the API is working as expected. 219 | 220 | * Startup the **Postman** app and import the collection file: ``postman/liberate-data - GraphQL.postman_collection.json``` 221 | 222 | * In **My Workspace**, Click **Collections** in left panel. 223 | * Click on the "Liberate data!" heading and then in the middle panel, click on Variables. 224 | * Then enter the three variable `api_key`,`atlas_app_id`, and `graphql_api` - using the values previous gathered in the CURRENT VALUE column. 225 | * Note: Obtain the GraphQL API (`graphql_api`) endpoint value from the GraphQL section in Atlas App Services. 226 | * See this diagram from an example: ![Postman variable](./img/postman-variables.jpg) 227 | 228 | * Click Save 229 | * Execute the 1st POST operation `Auth: Get Bearer & Access Token` to authenticate and obtain tokens by hitting the blue Send button. 230 | * If successful, copy/save the value of the output `access_token` - without the quotes - to be used in the other queries. 231 | 232 | * Now, execute any of the other operations after inserting the `access_token` value in the **Authorization** tab. Feel free to change query values. 233 | 234 | * The `Vector Search: Semantic search on Orders` operation uses a custom resolver which in turn executes an Atlas Vector Search pipeline. This pipeline is implemented in the `funcVectorSearchOrders` function and performs a real-time embedding of the search string against OpenAI and performs a vector search. 235 | 236 | * The `Search: Orders by search string` operation uses a custom resolver which in turn executes an Atlas Search pipeline. This pipeline is implemented in the `funcSearchOrders` function and performs a fuzzy text search on the `orders` collection, plus a union (`$unionWith`) and join (`$lookup`) to the `categories` collection, thus performing a text search on orders and categories. 237 | 238 | ### Swift mobile app with Realm SDK 239 | 240 | This segment shows a mobile app built with MongoDB Realm for an Apple iPhone communicating with a MongoDB Atlas database. 241 | 242 | * Start up **Xcode** 243 | * Open the the Swift app called `App.xcodeproj` under the [app-swift](./app-swift/) folder. 244 | * In the App section, open the Realm object and replace the `appId` and `appUrl`. Compile and run. 245 | * The `appId` was captured earlier. 246 | * The `appUrl` is found on the browser by by clicking on tApp Services `production-app` and copying the URL up to the `/dashboard` ending. 247 | * ![Swift Realm config](./img/swift-app-config.jpg) 248 | * In the mobile app, register with a new user via an email and password. 249 | * Browse orders. For the purpose of this demo, all users have access to all orders. 250 | 251 | ### Atlas Device Sync 252 | 253 | In this final segment, one can show Atlas Device Sync. This shows changes in data are propagated from Mobile App to Atlas Cluster (or the reverse) **immediately**. 254 | 255 | * Modify an order using the mobile app. 256 | * Open the same Order document in Atlas or Compass and notice the changes. Now modify the same order and the changes will be reflected on the mobile app. Atlas Device Sync works. 257 | * Finally, run the `Mutation: Change a Sales Order` GraphQL operation in postman. Change the Order ID and any fields in the order body. The changes should reflect in the mobile app. 258 | -------------------------------------------------------------------------------- /app-services/production-app/auth/custom_user_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": false 3 | } 4 | -------------------------------------------------------------------------------- /app-services/production-app/auth/providers.json: -------------------------------------------------------------------------------- 1 | { 2 | "anon-user": { 3 | "name": "anon-user", 4 | "type": "anon-user", 5 | "disabled": false 6 | }, 7 | "api-key": { 8 | "name": "api-key", 9 | "type": "api-key", 10 | "disabled": false 11 | }, 12 | "local-userpass": { 13 | "name": "local-userpass", 14 | "type": "local-userpass", 15 | "config": { 16 | "autoConfirm": true, 17 | "resetFunctionName": "resetFunc", 18 | "runConfirmationFunction": false, 19 | "runResetFunction": true 20 | }, 21 | "disabled": false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-atlas", 3 | "type": "mongodb-atlas", 4 | "config": { 5 | "clusterName": "production", 6 | "readPreference": "primary", 7 | "wireProtocolEnabled": false 8 | }, 9 | "version": 1 10 | } 11 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/categories/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/categories/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "categories", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/categories/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "categoryName": { 7 | "bsonType": "string" 8 | }, 9 | "description": { 10 | "bsonType": "string" 11 | }, 12 | "picture": { 13 | "bsonType": "object", 14 | "properties": {} 15 | } 16 | }, 17 | "title": "category" 18 | } 19 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/customers/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/customers/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "customers", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/customers/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "string" 5 | }, 6 | "address": { 7 | "bsonType": "string" 8 | }, 9 | "city": { 10 | "bsonType": "string" 11 | }, 12 | "companyName": { 13 | "bsonType": "string" 14 | }, 15 | "contactName": { 16 | "bsonType": "string" 17 | }, 18 | "contactTitle": { 19 | "bsonType": "string" 20 | }, 21 | "country": { 22 | "bsonType": "string" 23 | }, 24 | "fax": { 25 | "bsonType": "string" 26 | }, 27 | "phone": { 28 | "bsonType": "string" 29 | }, 30 | "postalCode": { 31 | "bsonType": "string" 32 | }, 33 | "region": { 34 | "bsonType": "string" 35 | } 36 | }, 37 | "title": "customer" 38 | } 39 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/employeeTerritories/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/employeeTerritories/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "employeeTerritories", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/employeeTerritories/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "object", 5 | "properties": { 6 | "employeeId": { 7 | "bsonType": "int" 8 | }, 9 | "territoryId": { 10 | "bsonType": "string" 11 | } 12 | } 13 | } 14 | }, 15 | "title": "employeeTerritory" 16 | } 17 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/employees/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/employees/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "employees", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/employees/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "address": { 7 | "bsonType": "string" 8 | }, 9 | "birthDate": { 10 | "bsonType": "date" 11 | }, 12 | "city": { 13 | "bsonType": "string" 14 | }, 15 | "country": { 16 | "bsonType": "string" 17 | }, 18 | "extension": { 19 | "bsonType": "string" 20 | }, 21 | "firstName": { 22 | "bsonType": "string" 23 | }, 24 | "hireDate": { 25 | "bsonType": "date" 26 | }, 27 | "homePhone": { 28 | "bsonType": "string" 29 | }, 30 | "lastName": { 31 | "bsonType": "string" 32 | }, 33 | "notes": { 34 | "bsonType": "string" 35 | }, 36 | "photo": { 37 | "bsonType": "object", 38 | "properties": {} 39 | }, 40 | "photoPath": { 41 | "bsonType": "string" 42 | }, 43 | "postalCode": { 44 | "bsonType": "string" 45 | }, 46 | "region": { 47 | "bsonType": "string" 48 | }, 49 | "reportsTo": { 50 | "bsonType": "int" 51 | }, 52 | "title": { 53 | "bsonType": "string" 54 | }, 55 | "titleOfCourtesy": { 56 | "bsonType": "string" 57 | } 58 | }, 59 | "title": "employee" 60 | } 61 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/orders/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/orders/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "orders", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAndWriteAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": true, 10 | "insert": true, 11 | "delete": true, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/orders/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "customer": { 7 | "bsonType": "object", 8 | "properties": { 9 | "companyName": { 10 | "bsonType": "string" 11 | }, 12 | "contactName": { 13 | "bsonType": "string" 14 | }, 15 | "contactTitle": { 16 | "bsonType": "string" 17 | }, 18 | "customerId": { 19 | "bsonType": "string" 20 | }, 21 | "phone": { 22 | "bsonType": "string" 23 | } 24 | } 25 | }, 26 | "customerId": { 27 | "bsonType": "string" 28 | }, 29 | "employee": { 30 | "bsonType": "object", 31 | "properties": { 32 | "employeeId": { 33 | "bsonType": "int" 34 | }, 35 | "firstName": { 36 | "bsonType": "string" 37 | }, 38 | "lastName": { 39 | "bsonType": "string" 40 | }, 41 | "notes": { 42 | "bsonType": "string" 43 | }, 44 | "title": { 45 | "bsonType": "string" 46 | } 47 | } 48 | }, 49 | "employeeId": { 50 | "bsonType": "int" 51 | }, 52 | "freight": { 53 | "bsonType": "double" 54 | }, 55 | "orderDate": { 56 | "bsonType": "date" 57 | }, 58 | "orderDetails": { 59 | "bsonType": "array", 60 | "items": { 61 | "bsonType": "object", 62 | "properties": { 63 | "discount": { 64 | "bsonType": "double" 65 | }, 66 | "product": { 67 | "bsonType": "object", 68 | "properties": { 69 | "categoryId": { 70 | "bsonType": "int" 71 | }, 72 | "productId": { 73 | "bsonType": "int" 74 | }, 75 | "productName": { 76 | "bsonType": "string" 77 | }, 78 | "quantityPerUnit": { 79 | "bsonType": "string" 80 | } 81 | } 82 | }, 83 | "productId": { 84 | "bsonType": "int" 85 | }, 86 | "quantity": { 87 | "bsonType": "int" 88 | }, 89 | "unitPrice": { 90 | "bsonType": "double" 91 | } 92 | } 93 | } 94 | }, 95 | "requiredDate": { 96 | "bsonType": "date" 97 | }, 98 | "shipAddress": { 99 | "bsonType": "string" 100 | }, 101 | "shipCity": { 102 | "bsonType": "string" 103 | }, 104 | "shipCountry": { 105 | "bsonType": "string" 106 | }, 107 | "shipName": { 108 | "bsonType": "string" 109 | }, 110 | "shipPostalCode": { 111 | "bsonType": "string" 112 | }, 113 | "shipRegion": { 114 | "bsonType": "string" 115 | }, 116 | "shipVia": { 117 | "bsonType": "int" 118 | }, 119 | "shippedDate": { 120 | "bsonType": "date" 121 | } 122 | }, 123 | "required": [ 124 | "_id", 125 | "customerId", 126 | "employeeId", 127 | "freight", 128 | "orderDate", 129 | "shipAddress", 130 | "shipCity", 131 | "shipCountry", 132 | "shipName", 133 | "shipPostalCode", 134 | "shipRegion", 135 | "shipVia", 136 | "shippedDate" 137 | ], 138 | "title": "order" 139 | } 140 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/products/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/products/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "products", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/products/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "categoryId": { 7 | "bsonType": "int" 8 | }, 9 | "discontinued": { 10 | "bsonType": "int" 11 | }, 12 | "productName": { 13 | "bsonType": "string" 14 | }, 15 | "quantityPerUnit": { 16 | "bsonType": "string" 17 | }, 18 | "reorderLevel": { 19 | "bsonType": "int" 20 | }, 21 | "supplierId": { 22 | "bsonType": "int" 23 | }, 24 | "unitPrice": { 25 | "bsonType": "double" 26 | }, 27 | "unitsInStock": { 28 | "bsonType": "int" 29 | }, 30 | "unitsOnOrder": { 31 | "bsonType": "int" 32 | } 33 | }, 34 | "title": "product" 35 | } 36 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/region/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/region/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "region", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/region/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "regionDescription": { 7 | "bsonType": "string" 8 | } 9 | }, 10 | "title": "region" 11 | } 12 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/shippers/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/shippers/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "shippers", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/shippers/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "companyName": { 7 | "bsonType": "string" 8 | }, 9 | "phone": { 10 | "bsonType": "string" 11 | } 12 | }, 13 | "title": "shipper" 14 | } 15 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/suppliers/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/suppliers/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "suppliers", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/suppliers/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "address": { 7 | "bsonType": "string" 8 | }, 9 | "city": { 10 | "bsonType": "string" 11 | }, 12 | "companyName": { 13 | "bsonType": "string" 14 | }, 15 | "contactName": { 16 | "bsonType": "string" 17 | }, 18 | "contactTitle": { 19 | "bsonType": "string" 20 | }, 21 | "country": { 22 | "bsonType": "string" 23 | }, 24 | "fax": { 25 | "bsonType": "string" 26 | }, 27 | "homepage": { 28 | "bsonType": "string" 29 | }, 30 | "phone": { 31 | "bsonType": "string" 32 | }, 33 | "postalCode": { 34 | "bsonType": "string" 35 | }, 36 | "region": { 37 | "bsonType": "string" 38 | } 39 | }, 40 | "title": "supplier" 41 | } 42 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/territories/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/territories/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "territories", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/territories/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "string" 5 | }, 6 | "regionId": { 7 | "bsonType": "int" 8 | }, 9 | "territoryDescription": { 10 | "bsonType": "string" 11 | } 12 | }, 13 | "title": "territory" 14 | } 15 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/usStates/relationships.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/usStates/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "usStates", 3 | "database": "northwind", 4 | "roles": [ 5 | { 6 | "name": "readAll", 7 | "apply_when": {}, 8 | "read": true, 9 | "write": false, 10 | "insert": false, 11 | "delete": false, 12 | "search": true 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /app-services/production-app/data_sources/mongodb-atlas/northwind/usStates/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": { 3 | "_id": { 4 | "bsonType": "int" 5 | }, 6 | "stateAbbr": { 7 | "bsonType": "string" 8 | }, 9 | "stateName": { 10 | "bsonType": "string" 11 | }, 12 | "stateRegion": { 13 | "bsonType": "string" 14 | } 15 | }, 16 | "title": "usState" 17 | } 18 | -------------------------------------------------------------------------------- /app-services/production-app/environments/development.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": {} 3 | } 4 | -------------------------------------------------------------------------------- /app-services/production-app/environments/no-environment.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": {} 3 | } 4 | -------------------------------------------------------------------------------- /app-services/production-app/environments/production.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": {} 3 | } 4 | -------------------------------------------------------------------------------- /app-services/production-app/environments/qa.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": {} 3 | } 4 | -------------------------------------------------------------------------------- /app-services/production-app/environments/testing.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": {} 3 | } 4 | -------------------------------------------------------------------------------- /app-services/production-app/functions/config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "resetFunc", 4 | "private": true 5 | }, 6 | { 7 | "name": "funcSearchOrders", 8 | "private": false 9 | }, 10 | { 11 | "name": "funcVectorizeStrings", 12 | "private": true 13 | }, 14 | { 15 | "name": "funcVectorizeWithOpenAI", 16 | "private": true 17 | }, 18 | { 19 | "name": "funcEmbedNorthwindOrders", 20 | "private": true 21 | }, 22 | { 23 | "name": "funcDescribeSalesOrderViaChatGPT35Turbo", 24 | "private": false, 25 | "disable_arg_logs": true 26 | }, 27 | { 28 | "name": "funcVectorSearchOrders", 29 | "private": false, 30 | "run_as_system": true 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /app-services/production-app/functions/funcDescribeSalesOrderViaChatGPT35Turbo.js: -------------------------------------------------------------------------------- 1 | exports = async function(salesOrder) { 2 | 3 | const openai_prompt = `From the Sales Order json object below, In 5 or more sentences, describe what the sales order is about. 4 | The description should include aspects like items in the sales order, quantity and discount: 5 | \n${JSON.stringify(salesOrder)}\n\n`; 6 | 7 | const openai_url ='https://api.openai.com/v1/chat/completions'; 8 | 9 | const openai_key = context.values.get("openAI_value"); 10 | 11 | try { 12 | console.log("Prompt: " + openai_prompt); 13 | 14 | let response = await context.http.post({ 15 | url: openai_url, 16 | headers: { 17 | 'Authorization': [`Bearer ${openai_key}`], 18 | 'Content-Type': ['application/json'] 19 | }, 20 | body: JSON.stringify({ 21 | "model": "gpt-3.5-turbo", 22 | "messages": [{"role": "user", "content": openai_prompt}], 23 | "temperature": 0.7 24 | }) 25 | }); 26 | 27 | let responseData = EJSON.parse(response.body.text()); 28 | 29 | if(response.statusCode === 200) { 30 | console.log("Successfully received description."); 31 | console.log(JSON.stringify(responseData)); 32 | 33 | const description = responseData.choices[0].message.content; 34 | console.log(description); 35 | return description; 36 | 37 | } else { 38 | console.log(`Failed to receive embedding. Status code: ${response.statusCode}`); 39 | } 40 | 41 | } catch(err) { 42 | console.error(err); 43 | } 44 | }; -------------------------------------------------------------------------------- /app-services/production-app/functions/funcEmbedNorthwindOrders.js: -------------------------------------------------------------------------------- 1 | exports = async function(changeEvent) { 2 | const doc = changeEvent.fullDocument; 3 | 4 | try { 5 | console.log(`Processing document with id: ${doc._id}`); 6 | 7 | const descriptionByLLM = await context.functions.execute("funcDescribeSalesOrderViaChatGPT35Turbo", doc); 8 | 9 | const embedding = await context.functions.execute("funcVectorizeWithOpenAI", descriptionByLLM); 10 | 11 | if (embedding.length > 0) { 12 | 13 | const mongodb = context.services.get('mongodb-atlas'); 14 | const db = mongodb.db('northwind'); 15 | const collection = db.collection('orders'); 16 | 17 | const result = await collection.updateOne( 18 | { _id: doc._id }, 19 | { $set: { 20 | "descriptionByLLM": descriptionByLLM, 21 | "embedding": embedding, 22 | }} 23 | ); 24 | 25 | if(result.modifiedCount === 1) { 26 | console.log("Successfully updated the document."); 27 | } else { 28 | console.log("Failed to update the document."); 29 | } 30 | } else { 31 | console.log(`Failed to receive embedding.`); 32 | } 33 | 34 | } catch(err) { 35 | console.error(err); 36 | } 37 | }; -------------------------------------------------------------------------------- /app-services/production-app/functions/funcSearchOrders.js: -------------------------------------------------------------------------------- 1 | exports = async function(searchString) { 2 | 3 | const orders = context.services.get('mongodb-atlas').db('northwind').collection('orders'); 4 | 5 | var pipeline = [ 6 | // orders 7 | { 8 | $search: { 9 | text: { 10 | query: searchString, 11 | path: [ 12 | 'employee.notes', 13 | 'orderDetails.product.productName', 14 | 'orderDetails.product.quantityPerUnit' 15 | ], 16 | fuzzy: { 17 | maxEdits: 1, 18 | prefixLength: 1, 19 | maxExpansions: 256 20 | } 21 | } 22 | } 23 | }, { 24 | $unionWith: { 25 | coll: 'categories', 26 | pipeline: [ 27 | { 28 | $search: { 29 | text: { 30 | query: searchString, 31 | path: [ 32 | 'categoryName', 33 | 'description' 34 | ], 35 | fuzzy: { 36 | maxEdits: 1, 37 | prefixLength: 1, 38 | maxExpansions: 256 39 | } 40 | } 41 | } 42 | }, 43 | { 44 | $lookup: { 45 | from: 'orders', 46 | localField: '_id', 47 | foreignField: 'orderDetails.product.categoryId', 48 | as: 'result' 49 | } 50 | }, 51 | { 52 | $project: { 53 | _id: 0, 54 | result: 1 55 | } 56 | }, 57 | { 58 | $unwind: '$result' 59 | } 60 | ] 61 | } 62 | } 63 | ]; 64 | 65 | 66 | return await orders.aggregate(pipeline).toArray() 67 | .then(data => { 68 | console.log(data.length); 69 | return data; 70 | }) 71 | .catch(err => { 72 | console.log(err.toString()); 73 | return err.toString(); 74 | }); 75 | }; -------------------------------------------------------------------------------- /app-services/production-app/functions/funcVectorSearchOrders.js: -------------------------------------------------------------------------------- 1 | exports = async function(searchString) { 2 | 3 | const orders = context.services.get('mongodb-atlas').db('northwind').collection('orders'); 4 | 5 | const searchVector = await context.functions.execute("funcVectorizeWithOpenAI", searchString); 6 | 7 | var pipeline = [ 8 | { $search: { 9 | index: "vector_euclidean", 10 | knnBeta: { 11 | vector: searchVector, 12 | path: "embedding", 13 | k: 3, 14 | } 15 | }} 16 | ]; 17 | 18 | return await orders.aggregate(pipeline).toArray() 19 | .then(data => { 20 | console.log(data.length); 21 | return data; 22 | }) 23 | .catch(err => { 24 | console.log(err.toString()); 25 | return err.toString(); 26 | }); 27 | }; -------------------------------------------------------------------------------- /app-services/production-app/functions/funcVectorizeStrings.js: -------------------------------------------------------------------------------- 1 | exports = async function(changeEvent) { 2 | const doc = changeEvent.fullDocument; 3 | 4 | try { 5 | console.log(`Processing document with id: ${doc._id}`); 6 | 7 | const embedding = await context.functions.execute("funcVectorizeWithOpenAI", doc.string); 8 | 9 | if (embedding.length > 0) { 10 | 11 | const mongodb = context.services.get('mongodb-atlas'); 12 | const db = mongodb.db('northwind'); 13 | const collection = db.collection('vectorizedStrings'); 14 | 15 | const result = await collection.updateOne( 16 | { _id: doc._id }, 17 | { $set: { 18 | vector: embedding, 19 | }} 20 | ); 21 | 22 | if(result.modifiedCount === 1) { 23 | console.log("Successfully updated the document."); 24 | } else { 25 | console.log("Failed to update the document."); 26 | } 27 | } else { 28 | console.log(`Failed to receive embedding. Status code: ${response.statusCode}`); 29 | } 30 | 31 | } catch(err) { 32 | console.error(err); 33 | } 34 | }; -------------------------------------------------------------------------------- /app-services/production-app/functions/funcVectorizeWithOpenAI.js: -------------------------------------------------------------------------------- 1 | exports = async function(stringToVectorize) { 2 | 3 | const openai_url = 'https://api.openai.com/v1/embeddings'; 4 | 5 | const openai_key = context.values.get("openAI_value"); 6 | 7 | try { 8 | console.log("Vectorizing: " + stringToVectorize); 9 | 10 | let response = await context.http.post({ 11 | url: openai_url, 12 | headers: { 13 | 'Authorization': [`Bearer ${openai_key}`], 14 | 'Content-Type': ['application/json'] 15 | }, 16 | body: JSON.stringify({ 17 | input: stringToVectorize, 18 | model: "text-embedding-ada-002" 19 | }) 20 | }); 21 | 22 | let responseData = EJSON.parse(response.body.text()); 23 | 24 | if(response.statusCode === 200) { 25 | console.log("Successfully received embedding."); 26 | 27 | const embedding = responseData.data[0].embedding; 28 | 29 | console.log(JSON.stringify(embedding)); 30 | 31 | return embedding; 32 | 33 | } else { 34 | console.log(`Failed to receive embedding. Status code: ${response.statusCode}`); 35 | } 36 | 37 | } catch(err) { 38 | console.error(err); 39 | } 40 | }; -------------------------------------------------------------------------------- /app-services/production-app/functions/resetFunc.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | This function will be run when the client SDK 'callResetPasswordFunction' and is called with an object parameter 4 | which contains four keys: 'token', 'tokenId', 'username', and 'password', and additional parameters 5 | for each parameter passed in as part of the argument list from the SDK. 6 | 7 | The return object must contain a 'status' key which can be empty or one of three string values: 8 | 'success', 'pending', or 'fail' 9 | 10 | 'success': the user's password is set to the passed in 'password' parameter. 11 | 12 | 'pending': the user's password is not reset and the UserPasswordAuthProviderClient 'resetPassword' function would 13 | need to be called with the token, tokenId, and new password via an SDK. (see below) 14 | 15 | const Realm = require("realm"); 16 | const appConfig = { 17 | id: "my-app-id", 18 | timeout: 1000, 19 | app: { 20 | name: "my-app-name", 21 | version: "1" 22 | } 23 | }; 24 | let app = new Realm.App(appConfig); 25 | let client = app.auth.emailPassword; 26 | await client.resetPassword(token, tokenId, newPassword); 27 | 28 | 'fail': the user's password is not reset and will not be able to log in with that password. 29 | 30 | If an error is thrown within the function the result is the same as 'fail'. 31 | 32 | Example below: 33 | 34 | exports = ({ token, tokenId, username, password }, sendEmail, securityQuestionAnswer) => { 35 | // process the reset token, tokenId, username and password 36 | if (sendEmail) { 37 | context.functions.execute('sendResetPasswordEmail', username, token, tokenId); 38 | // will wait for SDK resetPassword to be called with the token and tokenId 39 | return { status: 'pending' }; 40 | } else if (context.functions.execute('validateSecurityQuestionAnswer', username, securityQuestionAnswer)) { 41 | // will set the users password to the password parameter 42 | return { status: 'success' }; 43 | } 44 | 45 | // will not reset the password 46 | return { status: 'fail' }; 47 | }; 48 | 49 | The uncommented function below is just a placeholder and will result in failure. 50 | */ 51 | 52 | exports = ({ token, tokenId, username, password }) => { 53 | // will not reset the password 54 | return { status: 'fail' }; 55 | }; 56 | -------------------------------------------------------------------------------- /app-services/production-app/graphql/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "use_natural_pluralization": true 3 | } 4 | -------------------------------------------------------------------------------- /app-services/production-app/graphql/custom_resolvers/query_searchOrders.json: -------------------------------------------------------------------------------- 1 | { 2 | "field_name": "searchOrders", 3 | "function_name": "funcSearchOrders", 4 | "input_type": "string", 5 | "input_type_format": "scalar", 6 | "on_type": "Query", 7 | "payload_type": "Order", 8 | "payload_type_format": "generated-list" 9 | } 10 | -------------------------------------------------------------------------------- /app-services/production-app/graphql/custom_resolvers/query_vectorSearchOrders.json: -------------------------------------------------------------------------------- 1 | { 2 | "field_name": "vectorSearchOrders", 3 | "function_name": "funcVectorSearchOrders", 4 | "input_type": "string", 5 | "input_type_format": "scalar", 6 | "on_type": "Query", 7 | "payload_type": "Order", 8 | "payload_type_format": "generated-list" 9 | } 10 | -------------------------------------------------------------------------------- /app-services/production-app/hosting/metadata.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /app-services/production-app/http_endpoints/config.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /app-services/production-app/realm_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_id": "production-app-upqth", 3 | "config_version": 20210101, 4 | "name": "production-app", 5 | "location": "US-OR", 6 | "provider_region": "aws-us-west-2", 7 | "deployment_model": "LOCAL", 8 | "environment": "production" 9 | } 10 | -------------------------------------------------------------------------------- /app-services/production-app/sync/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "flexible", 3 | "state": "enabled", 4 | "development_mode_enabled": false, 5 | "service_name": "mongodb-atlas", 6 | "database_name": "northwind", 7 | "last_disabled": 1668696344, 8 | "client_max_offline_days": 30, 9 | "is_recovery_mode_disabled": false, 10 | "permissions": { 11 | "rules": {}, 12 | "defaultRoles": [ 13 | { 14 | "name": "read-write", 15 | "applyWhen": {}, 16 | "read": true, 17 | "write": true 18 | } 19 | ] 20 | }, 21 | "queryable_fields_names": [ 22 | "customerId" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /app-services/production-app/triggers/trgEmbedNorthwindOrders.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trgEmbedNorthwindOrders", 3 | "type": "DATABASE", 4 | "config": { 5 | "operation_types": [ 6 | "INSERT", 7 | "UPDATE", 8 | "REPLACE" 9 | ], 10 | "database": "northwind", 11 | "collection": "orders", 12 | "service_name": "mongodb-atlas", 13 | "match": {}, 14 | "project": {}, 15 | "full_document": true, 16 | "full_document_before_change": false, 17 | "unordered": false, 18 | "skip_catchup_events": false, 19 | "tolerate_resume_errors": false 20 | }, 21 | "disabled": false, 22 | "event_processors": { 23 | "FUNCTION": { 24 | "config": { 25 | "function_name": "funcEmbedNorthwindOrders" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app-services/production-app/triggers/trgVectorizeStrings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trgVectorizeStrings", 3 | "type": "DATABASE", 4 | "config": { 5 | "operation_types": [ 6 | "INSERT", 7 | "UPDATE" 8 | ], 9 | "database": "northwind", 10 | "collection": "vectorizedStrings", 11 | "service_name": "mongodb-atlas", 12 | "match": {}, 13 | "project": {}, 14 | "full_document": true, 15 | "full_document_before_change": false, 16 | "unordered": false, 17 | "skip_catchup_events": false, 18 | "tolerate_resume_errors": false 19 | }, 20 | "disabled": false, 21 | "event_processors": { 22 | "FUNCTION": { 23 | "config": { 24 | "function_name": "funcVectorizeStrings" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app-services/production-app/values/openAI_value.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "openAI_value", 3 | "value": "openAI_secret", 4 | "from_secret": true 5 | } 6 | -------------------------------------------------------------------------------- /app-swift/App.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 463C5364291044A9008F63E8 /* order.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463C5363291044A9008F63E8 /* order.swift */; }; 11 | 463C5366291044C9008F63E8 /* order_customer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463C5365291044C9008F63E8 /* order_customer.swift */; }; 12 | 463C5368291044F2008F63E8 /* order_employee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463C5367291044F2008F63E8 /* order_employee.swift */; }; 13 | 463C536A29104507008F63E8 /* order_orderDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463C536929104507008F63E8 /* order_orderDetails.swift */; }; 14 | 463C536C2910453B008F63E8 /* order_orderDetails_product.swift in Sources */ = {isa = PBXBuildFile; fileRef = 463C536B2910453B008F63E8 /* order_orderDetails_product.swift */; }; 15 | 466674422919D5AC00549EF5 /* OrderDetailsRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 466674412919D5AC00549EF5 /* OrderDetailsRow.swift */; }; 16 | 46667444291AB8AF00549EF5 /* OrderDetailsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46667443291AB8AF00549EF5 /* OrderDetailsList.swift */; }; 17 | 46667446291AB8CB00549EF5 /* OrderDetailsDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46667445291AB8CB00549EF5 /* OrderDetailsDetails.swift */; }; 18 | 46E7BA6529234EC9002B855A /* OrderDetailsDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46E7BA6429234EC9002B855A /* OrderDetailsDetailsView.swift */; }; 19 | 911F548827C6A2BC005D4876 /* AppConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911F548727C6A2BC005D4876 /* AppConfig.swift */; }; 20 | 912196BE27C6868100407648 /* Realm.plist in Resources */ = {isa = PBXBuildFile; fileRef = 912196BD27C6868100407648 /* Realm.plist */; }; 21 | 913D464B2770E46800ABE7D3 /* realmApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913D464A2770E46800ABE7D3 /* realmApp.swift */; }; 22 | 913D464D2770E46800ABE7D3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913D464C2770E46800ABE7D3 /* ContentView.swift */; }; 23 | 913D464F2770E46A00ABE7D3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 913D464E2770E46A00ABE7D3 /* Assets.xcassets */; }; 24 | 913D46522770E46A00ABE7D3 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 913D46512770E46A00ABE7D3 /* Preview Assets.xcassets */; }; 25 | 913D46602770E94500ABE7D3 /* CreateItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913D465F2770E94500ABE7D3 /* CreateItemView.swift */; }; 26 | 913D46622770F0C600ABE7D3 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913D46612770F0C600ABE7D3 /* LoginView.swift */; }; 27 | 915E413A284937E700D7C234 /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = 915E4139284937E700D7C234 /* Realm */; }; 28 | 915E413C284937E700D7C234 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 915E413B284937E700D7C234 /* RealmSwift */; }; 29 | 917097DC27A05EBC00F1D65B /* LogoutButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917097DB27A05EBC00F1D65B /* LogoutButton.swift */; }; 30 | 917097DE27A05F0000F1D65B /* OpenRealmView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917097DD27A05F0000F1D65B /* OpenRealmView.swift */; }; 31 | 917097E027A05F3E00F1D65B /* ItemDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917097DF27A05F3E00F1D65B /* ItemDetail.swift */; }; 32 | 917097E227A05F5A00F1D65B /* ItemRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917097E127A05F5A00F1D65B /* ItemRow.swift */; }; 33 | 917097E427A05F7E00F1D65B /* ItemsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917097E327A05F7E00F1D65B /* ItemsView.swift */; }; 34 | 917097E627A05FA000F1D65B /* ItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917097E527A05FA000F1D65B /* ItemList.swift */; }; 35 | 91DF3EEA27AAE18F0020D937 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91DF3EE927AAE18F0020D937 /* ErrorView.swift */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 463C5363291044A9008F63E8 /* order.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = order.swift; sourceTree = ""; }; 40 | 463C5365291044C9008F63E8 /* order_customer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = order_customer.swift; sourceTree = ""; }; 41 | 463C5367291044F2008F63E8 /* order_employee.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = order_employee.swift; sourceTree = ""; }; 42 | 463C536929104507008F63E8 /* order_orderDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = order_orderDetails.swift; sourceTree = ""; }; 43 | 463C536B2910453B008F63E8 /* order_orderDetails_product.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = order_orderDetails_product.swift; sourceTree = ""; }; 44 | 466674412919D5AC00549EF5 /* OrderDetailsRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsRow.swift; sourceTree = ""; }; 45 | 46667443291AB8AF00549EF5 /* OrderDetailsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsList.swift; sourceTree = ""; }; 46 | 46667445291AB8CB00549EF5 /* OrderDetailsDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsDetails.swift; sourceTree = ""; }; 47 | 46E7BA6429234EC9002B855A /* OrderDetailsDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsDetailsView.swift; sourceTree = ""; }; 48 | 911F548727C6A2BC005D4876 /* AppConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfig.swift; sourceTree = ""; }; 49 | 912196BD27C6868100407648 /* Realm.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Realm.plist; sourceTree = ""; }; 50 | 913D46472770E46800ABE7D3 /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 913D464A2770E46800ABE7D3 /* realmApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = realmApp.swift; sourceTree = ""; }; 52 | 913D464C2770E46800ABE7D3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 53 | 913D464E2770E46A00ABE7D3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 913D46512770E46A00ABE7D3 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 55 | 913D465F2770E94500ABE7D3 /* CreateItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateItemView.swift; sourceTree = ""; }; 56 | 913D46612770F0C600ABE7D3 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; 57 | 917097DB27A05EBC00F1D65B /* LogoutButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutButton.swift; sourceTree = ""; }; 58 | 917097DD27A05F0000F1D65B /* OpenRealmView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenRealmView.swift; sourceTree = ""; }; 59 | 917097DF27A05F3E00F1D65B /* ItemDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDetail.swift; sourceTree = ""; }; 60 | 917097E127A05F5A00F1D65B /* ItemRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemRow.swift; sourceTree = ""; }; 61 | 917097E327A05F7E00F1D65B /* ItemsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemsView.swift; sourceTree = ""; }; 62 | 917097E527A05FA000F1D65B /* ItemList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemList.swift; sourceTree = ""; }; 63 | 91DF3EE927AAE18F0020D937 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; 64 | /* End PBXFileReference section */ 65 | 66 | /* Begin PBXFrameworksBuildPhase section */ 67 | 913D46442770E46800ABE7D3 /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | 915E413C284937E700D7C234 /* RealmSwift in Frameworks */, 72 | 915E413A284937E700D7C234 /* Realm in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | 913D463E2770E46800ABE7D3 = { 80 | isa = PBXGroup; 81 | children = ( 82 | 913D46492770E46800ABE7D3 /* App */, 83 | 913D46482770E46800ABE7D3 /* Products */, 84 | ); 85 | sourceTree = ""; 86 | }; 87 | 913D46482770E46800ABE7D3 /* Products */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 913D46472770E46800ABE7D3 /* App.app */, 91 | ); 92 | name = Products; 93 | sourceTree = ""; 94 | }; 95 | 913D46492770E46800ABE7D3 /* App */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 911F548727C6A2BC005D4876 /* AppConfig.swift */, 99 | 913D464E2770E46A00ABE7D3 /* Assets.xcassets */, 100 | 913D46502770E46A00ABE7D3 /* Preview Content */, 101 | 912196BD27C6868100407648 /* Realm.plist */, 102 | 913D464A2770E46800ABE7D3 /* realmApp.swift */, 103 | 917097E727A0600000F1D65B /* Views */, 104 | 463C5363291044A9008F63E8 /* order.swift */, 105 | 463C5365291044C9008F63E8 /* order_customer.swift */, 106 | 463C5367291044F2008F63E8 /* order_employee.swift */, 107 | 463C536929104507008F63E8 /* order_orderDetails.swift */, 108 | 463C536B2910453B008F63E8 /* order_orderDetails_product.swift */, 109 | ); 110 | path = App; 111 | sourceTree = ""; 112 | }; 113 | 913D46502770E46A00ABE7D3 /* Preview Content */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 913D46512770E46A00ABE7D3 /* Preview Assets.xcassets */, 117 | ); 118 | path = "Preview Content"; 119 | sourceTree = ""; 120 | }; 121 | 917097E727A0600000F1D65B /* Views */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 913D464C2770E46800ABE7D3 /* ContentView.swift */, 125 | 91DF3EE927AAE18F0020D937 /* ErrorView.swift */, 126 | 913D46612770F0C600ABE7D3 /* LoginView.swift */, 127 | 917097DB27A05EBC00F1D65B /* LogoutButton.swift */, 128 | 913D465F2770E94500ABE7D3 /* CreateItemView.swift */, 129 | 917097DD27A05F0000F1D65B /* OpenRealmView.swift */, 130 | 917097DF27A05F3E00F1D65B /* ItemDetail.swift */, 131 | 917097E527A05FA000F1D65B /* ItemList.swift */, 132 | 917097E127A05F5A00F1D65B /* ItemRow.swift */, 133 | 917097E327A05F7E00F1D65B /* ItemsView.swift */, 134 | 466674412919D5AC00549EF5 /* OrderDetailsRow.swift */, 135 | 46667443291AB8AF00549EF5 /* OrderDetailsList.swift */, 136 | 46667445291AB8CB00549EF5 /* OrderDetailsDetails.swift */, 137 | 46E7BA6429234EC9002B855A /* OrderDetailsDetailsView.swift */, 138 | ); 139 | path = Views; 140 | sourceTree = ""; 141 | }; 142 | /* End PBXGroup section */ 143 | 144 | /* Begin PBXNativeTarget section */ 145 | 913D46462770E46800ABE7D3 /* App */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 913D46552770E46A00ABE7D3 /* Build configuration list for PBXNativeTarget "App" */; 148 | buildPhases = ( 149 | 913D46432770E46800ABE7D3 /* Sources */, 150 | 913D46442770E46800ABE7D3 /* Frameworks */, 151 | 913D46452770E46800ABE7D3 /* Resources */, 152 | ); 153 | buildRules = ( 154 | ); 155 | dependencies = ( 156 | ); 157 | name = App; 158 | packageProductDependencies = ( 159 | 915E4139284937E700D7C234 /* Realm */, 160 | 915E413B284937E700D7C234 /* RealmSwift */, 161 | ); 162 | productName = "realm-template-apps-swiftui"; 163 | productReference = 913D46472770E46800ABE7D3 /* App.app */; 164 | productType = "com.apple.product-type.application"; 165 | }; 166 | /* End PBXNativeTarget section */ 167 | 168 | /* Begin PBXProject section */ 169 | 913D463F2770E46800ABE7D3 /* Project object */ = { 170 | isa = PBXProject; 171 | attributes = { 172 | BuildIndependentTargetsInParallel = 1; 173 | LastSwiftUpdateCheck = 1320; 174 | LastUpgradeCheck = 1320; 175 | TargetAttributes = { 176 | 913D46462770E46800ABE7D3 = { 177 | CreatedOnToolsVersion = 13.2.1; 178 | }; 179 | }; 180 | }; 181 | buildConfigurationList = 913D46422770E46800ABE7D3 /* Build configuration list for PBXProject "App" */; 182 | compatibilityVersion = "Xcode 13.0"; 183 | developmentRegion = en; 184 | hasScannedForEncodings = 0; 185 | knownRegions = ( 186 | en, 187 | Base, 188 | ); 189 | mainGroup = 913D463E2770E46800ABE7D3; 190 | packageReferences = ( 191 | 915E4138284937E700D7C234 /* XCRemoteSwiftPackageReference "realm-swift" */, 192 | ); 193 | productRefGroup = 913D46482770E46800ABE7D3 /* Products */; 194 | projectDirPath = ""; 195 | projectRoot = ""; 196 | targets = ( 197 | 913D46462770E46800ABE7D3 /* App */, 198 | ); 199 | }; 200 | /* End PBXProject section */ 201 | 202 | /* Begin PBXResourcesBuildPhase section */ 203 | 913D46452770E46800ABE7D3 /* Resources */ = { 204 | isa = PBXResourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 913D46522770E46A00ABE7D3 /* Preview Assets.xcassets in Resources */, 208 | 913D464F2770E46A00ABE7D3 /* Assets.xcassets in Resources */, 209 | 912196BE27C6868100407648 /* Realm.plist in Resources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXResourcesBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | 913D46432770E46800ABE7D3 /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 917097E427A05F7E00F1D65B /* ItemsView.swift in Sources */, 221 | 46667444291AB8AF00549EF5 /* OrderDetailsList.swift in Sources */, 222 | 917097E627A05FA000F1D65B /* ItemList.swift in Sources */, 223 | 463C5364291044A9008F63E8 /* order.swift in Sources */, 224 | 46667446291AB8CB00549EF5 /* OrderDetailsDetails.swift in Sources */, 225 | 463C5366291044C9008F63E8 /* order_customer.swift in Sources */, 226 | 466674422919D5AC00549EF5 /* OrderDetailsRow.swift in Sources */, 227 | 917097DE27A05F0000F1D65B /* OpenRealmView.swift in Sources */, 228 | 913D46622770F0C600ABE7D3 /* LoginView.swift in Sources */, 229 | 917097E227A05F5A00F1D65B /* ItemRow.swift in Sources */, 230 | 463C536A29104507008F63E8 /* order_orderDetails.swift in Sources */, 231 | 917097DC27A05EBC00F1D65B /* LogoutButton.swift in Sources */, 232 | 913D464D2770E46800ABE7D3 /* ContentView.swift in Sources */, 233 | 91DF3EEA27AAE18F0020D937 /* ErrorView.swift in Sources */, 234 | 463C5368291044F2008F63E8 /* order_employee.swift in Sources */, 235 | 917097E027A05F3E00F1D65B /* ItemDetail.swift in Sources */, 236 | 911F548827C6A2BC005D4876 /* AppConfig.swift in Sources */, 237 | 913D464B2770E46800ABE7D3 /* realmApp.swift in Sources */, 238 | 46E7BA6529234EC9002B855A /* OrderDetailsDetailsView.swift in Sources */, 239 | 463C536C2910453B008F63E8 /* order_orderDetails_product.swift in Sources */, 240 | 913D46602770E94500ABE7D3 /* CreateItemView.swift in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXSourcesBuildPhase section */ 245 | 246 | /* Begin XCBuildConfiguration section */ 247 | 913D46532770E46A00ABE7D3 /* Debug */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | ALWAYS_SEARCH_USER_PATHS = NO; 251 | CLANG_ANALYZER_NONNULL = YES; 252 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 253 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 254 | CLANG_CXX_LIBRARY = "libc++"; 255 | CLANG_ENABLE_MODULES = YES; 256 | CLANG_ENABLE_OBJC_ARC = YES; 257 | CLANG_ENABLE_OBJC_WEAK = YES; 258 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 259 | CLANG_WARN_BOOL_CONVERSION = YES; 260 | CLANG_WARN_COMMA = YES; 261 | CLANG_WARN_CONSTANT_CONVERSION = YES; 262 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 264 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 265 | CLANG_WARN_EMPTY_BODY = YES; 266 | CLANG_WARN_ENUM_CONVERSION = YES; 267 | CLANG_WARN_INFINITE_RECURSION = YES; 268 | CLANG_WARN_INT_CONVERSION = YES; 269 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 270 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 271 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 272 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 273 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 274 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 275 | CLANG_WARN_STRICT_PROTOTYPES = YES; 276 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 277 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 278 | CLANG_WARN_UNREACHABLE_CODE = YES; 279 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 280 | COPY_PHASE_STRIP = NO; 281 | DEBUG_INFORMATION_FORMAT = dwarf; 282 | ENABLE_STRICT_OBJC_MSGSEND = YES; 283 | ENABLE_TESTABILITY = YES; 284 | GCC_C_LANGUAGE_STANDARD = gnu11; 285 | GCC_DYNAMIC_NO_PIC = NO; 286 | GCC_NO_COMMON_BLOCKS = YES; 287 | GCC_OPTIMIZATION_LEVEL = 0; 288 | GCC_PREPROCESSOR_DEFINITIONS = ( 289 | "DEBUG=1", 290 | "$(inherited)", 291 | ); 292 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 294 | GCC_WARN_UNDECLARED_SELECTOR = YES; 295 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 296 | GCC_WARN_UNUSED_FUNCTION = YES; 297 | GCC_WARN_UNUSED_VARIABLE = YES; 298 | IPHONEOS_DEPLOYMENT_TARGET = 15.2; 299 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 300 | MTL_FAST_MATH = YES; 301 | ONLY_ACTIVE_ARCH = YES; 302 | SDKROOT = iphoneos; 303 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 304 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 305 | }; 306 | name = Debug; 307 | }; 308 | 913D46542770E46A00ABE7D3 /* Release */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | CLANG_ANALYZER_NONNULL = YES; 313 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 315 | CLANG_CXX_LIBRARY = "libc++"; 316 | CLANG_ENABLE_MODULES = YES; 317 | CLANG_ENABLE_OBJC_ARC = YES; 318 | CLANG_ENABLE_OBJC_WEAK = YES; 319 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 320 | CLANG_WARN_BOOL_CONVERSION = YES; 321 | CLANG_WARN_COMMA = YES; 322 | CLANG_WARN_CONSTANT_CONVERSION = YES; 323 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 325 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 326 | CLANG_WARN_EMPTY_BODY = YES; 327 | CLANG_WARN_ENUM_CONVERSION = YES; 328 | CLANG_WARN_INFINITE_RECURSION = YES; 329 | CLANG_WARN_INT_CONVERSION = YES; 330 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 331 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 332 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 334 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 335 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 336 | CLANG_WARN_STRICT_PROTOTYPES = YES; 337 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 338 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 339 | CLANG_WARN_UNREACHABLE_CODE = YES; 340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 341 | COPY_PHASE_STRIP = NO; 342 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 343 | ENABLE_NS_ASSERTIONS = NO; 344 | ENABLE_STRICT_OBJC_MSGSEND = YES; 345 | GCC_C_LANGUAGE_STANDARD = gnu11; 346 | GCC_NO_COMMON_BLOCKS = YES; 347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 349 | GCC_WARN_UNDECLARED_SELECTOR = YES; 350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 351 | GCC_WARN_UNUSED_FUNCTION = YES; 352 | GCC_WARN_UNUSED_VARIABLE = YES; 353 | IPHONEOS_DEPLOYMENT_TARGET = 15.2; 354 | MTL_ENABLE_DEBUG_INFO = NO; 355 | MTL_FAST_MATH = YES; 356 | SDKROOT = iphoneos; 357 | SWIFT_COMPILATION_MODE = wholemodule; 358 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 359 | VALIDATE_PRODUCT = YES; 360 | }; 361 | name = Release; 362 | }; 363 | 913D46562770E46A00ABE7D3 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 368 | CODE_SIGN_STYLE = Automatic; 369 | CURRENT_PROJECT_VERSION = 1; 370 | DEVELOPMENT_ASSET_PATHS = "\"App/Preview Content\""; 371 | DEVELOPMENT_TEAM = 4K8S736645; 372 | ENABLE_PREVIEWS = YES; 373 | GENERATE_INFOPLIST_FILE = YES; 374 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 375 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 376 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 377 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 378 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 379 | LD_RUNPATH_SEARCH_PATHS = ( 380 | "$(inherited)", 381 | "@executable_path/Frameworks", 382 | ); 383 | MARKETING_VERSION = 1.0; 384 | PRODUCT_BUNDLE_IDENTIFIER = mongodb.realm.reinvent.App; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | SWIFT_EMIT_LOC_STRINGS = YES; 387 | SWIFT_VERSION = 5.0; 388 | TARGETED_DEVICE_FAMILY = "1,2"; 389 | }; 390 | name = Debug; 391 | }; 392 | 913D46572770E46A00ABE7D3 /* Release */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 396 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 397 | CODE_SIGN_STYLE = Automatic; 398 | CURRENT_PROJECT_VERSION = 1; 399 | DEVELOPMENT_ASSET_PATHS = "\"App/Preview Content\""; 400 | DEVELOPMENT_TEAM = 4K8S736645; 401 | ENABLE_PREVIEWS = YES; 402 | GENERATE_INFOPLIST_FILE = YES; 403 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 404 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 405 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 406 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 407 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 408 | LD_RUNPATH_SEARCH_PATHS = ( 409 | "$(inherited)", 410 | "@executable_path/Frameworks", 411 | ); 412 | MARKETING_VERSION = 1.0; 413 | PRODUCT_BUNDLE_IDENTIFIER = mongodb.realm.reinvent.App; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | SWIFT_EMIT_LOC_STRINGS = YES; 416 | SWIFT_VERSION = 5.0; 417 | TARGETED_DEVICE_FAMILY = "1,2"; 418 | }; 419 | name = Release; 420 | }; 421 | /* End XCBuildConfiguration section */ 422 | 423 | /* Begin XCConfigurationList section */ 424 | 913D46422770E46800ABE7D3 /* Build configuration list for PBXProject "App" */ = { 425 | isa = XCConfigurationList; 426 | buildConfigurations = ( 427 | 913D46532770E46A00ABE7D3 /* Debug */, 428 | 913D46542770E46A00ABE7D3 /* Release */, 429 | ); 430 | defaultConfigurationIsVisible = 0; 431 | defaultConfigurationName = Release; 432 | }; 433 | 913D46552770E46A00ABE7D3 /* Build configuration list for PBXNativeTarget "App" */ = { 434 | isa = XCConfigurationList; 435 | buildConfigurations = ( 436 | 913D46562770E46A00ABE7D3 /* Debug */, 437 | 913D46572770E46A00ABE7D3 /* Release */, 438 | ); 439 | defaultConfigurationIsVisible = 0; 440 | defaultConfigurationName = Release; 441 | }; 442 | /* End XCConfigurationList section */ 443 | 444 | /* Begin XCRemoteSwiftPackageReference section */ 445 | 915E4138284937E700D7C234 /* XCRemoteSwiftPackageReference "realm-swift" */ = { 446 | isa = XCRemoteSwiftPackageReference; 447 | repositoryURL = "https://github.com/realm/realm-swift.git"; 448 | requirement = { 449 | kind = upToNextMajorVersion; 450 | minimumVersion = 10.28.0; 451 | }; 452 | }; 453 | /* End XCRemoteSwiftPackageReference section */ 454 | 455 | /* Begin XCSwiftPackageProductDependency section */ 456 | 915E4139284937E700D7C234 /* Realm */ = { 457 | isa = XCSwiftPackageProductDependency; 458 | package = 915E4138284937E700D7C234 /* XCRemoteSwiftPackageReference "realm-swift" */; 459 | productName = Realm; 460 | }; 461 | 915E413B284937E700D7C234 /* RealmSwift */ = { 462 | isa = XCSwiftPackageProductDependency; 463 | package = 915E4138284937E700D7C234 /* XCRemoteSwiftPackageReference "realm-swift" */; 464 | productName = RealmSwift; 465 | }; 466 | /* End XCSwiftPackageProductDependency section */ 467 | }; 468 | rootObject = 913D463F2770E46800ABE7D3 /* Project object */; 469 | } 470 | -------------------------------------------------------------------------------- /app-swift/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app-swift/App.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app-swift/App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "realm-core", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/realm/realm-core", 7 | "state" : { 8 | "revision" : "3c4b86da569368c4ee5ccca2a112d511cc6fa936", 9 | "version" : "12.11.0" 10 | } 11 | }, 12 | { 13 | "identity" : "realm-swift", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/realm/realm-swift.git", 16 | "state" : { 17 | "revision" : "dc1672b3011eb992ce95db4feec83cd897626a16", 18 | "version" : "10.32.1" 19 | } 20 | } 21 | ], 22 | "version" : 2 23 | } 24 | -------------------------------------------------------------------------------- /app-swift/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /app-swift/App/AppConfig.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RealmSwift 3 | 4 | /// Store the Realm app details to use when instantiating the app and 5 | /// when using the `@AsyncOpen` property wrapper to open the realm. 6 | struct AppConfig { 7 | var appId: String 8 | var baseUrl: String 9 | } 10 | 11 | 12 | /// Read the Realm.plist file and store the app ID and baseUrl to use elsewhere. 13 | func loadAppConfig() -> AppConfig { 14 | guard let path = Bundle.main.path(forResource: "Realm", ofType: "plist") else { 15 | fatalError("Could not load Realm.plist file!") 16 | } 17 | // Any errors here indicate that the Realm.plist file has not been formatted properly. 18 | // Expected key/values: 19 | // "appId": "your Realm app ID" 20 | let data = NSData(contentsOfFile: path)! as Data 21 | let realmPropertyList = try! PropertyListSerialization.propertyList(from: data, format: nil) as! [String: Any] 22 | let appId = realmPropertyList["appId"]! as! String 23 | let baseUrl = realmPropertyList["baseUrl"]! as! String 24 | // Get on-disk location of the default Realm 25 | let realm = try! Realm() 26 | print("Realm is located at:", realm.configuration.fileURL!) 27 | return AppConfig(appId: appId, baseUrl: baseUrl) 28 | } 29 | -------------------------------------------------------------------------------- /app-swift/App/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app-swift/App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app-swift/App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app-swift/App/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app-swift/App/Realm.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | appId 6 | production-app-upqth 7 | appUrl 8 | https://realm.mongodb.com/groups/63583ea8f47fc018ab148263/apps/635840a4cff54ef96106cd66 9 | baseUrl 10 | https://realm.mongodb.com 11 | dataSourceName 12 | mongodb-atlas 13 | 14 | 15 | -------------------------------------------------------------------------------- /app-swift/App/Views/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | struct ContentView: View { 5 | @ObservedObject var app: RealmSwift.App 6 | 7 | 8 | var body: some View { 9 | if let user = app.currentUser { 10 | 11 | let config = user.flexibleSyncConfiguration(initialSubscriptions: { subs in 12 | if let foundSubscription = subs.first(named: "user_tasks") { 13 | // Existing subscription found - do nothing 14 | return 15 | } else { 16 | subs.append(QuerySubscription(name: "user_tasks") { 17 | $0._id != 0 18 | }) 19 | } 20 | }) 21 | OpenRealmView(user: user).environment(\.realmConfiguration, config) 22 | } else { 23 | // If there is no user logged in, show the login view. 24 | LoginView() 25 | } 26 | Text("Built with the Atlas Device Sync Template") 27 | .font(.footnote) 28 | .padding() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app-swift/App/Views/CreateItemView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// Instantiate a new Item object, let the user input a ``summary``, and then 5 | /// append it to the ``items`` collection to add it to the Item list. 6 | struct CreateItemView: View { 7 | // The ``items`` ObservedResults collection is the 8 | // entire list of Item objects in the realm. 9 | @ObservedResults( 10 | order.self, 11 | sortDescriptor: {SortDescriptor(keyPath: "_id", ascending: false)}() 12 | ) var items 13 | 14 | // Create a new Realm Item object. 15 | @State private var newItem = order() 16 | @State private var newOrderDetails = order_orderDetails() 17 | 18 | 19 | // We've passed in the ``creatingNewItem`` variable 20 | // from the ItemsView to know when the user is done 21 | // with the new Item and we should return to the ItemsView. 22 | @Binding var isInCreateItemView: Bool 23 | 24 | @State var user: User 25 | 26 | @State var customerId = "" 27 | @State var employeeId = 0 28 | @State var freight = 0.00 29 | @State var orderDate = Date() 30 | @State var shipAddress = "" 31 | @State var shipCity = "" 32 | @State var shipCountry = "" 33 | @State var shipPostalCode = "" 34 | @State var shipRegion = "" 35 | @State var shipVia = 0 36 | @State var productId = 0 37 | @State var quantity = 0 38 | @State var unitPrice = 0.00 39 | 40 | var body: some View { 41 | 42 | let lastOrderId = items.first?._id ?? 10000 43 | 44 | Form { 45 | // Section(header: Text("Customer ID")) { 46 | // // Accessing the observed item object lets us update the live object 47 | // // No need to explicitly update the object in a write transaction 48 | // TextField("Customer ID", text: $customerId) 49 | // } 50 | Section(header: Text("Shipping Address")) { 51 | TextField("Shipping Address", text: $shipAddress) 52 | } 53 | Section(header: Text("Freight")) { 54 | TextField("Freight", value: $freight, format: .number) 55 | } 56 | Section(header: Text("Order Date")) { 57 | TextField("Order Date", value: $orderDate, format: .dateTime) 58 | } 59 | Section(header: Text("City")) { 60 | TextField("City", text: $shipCity) 61 | } 62 | Section(header: Text("Country")) { 63 | TextField("Country", text: $shipCountry) 64 | } 65 | Section(header: Text("Postal Code")) { 66 | TextField("Postal Code", text: $shipPostalCode) 67 | } 68 | // Order Details 69 | Section(header: Text("Product ID")) { 70 | TextField("Product ID", value: $productId, format: .number) 71 | } 72 | Section(header: Text("Quantity")) { 73 | TextField("Quantity", value: $quantity, format: .number) 74 | } 75 | Section(header: Text("Unit Price")) { 76 | TextField("Unit Price", value: $unitPrice, format: .number) 77 | } 78 | 79 | Section { 80 | Button(action: { 81 | // newItem.owner_id = user.id 82 | // To avoid updating too many times and causing Sync-related 83 | // performance issues, we only assign to the `newItem.summary` 84 | // once when the user presses `Save`. 85 | newItem.orderDetails = List() 86 | newItem.orderDetails.append(newOrderDetails) 87 | newItem._id = lastOrderId 88 | newItem._id += 1 89 | newItem.customerId = customerId 90 | newItem.employeeId = employeeId 91 | newItem.freight = freight 92 | newItem.orderDate = orderDate 93 | newItem.shipAddress = shipAddress 94 | newItem.shipCity = shipCity 95 | newItem.shipCountry = shipCountry 96 | newItem.shipPostalCode = shipPostalCode 97 | newItem.shipRegion = shipRegion 98 | newItem.shipVia = shipVia 99 | newOrderDetails.unitPrice = unitPrice 100 | newOrderDetails.productId = productId 101 | newOrderDetails.quantity = quantity 102 | 103 | // Appending the new Item object to the ``items`` 104 | // ObservedResults collection adds it to the 105 | // realm in an implicit write. 106 | $items.append(newItem) 107 | 108 | // Now we're done with this view, so set the 109 | // ``isInCreateItemView`` variable to false to 110 | // return to the ItemsView. 111 | isInCreateItemView = false 112 | }) { 113 | HStack { 114 | Spacer() 115 | Text("Save") 116 | Spacer() 117 | } 118 | } 119 | Button(action: { 120 | // If the user cancels, we don't want to 121 | // append the new object we created to the 122 | // task list, so we set the ``isInCreateItemView`` 123 | // value to false to return to the ItemsView. 124 | isInCreateItemView = false 125 | }) { 126 | HStack { 127 | Spacer() 128 | Text("Cancel") 129 | Spacer() 130 | } 131 | } 132 | } 133 | } 134 | .navigationBarTitle("Add Order") 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app-swift/App/Views/ErrorView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ErrorView: View { 4 | @State var error: Error 5 | 6 | var body: some View { 7 | Text("Error: \(error.localizedDescription)") 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app-swift/App/Views/ItemDetail.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// Show a detail view of a task Item. User can edit the summary or mark the Item complete. 5 | struct ItemDetail: View { 6 | // This property wrapper observes the Item object and 7 | // invalidates the view when the Item object changes. 8 | @ObservedRealmObject var anOrder: order 9 | @State var isInEditMode: Bool? 10 | @State var customerId = "" 11 | @State var shipAddress = "" 12 | @State var freight = 0.00 13 | @State var orderDate = Date() 14 | @State var shipCity = "" 15 | @State var shipCountry = "" 16 | @State var shipName = "" 17 | @State var shipPostalCode = "" 18 | 19 | //WARNING Don't bind a TextField directly to a realm object (anOrder in this case) like we are. This is only for demo purposes. 20 | 21 | var body: some View { 22 | Form { 23 | Section(header: Text("Customer ID")) { 24 | // Accessing the observed item object lets us update the live object 25 | // No need to explicitly update the object in a write transaction 26 | TextField("Customer ID", text: $anOrder.customerId) 27 | } 28 | Section(header: Text("Shipping Address")) { 29 | TextField("Shipping Address", text: $anOrder.shipAddress) 30 | } 31 | Section(header: Text("Freight")) { 32 | TextField("Freight", value: $anOrder.freight, format: .number) 33 | } 34 | Section(header: Text("Order Date")) { 35 | TextField("Order Date", value: $anOrder.orderDate, format: .dateTime) 36 | } 37 | Section(header: Text("City")) { 38 | TextField("City", text: $anOrder.shipCity) 39 | } 40 | Section(header: Text("Country")) { 41 | TextField("Country", text: $anOrder.shipCountry) 42 | } 43 | Section(header: Text("Name")) { 44 | TextField("Name", text: $anOrder.shipName) 45 | } 46 | Section(header: Text("Postal Code")) { 47 | TextField("Postal Code", text: $anOrder.shipPostalCode) 48 | } 49 | NavigationLink(destination: OrderDetailsDetailsView(order: anOrder)) { 50 | Text("Order Details") 51 | } 52 | } 53 | .navigationBarTitle("Order: \(anOrder._id)", displayMode: .inline) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app-swift/App/Views/ItemList.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// View a list of all Items in the realm. User can swipe to delete Items. 5 | struct ItemList: View { 6 | // ObservedResults is a collection of all Item objects in the realm. 7 | // Deleting objects from the observed collection 8 | // deletes them from the realm. 9 | @ObservedResults( 10 | order.self, 11 | sortDescriptor: {SortDescriptor(keyPath: "_id", ascending: false)}() 12 | ) var items 13 | 14 | var body: some View { 15 | 16 | VStack { 17 | List { 18 | ForEach(items) { 19 | item in ItemRow(item: item) 20 | } 21 | .onDelete(perform: $items.remove) 22 | } 23 | .listStyle(InsetListStyle()) 24 | 25 | Spacer() 26 | Text("Log in with the same account on another device or simulator to see your list sync in real-time") 27 | .frame(maxWidth: 300, alignment: .center) 28 | } 29 | .navigationBarTitle("Orders", displayMode: .inline) 30 | 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app-swift/App/Views/ItemRow.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | struct ItemRow: View { 5 | @ObservedRealmObject var item: order 6 | @State var isInEditMode = false 7 | 8 | var body: some View { 9 | NavigationLink(destination: ItemDetail(anOrder: item)) { 10 | Text(String(item._id)) 11 | Spacer() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app-swift/App/Views/ItemsView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// Use views to see a list of all Items, add or delete Items, or logout. 5 | struct ItemsView: View { 6 | var leadingBarButton: AnyView? 7 | // ObservedResults is a mutable collection; here it's 8 | // all of the Item objects in the realm. 9 | // You can append or delete todos directly from the collection. 10 | @ObservedResults(order.self) var item 11 | @State var isInCreateItemView = false 12 | @State var itemSummary = "" 13 | @State var user: User 14 | 15 | var body: some View { 16 | NavigationView { 17 | VStack { 18 | if isInCreateItemView { 19 | CreateItemView(isInCreateItemView: $isInCreateItemView, user: user) 20 | } 21 | else { 22 | ItemList() 23 | } 24 | } 25 | .navigationBarItems(leading: self.leadingBarButton, 26 | trailing: HStack { 27 | Button { 28 | isInCreateItemView = true 29 | } label: { 30 | Image(systemName: "plus") 31 | } 32 | }) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app-swift/App/Views/LoginView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// Log in or register users using email/password authentication 5 | struct LoginView: View { 6 | @State var email = "" 7 | @State var password = "" 8 | 9 | @State private var isLoggingIn = false 10 | @State var error: Error? 11 | 12 | var body: some View { 13 | VStack { 14 | if isLoggingIn { 15 | ProgressView() 16 | } 17 | if let error = error { 18 | Text("Error: \(error.localizedDescription)") 19 | } 20 | Text("My Sync App") 21 | .font(.title) 22 | TextField("Email", text: $email) 23 | .textInputAutocapitalization(.never) 24 | .textFieldStyle(.roundedBorder) 25 | SecureField("Password", text: $password) 26 | .textFieldStyle(.roundedBorder) 27 | Button("Log In") { 28 | // Button pressed, so log in 29 | isLoggingIn = true 30 | Task.init { 31 | await login(email: email, password: password) 32 | isLoggingIn = false 33 | } 34 | } 35 | .disabled(isLoggingIn) 36 | .frame(width: 150, height: 50) 37 | .background(Color.gray) 38 | .foregroundColor(.white) 39 | .clipShape(Capsule()) 40 | Button("Create Account") { 41 | // Button pressed, so create account and then log in 42 | isLoggingIn = true 43 | Task { 44 | await signUp(email: email, password: password) 45 | isLoggingIn = false 46 | } 47 | } 48 | .disabled(isLoggingIn) 49 | .frame(width: 150, height: 50) 50 | .background(Color.gray) 51 | .foregroundColor(.white) 52 | .clipShape(Capsule()) 53 | } 54 | } 55 | 56 | /// Logs in with an existing user. 57 | func login(email: String, password: String) async { 58 | do { 59 | let user = try await realmApp.login(credentials: Credentials.emailPassword(email: email, password: password)) 60 | print("Successfully logged in user: \(user)") 61 | } catch { 62 | print("Failed to log in user: \(error.localizedDescription)") 63 | self.error = error 64 | } 65 | } 66 | 67 | /// Registers a new user with the email/password authentication provider. 68 | func signUp(email: String, password: String) async { 69 | do { 70 | try await realmApp.emailPasswordAuth.registerUser(email: email, password: password) 71 | print("Successfully registered user") 72 | await login(email: email, password: password) 73 | } catch { 74 | print("Failed to register user: \(error.localizedDescription)") 75 | self.error = error 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app-swift/App/Views/LogoutButton.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// Logout from the synchronized realm. Returns the user to the login/sign up screen. 5 | struct LogoutButton: View { 6 | @State var isLoggingOut = false 7 | @State var error: Error? 8 | @State var errorMessage: ErrorMessage? = nil 9 | 10 | var body: some View { 11 | if isLoggingOut { 12 | ProgressView() 13 | } 14 | Button("Log Out") { 15 | guard let user = realmApp.currentUser else { 16 | return 17 | } 18 | isLoggingOut = true 19 | Task { 20 | await logout(user: user) 21 | // Other views are observing the app and will detect 22 | // that the currentUser has changed. Nothing more to do here. 23 | isLoggingOut = false 24 | } 25 | }.disabled(realmApp.currentUser == nil || isLoggingOut) 26 | // Show an alert if there is an error during logout 27 | .alert(item: $errorMessage) { errorMessage in 28 | Alert( 29 | title: Text("Failed to log out"), 30 | message: Text(errorMessage.errorText), 31 | dismissButton: .cancel() 32 | ) 33 | } 34 | } 35 | 36 | /// Asynchronously log the user out, or display an alert with an error if logout fails. 37 | func logout(user: User) async { 38 | do { 39 | try await user.logOut() 40 | print("Successfully logged user out") 41 | } catch { 42 | print("Failed to log user out: \(error.localizedDescription)") 43 | // SwiftUI Alert requires the item it displays to be Identifiable. 44 | // Optional Error is not Identifiable. 45 | // Store the error as errorText in our Identifiable ErrorMessage struct, 46 | // which we can display in the alert. 47 | self.errorMessage = ErrorMessage(errorText: error.localizedDescription) 48 | } 49 | } 50 | } 51 | 52 | struct ErrorMessage: Identifiable { 53 | let id = UUID() 54 | let errorText: String 55 | } 56 | -------------------------------------------------------------------------------- /app-swift/App/Views/OpenRealmView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// Called when login completes. Opens the realm asynchronously and navigates to the Items screen. 5 | struct OpenRealmView: View { 6 | @AsyncOpen(appId: theAppConfig.appId, timeout: 2000) var asyncOpen 7 | // We must pass the user, so we can set the user.id when we create Item objects 8 | @State var user: User 9 | 10 | var body: some View { 11 | switch asyncOpen { 12 | // Starting the Realm.asyncOpen process. 13 | // Show a progress view. 14 | case .connecting: 15 | ProgressView() 16 | // Waiting for a user to be logged in before executing 17 | // Realm.asyncOpen. 18 | case .waitingForUser: 19 | ProgressView("Waiting for user to log in...") 20 | // The realm has been opened and is ready for use. 21 | // Show the Items view. 22 | case .open(let realm): 23 | ItemsView(leadingBarButton: AnyView(LogoutButton()), user: user) 24 | .environment(\.realm, realm) 25 | // The realm is currently being downloaded from the server. 26 | // Show a progress view. 27 | case .progress(let progress): 28 | ProgressView(progress) 29 | // Opening the Realm failed. 30 | // Show an error view. 31 | case .error(let error): 32 | ErrorView(error: error) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app-swift/App/Views/OrderDetailsDetails.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrderDetailsDetails.swift 3 | // App 4 | // 5 | // Created by Mark Franklin on 11/8/22. 6 | // 7 | 8 | import SwiftUI 9 | import RealmSwift 10 | 11 | struct OrderDetailsDetails: View { 12 | @ObservedRealmObject var anOrderDetails: order_orderDetails 13 | @State var quantity = 0 14 | @State var productId = 0 15 | @State var unitPrice = 0.00 16 | 17 | var body: some View { 18 | Form { 19 | Section(header: Text("Quantity")) { 20 | TextField("Quantity", value: $anOrderDetails.quantity, format: .number) 21 | } 22 | Section(header: Text("Product ID")) { 23 | TextField("Product ID", value: $anOrderDetails.productId, format: .number) 24 | } 25 | Section(header: Text("Unit Price")) { 26 | TextField("Unit Price", value: $anOrderDetails.unitPrice, format: .currency(code: "USD")) 27 | } 28 | } 29 | .navigationBarBackButtonHidden() 30 | .navigationBarTitle("Update Order Details") 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app-swift/App/Views/OrderDetailsDetailsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrderDetailsDetailsView.swift 3 | // App 4 | // 5 | // Created by Mark Franklin on 11/14/22. 6 | // 7 | 8 | import SwiftUI 9 | import RealmSwift 10 | 11 | struct OrderDetailsDetailsView: View { 12 | @ObservedRealmObject var order: order 13 | var body: some View { 14 | NavigationView { 15 | VStack { 16 | OrderDetailsList(order: order) 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app-swift/App/Views/OrderDetailsList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrderDetailsList.swift 3 | // App 4 | // 5 | // Created by Mark Franklin on 11/8/22. 6 | // 7 | 8 | import SwiftUI 9 | import RealmSwift 10 | 11 | struct OrderDetailsList: View { 12 | @ObservedRealmObject var order: order 13 | var body: some View { 14 | VStack { 15 | List { 16 | ForEach(order.orderDetails) { 17 | orderDetails in OrderDetailsRow(orderDetails: orderDetails) 18 | } 19 | }.listStyle(InsetListStyle()) 20 | Spacer() 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app-swift/App/Views/OrderDetailsRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrderDetailsRow.swift 3 | // App 4 | // 5 | // Created by Mark Franklin on 11/7/22. 6 | // 7 | 8 | import SwiftUI 9 | import RealmSwift 10 | 11 | struct OrderDetailsRow: View { 12 | @ObservedRealmObject var orderDetails: order_orderDetails 13 | var body: some View { 14 | NavigationLink(destination: OrderDetailsDetails(anOrderDetails: orderDetails)) { 15 | Text(String(orderDetails.productId ?? 0)) 16 | Spacer() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app-swift/App/order.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RealmSwift 3 | 4 | class order: Object, ObjectKeyIdentifiable { 5 | @Persisted(primaryKey: true) var _id: Int 6 | @Persisted var customer: order_customer? 7 | @Persisted var customerId: String 8 | @Persisted var employee: order_employee? 9 | @Persisted var employeeId: Int 10 | @Persisted var freight: Double 11 | @Persisted var orderDate: Date 12 | @Persisted var orderDetails: List 13 | @Persisted var requiredDate: Date? 14 | @Persisted var shipAddress: String 15 | @Persisted var shipCity: String 16 | @Persisted var shipCountry: String 17 | @Persisted var shipName: String 18 | @Persisted var shipPostalCode: String 19 | @Persisted var shipRegion: String 20 | @Persisted var shipVia: Int 21 | @Persisted var shippedDate: Date 22 | } 23 | -------------------------------------------------------------------------------- /app-swift/App/order_customer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RealmSwift 3 | 4 | class order_customer: EmbeddedObject { 5 | @Persisted var companyName: String? 6 | 7 | @Persisted var contactName: String? 8 | 9 | @Persisted var contactTitle: String? 10 | 11 | @Persisted var customerId: String? 12 | 13 | @Persisted var phone: String? 14 | } 15 | -------------------------------------------------------------------------------- /app-swift/App/order_employee.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RealmSwift 3 | 4 | class order_employee: EmbeddedObject { 5 | @Persisted var employeeId: Int? 6 | 7 | @Persisted var firstName: String? 8 | 9 | @Persisted var lastName: String? 10 | 11 | @Persisted var notes: String? 12 | 13 | @Persisted var title: String? 14 | } 15 | -------------------------------------------------------------------------------- /app-swift/App/order_orderDetails.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RealmSwift 3 | 4 | class order_orderDetails: EmbeddedObject, ObjectKeyIdentifiable { 5 | @Persisted var discount: Double? 6 | 7 | @Persisted var product: order_orderDetails_product? 8 | 9 | @Persisted var productId: Int? 10 | 11 | @Persisted var quantity: Int? 12 | 13 | @Persisted var unitPrice: Double? 14 | } 15 | -------------------------------------------------------------------------------- /app-swift/App/order_orderDetails_product.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import RealmSwift 3 | 4 | class order_orderDetails_product: EmbeddedObject { 5 | @Persisted var categoryId: Int? 6 | 7 | @Persisted var productId: Int? 8 | 9 | @Persisted var productName: String? 10 | 11 | @Persisted var quantityPerUnit: String? 12 | } 13 | -------------------------------------------------------------------------------- /app-swift/App/realmApp.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealmSwift 3 | 4 | /// This method loads app config details from a Realm.plist we generate 5 | /// for the template apps. 6 | /// When you create your own Realm app, use your preferred method 7 | /// to store and access app configuration details. 8 | let theAppConfig = loadAppConfig() 9 | 10 | let realmApp = App(id: theAppConfig.appId, configuration: AppConfiguration(baseURL: theAppConfig.baseUrl, transport: nil, localAppName: nil, localAppVersion: nil)) 11 | 12 | @main 13 | struct realmSwiftUIApp: SwiftUI.App { 14 | var body: some Scene { 15 | WindowGroup { 16 | ContentView(app: realmApp) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app-swift/README.md: -------------------------------------------------------------------------------- 1 | # SwiftUI Template App 2 | 3 | This project uses Swift Package Manager (SPM) to load dependencies. 4 | 5 | ## Configuration 6 | 7 | Ensure App/Realm.plist exists and contains the following properties: 8 | 9 | - **appId:** your Realm app ID, which can be found in the Realm app UI at https://realm.mongodb.com 10 | - **baseUrl:** the Realm backend URL. Should be https://realm.mongodb.com in most cases. 11 | 12 | ## Run the app 13 | 14 | - Open App.xcodeproj in Xcode. 15 | - Wait for SPM to download dependencies. 16 | - Press "Run". 17 | 18 | ## Issues 19 | 20 | Please report issues with the template at https://github.com/mongodb-university/realm-template-apps/issues/new 21 | -------------------------------------------------------------------------------- /atlas/clean-colls.js: -------------------------------------------------------------------------------- 1 | use northwind 2 | db.categories.remove({}); 3 | db.customers.remove({}); 4 | db.employees.remove({}); 5 | db.employeeTerritories.remove({}); 6 | db.Item.remove({}); 7 | db.orders.remove({}); 8 | db.products.remove({}); 9 | db.region.remove({}); 10 | db.shippers.remove({}); 11 | db.suppliers.remove({}); 12 | db.territories.remove({}); 13 | db.usStates.remove({}); -------------------------------------------------------------------------------- /atlas/search-indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "default", 3 | "collectionName": "orders", 4 | "database": "northwind", 5 | "mappings": { 6 | "dynamic": true 7 | } 8 | } 9 | 10 | { 11 | "name": "default", 12 | "collectionName": "categories", 13 | "database": "northwind", 14 | "mappings": { 15 | "dynamic": true 16 | } 17 | } -------------------------------------------------------------------------------- /img/app-svc-key.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/app-svc-key.gif -------------------------------------------------------------------------------- /img/categories-index.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/categories-index.gif -------------------------------------------------------------------------------- /img/create-keypair.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/create-keypair.gif -------------------------------------------------------------------------------- /img/demo-components.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/demo-components.jpg -------------------------------------------------------------------------------- /img/orders-index.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/orders-index.gif -------------------------------------------------------------------------------- /img/orders_mappings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/orders_mappings.jpg -------------------------------------------------------------------------------- /img/postman-variables.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/postman-variables.jpg -------------------------------------------------------------------------------- /img/save-vars.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/save-vars.gif -------------------------------------------------------------------------------- /img/swift-app-config.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mongodb-developer/liberate-data/686e85a9c886c74e2f8518297986afffb506f09a/img/swift-app-config.jpg -------------------------------------------------------------------------------- /postgres/backup.sh: -------------------------------------------------------------------------------- 1 | "/Applications/pgAdmin 4.app/Contents/SharedSupport/pg_dump" --file ./northwind.sql --host "localhost" --port "5432" --username "demo" --verbose --role "postgres" --format=p --blobs --create --schema "northwind" postgres 2 | -------------------------------------------------------------------------------- /postman/liberate-data - GraphQL.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "", 4 | "name": "Liberate data!", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", 6 | "_exporter_id": "1711440" 7 | }, 8 | "item": [ 9 | { 10 | "name": "Auth: Get Bearer & Access Token", 11 | "event": [ 12 | { 13 | "listen": "test", 14 | "script": { 15 | "exec": [ 16 | "let jsonData = pm.response.json();", 17 | "console.log(\"jsonData\" + JSON.stringify(jsonData));", 18 | "", 19 | "let access_token = jsonData.access_token;", 20 | "let refresh_token = jsonData.refresh_token;", 21 | "console.log(access_token);", 22 | "console.log(refresh_token);", 23 | "", 24 | "pm.collectionVariables.set('access_token', access_token);", 25 | "pm.collectionVariables.set('refresh_token', refresh_token);" 26 | ], 27 | "type": "text/javascript" 28 | } 29 | } 30 | ], 31 | "request": { 32 | "auth": { 33 | "type": "noauth" 34 | }, 35 | "method": "POST", 36 | "header": [ 37 | { 38 | "key": "Content-Type", 39 | "value": "application/json", 40 | "type": "text" 41 | } 42 | ], 43 | "body": { 44 | "mode": "raw", 45 | "raw": "{\n \"key\": \"{{api_key}}\"\n}" 46 | }, 47 | "url": { 48 | "raw": "https://us-west-2.aws.realm.mongodb.com/api/client/v2.0/app/{{atlas_app_id}}/auth/providers/api-key/login", 49 | "protocol": "https", 50 | "host": [ 51 | "us-west-2", 52 | "aws", 53 | "realm", 54 | "mongodb", 55 | "com" 56 | ], 57 | "path": [ 58 | "api", 59 | "client", 60 | "v2.0", 61 | "app", 62 | "{{atlas_app_id}}", 63 | "auth", 64 | "providers", 65 | "api-key", 66 | "login" 67 | ] 68 | } 69 | }, 70 | "response": [] 71 | }, 72 | { 73 | "name": "Query: Orders shipped to London", 74 | "request": { 75 | "auth": { 76 | "type": "bearer", 77 | "bearer": [ 78 | { 79 | "key": "token", 80 | "value": "{{access_token}}", 81 | "type": "string" 82 | } 83 | ] 84 | }, 85 | "method": "POST", 86 | "header": [ 87 | { 88 | "key": "Content-Type", 89 | "value": "application/json", 90 | "type": "text" 91 | } 92 | ], 93 | "body": { 94 | "mode": "graphql", 95 | "graphql": { 96 | "query": "query {\n orders(query: {shipCity:\"London\"}) {\n _id\n freight\n orderDate\n requiredDate\n shipAddress\n shipCity\n shipCountry\n shipName\n shipPostalCode\n shipRegion\n shipVia\n shippedDate\n customer {\n customerId\n companyName\n contactName\n contactTitle\n }\n employee {\n employeeId\n firstName\n lastName\n } \n orderDetails {\n discount\n quantity\n unitPrice\n product {\n productId\n productName\n quantityPerUnit\n }\n }\n }\n}", 97 | "variables": "" 98 | } 99 | }, 100 | "url": { 101 | "raw": "{{graphql_api}}", 102 | "host": [ 103 | "{{graphql_api}}" 104 | ] 105 | } 106 | }, 107 | "response": [] 108 | }, 109 | { 110 | "name": "Query: Orders shipped to London by Employee 5", 111 | "request": { 112 | "auth": { 113 | "type": "bearer", 114 | "bearer": [ 115 | { 116 | "key": "token", 117 | "value": "{{access_token}}", 118 | "type": "string" 119 | } 120 | ] 121 | }, 122 | "method": "POST", 123 | "header": [ 124 | { 125 | "key": "Content-Type", 126 | "value": "application/json", 127 | "type": "text" 128 | } 129 | ], 130 | "body": { 131 | "mode": "graphql", 132 | "graphql": { 133 | "query": "query ordersByEmployee5($criteria: OrderQueryInput!) {\n orders(query: $criteria) {\n _id\n freight\n orderDate\n requiredDate\n shipAddress\n shipCity\n shipCountry\n shipName\n shipPostalCode\n shipRegion\n shipVia\n shippedDate\n customer {\n customerId\n companyName\n contactName\n contactTitle\n }\n employee {\n employeeId\n firstName\n lastName\n } \n orderDetails {\n discount\n quantity\n unitPrice\n product {\n productId\n productName\n quantityPerUnit\n }\n }\n }\n}", 134 | "variables": "{\n \"criteria\": {\n \"shipCity\":\"London\",\n \"employee\" : {\n \"employeeId\": 5\n }\n }\n}" 135 | } 136 | }, 137 | "url": { 138 | "raw": "{{graphql_api}}", 139 | "host": [ 140 | "{{graphql_api}}" 141 | ] 142 | } 143 | }, 144 | "response": [] 145 | }, 146 | { 147 | "name": "Query: Orders shipped to London by Employee 1 to Customer EASTC", 148 | "request": { 149 | "auth": { 150 | "type": "bearer", 151 | "bearer": [ 152 | { 153 | "key": "token", 154 | "value": "{{access_token}}", 155 | "type": "string" 156 | } 157 | ] 158 | }, 159 | "method": "POST", 160 | "header": [ 161 | { 162 | "key": "Content-Type", 163 | "value": "application/json", 164 | "type": "text" 165 | } 166 | ], 167 | "body": { 168 | "mode": "graphql", 169 | "graphql": { 170 | "query": "query ordersByEmployee5($criteria: OrderQueryInput!) {\n orders(query: $criteria) {\n _id\n freight\n orderDate\n requiredDate\n shipAddress\n shipCity\n shipCountry\n shipName\n shipPostalCode\n shipRegion\n shipVia\n shippedDate\n customer {\n customerId\n companyName\n contactName\n contactTitle\n }\n employee {\n employeeId\n firstName\n lastName\n } \n orderDetails {\n discount\n quantity\n unitPrice\n product {\n productId\n productName\n quantityPerUnit\n }\n }\n }\n}", 171 | "variables": "{\n \"criteria\": {\n \"shipCity\":\"London\",\n \"employee\" : {\n \"employeeId\": 1\n },\n \"customer\" : {\n \"customerId\": \"EASTC\"\n }\n }\n}" 172 | } 173 | }, 174 | "url": { 175 | "raw": "{{graphql_api}}", 176 | "host": [ 177 | "{{graphql_api}}" 178 | ] 179 | } 180 | }, 181 | "response": [] 182 | }, 183 | { 184 | "name": "Search: Orders by search string", 185 | "request": { 186 | "auth": { 187 | "type": "bearer", 188 | "bearer": [ 189 | { 190 | "key": "token", 191 | "value": "{{access_token}}", 192 | "type": "string" 193 | } 194 | ] 195 | }, 196 | "method": "POST", 197 | "header": [ 198 | { 199 | "key": "Content-Type", 200 | "value": "application/json", 201 | "type": "text" 202 | } 203 | ], 204 | "body": { 205 | "mode": "graphql", 206 | "graphql": { 207 | "query": "query {\n searchOrders(input:\"nwl clm chwdr\") {\n _id\n freight\n orderDate\n requiredDate\n shipAddress\n shipCity\n shipCountry\n shipName\n shipPostalCode\n shipRegion\n shipVia\n shippedDate\n customer {\n companyName\n contactName\n contactTitle\n }\n employee {\n firstName\n lastName\n } \n orderDetails {\n discount\n productId\n quantity\n unitPrice\n product {\n categoryId\n productName\n quantityPerUnit\n }\n }\n }\n}", 208 | "variables": "" 209 | } 210 | }, 211 | "url": { 212 | "raw": "{{graphql_api}}", 213 | "host": [ 214 | "{{graphql_api}}" 215 | ] 216 | } 217 | }, 218 | "response": [] 219 | }, 220 | { 221 | "name": "Vector Search: Semantic search on Orders", 222 | "request": { 223 | "auth": { 224 | "type": "bearer", 225 | "bearer": [ 226 | { 227 | "key": "token", 228 | "value": "{{access_token}}", 229 | "type": "string" 230 | } 231 | ] 232 | }, 233 | "method": "POST", 234 | "header": [ 235 | { 236 | "key": "Content-Type", 237 | "value": "application/json", 238 | "type": "text" 239 | } 240 | ], 241 | "body": { 242 | "mode": "graphql", 243 | "graphql": { 244 | "query": "query {\n vectorSearchOrders(input:\"Customers who ordered seafood and beer with a discount of 10 percent or more\") {\n _id\n freight\n orderDate\n requiredDate\n shipAddress\n shipCity\n shipCountry\n shipName\n shipPostalCode\n shipRegion\n shipVia\n shippedDate\n customer {\n companyName\n contactName\n contactTitle\n }\n employee {\n firstName\n lastName\n } \n orderDetails {\n discount\n productId\n quantity\n unitPrice\n product {\n categoryId\n productName\n quantityPerUnit\n }\n }\n }\n}", 245 | "variables": "" 246 | } 247 | }, 248 | "url": { 249 | "raw": "{{graphql_api}}", 250 | "host": [ 251 | "{{graphql_api}}" 252 | ] 253 | } 254 | }, 255 | "response": [] 256 | }, 257 | { 258 | "name": "Mutation: Change a Sales Order", 259 | "request": { 260 | "auth": { 261 | "type": "bearer", 262 | "bearer": [ 263 | { 264 | "key": "token", 265 | "value": "{{access_token}}", 266 | "type": "string" 267 | } 268 | ] 269 | }, 270 | "method": "POST", 271 | "header": [ 272 | { 273 | "key": "Content-Type", 274 | "value": "application/json", 275 | "type": "text" 276 | } 277 | ], 278 | "body": { 279 | "mode": "graphql", 280 | "graphql": { 281 | "query": "mutation {\n updateOneOrder(\n query: { \n _id: 10364\n },\n set: { \n shipAddress: \"1633 Broadway 38th floor\",\n shipCity: \" New York\",\n shipCountry: \"USA\",\n shipName: \"Atte: Valmik (aka Sig's doppelganger)\",\n shipPostalCode: \"10019\",\n shipRegion: \"NY\"\n }) {\n _id\n orderDate\n shipAddress\n shipCity\n shipCountry\n shipName\n shipPostalCode\n shipRegion\n }\n}", 282 | "variables": "" 283 | } 284 | }, 285 | "url": { 286 | "raw": "{{graphql_api}}", 287 | "host": [ 288 | "{{graphql_api}}" 289 | ] 290 | } 291 | }, 292 | "response": [] 293 | } 294 | ], 295 | "event": [ 296 | { 297 | "listen": "prerequest", 298 | "script": { 299 | "type": "text/javascript", 300 | "exec": [ 301 | "" 302 | ] 303 | } 304 | }, 305 | { 306 | "listen": "test", 307 | "script": { 308 | "type": "text/javascript", 309 | "exec": [ 310 | "" 311 | ] 312 | } 313 | } 314 | ], 315 | "variable": [ 316 | { 317 | "key": "access_token", 318 | "value": "" 319 | }, 320 | { 321 | "key": "refresh_token", 322 | "value": "", 323 | "type": "string" 324 | }, 325 | { 326 | "key": "api_key", 327 | "value": "<>", 328 | "type": "string" 329 | }, 330 | { 331 | "key": "atlas_app_id", 332 | "value": "<>", 333 | "type": "string" 334 | }, 335 | { 336 | "key": "graphql_api", 337 | "value": "<>", 338 | "type": "string" 339 | } 340 | ] 341 | } --------------------------------------------------------------------------------