text: // Copyright (c) Microsoft Corporation. All rights reserved.
  // Licensed under the MIT License.
  
  // WARNING! Do not edit this file manually, your changes will be overwritten.
  
  #include "QueryObject.h"
  #include "MutationObject.h"
  #include "SubscriptionObject.h"
  
  #include "graphqlservice/internal/Schema.h"
  
  #include "graphqlservice/introspection/IntrospectionSchema.h"
  
  #include <algorithm>
  #include <array>
  #include <functional>
  #include <sstream>
  #include <stdexcept>
  #include <string_view>
  #include <tuple>
  #include <vector>
  
  using namespace std::literals;
  
  namespace graphql {
  namespace service {
  
  static const std::array<std::string_view, 10> s_namesSpecialFolder = {
  	R"gql(INBOX)gql"sv,
  	R"gql(CALENDAR)gql"sv,
  	R"gql(CONTACTS)gql"sv,
  	R"gql(TASKS)gql"sv,
  	R"gql(ARCHIVE)gql"sv,
  	R"gql(DELETED)gql"sv,
  	R"gql(DRAFTS)gql"sv,
  	R"gql(OUTBOX)gql"sv,
  	R"gql(SENT)gql"sv,
  	R"gql(SPAM)gql"sv
  };
  
  template <>
  mapi::SpecialFolder ModifiedArgument<mapi::SpecialFolder>::convert(const response::Value& value)
  {
  	if (!value.maybe_enum())
  	{
  		throw service::schema_exception { { R"ex(not a valid SpecialFolder value)ex" } };
  	}
  
  	const auto itr = std::find(s_namesSpecialFolder.cbegin(), s_namesSpecialFolder.cend(), value.get<std::string>());
  
  	if (itr == s_namesSpecialFolder.cend())
  	{
  		throw service::schema_exception { { R"ex(not a valid SpecialFolder value)ex" } };
  	}
  
  	return static_cast<mapi::SpecialFolder>(itr - s_namesSpecialFolder.cbegin());
  }
  
  template <>
  service::AwaitableResolver ModifiedResult<mapi::SpecialFolder>::convert(service::AwaitableScalar<mapi::SpecialFolder> result, ResolverParams params)
  {
  	return resolve(std::move(result), std::move(params),
  		[](mapi::SpecialFolder value, const ResolverParams&)
  		{
  			response::Value result(response::Type::EnumValue);
  
  			result.set<std::string>(std::string { s_namesSpecialFolder[static_cast<size_t>(value)] });
  
  			return result;
  		});
  }
  
  template <>
  void ModifiedResult<mapi::SpecialFolder>::validateScalar(const response::Value& value)
  {
  	if (!value.maybe_enum())
  	{
  		throw service::schema_exception { { R"ex(not a valid SpecialFolder value)ex" } };
  	}
  
  	const auto itr = std::find(s_namesSpecialFolder.cbegin(), s_namesSpecialFolder.cend(), value.get<std::string>());
  
  	if (itr == s_namesSpecialFolder.cend())
  	{
  		throw service::schema_exception { { R"ex(not a valid SpecialFolder value)ex" } };
  	}
  }
  
  static const std::array<std::string_view, 7> s_namesPropType = {
  	R"gql(INT)gql"sv,
  	R"gql(BOOL)gql"sv,
  	R"gql(STRING)gql"sv,
  	R"gql(GUID)gql"sv,
  	R"gql(DATETIME)gql"sv,
  	R"gql(BINARY)gql"sv,
  	R"gql(STREAM)gql"sv
  };
  
  template <>
  mapi::PropType ModifiedArgument<mapi::PropType>::convert(const response::Value& value)
  {
  	if (!value.maybe_enum())
  	{
  		throw service::schema_exception { { R"ex(not a valid PropType value)ex" } };
  	}
  
  	const auto itr = std::find(s_namesPropType.cbegin(), s_namesPropType.cend(), value.get<std::string>());
  
  	if (itr == s_namesPropType.cend())
  	{
  		throw service::schema_exception { { R"ex(not a valid PropType value)ex" } };
  	}
  
  	return static_cast<mapi::PropType>(itr - s_namesPropType.cbegin());
  }
  
  template <>
  service::AwaitableResolver ModifiedResult<mapi::PropType>::convert(service::AwaitableScalar<mapi::PropType> result, ResolverParams params)
  {
  	return resolve(std::move(result), std::move(params),
  		[](mapi::PropType value, const ResolverParams&)
  		{
  			response::Value result(response::Type::EnumValue);
  
  			result.set<std::string>(std::string { s_namesPropType[static_cast<size_t>(value)] });
  
  			return result;
  		});
  }
  
  template <>
  void ModifiedResult<mapi::PropType>::validateScalar(const response::Value& value)
  {
  	if (!value.maybe_enum())
  	{
  		throw service::schema_exception { { R"ex(not a valid PropType value)ex" } };
  	}
  
  	const auto itr = std::find(s_namesPropType.cbegin(), s_namesPropType.cend(), value.get<std::string>());
  
  	if (itr == s_namesPropType.cend())
  	{
  		throw service::schema_exception { { R"ex(not a valid PropType value)ex" } };
  	}
  }
  
  template <>
  mapi::ObjectId ModifiedArgument<mapi::ObjectId>::convert(const response::Value& value)
  {
  	auto valueStoreId = service::ModifiedArgument<response::IdType>::require("storeId", value);
  	auto valueObjectId = service::ModifiedArgument<response::IdType>::require("objectId", value);
  
  	return {
  		std::move(valueStoreId),
  		std::move(valueObjectId)
  	};
  }
  
  template <>
  mapi::NamedPropInput ModifiedArgument<mapi::NamedPropInput>::convert(const response::Value& value)
  {
  	auto valuePropset = service::ModifiedArgument<response::Value>::require("propset", value);
  	auto valueId = service::ModifiedArgument<int>::require<service::TypeModifier::Nullable>("id", value);
  	auto valueName = service::ModifiedArgument<std::string>::require<service::TypeModifier::Nullable>("name", value);
  
  	return {
  		std::move(valuePropset),
  		std::move(valueId),
  		std::move(valueName)
  	};
  }
  
  template <>
  mapi::PropValueInput ModifiedArgument<mapi::PropValueInput>::convert(const response::Value& value)
  {
  	auto valueInteger = service::ModifiedArgument<int>::require<service::TypeModifier::Nullable>("integer", value);
  	auto valueBoolean = service::ModifiedArgument<bool>::require<service::TypeModifier::Nullable>("boolean", value);
  	auto valueString = service::ModifiedArgument<std::string>::require<service::TypeModifier::Nullable>("string", value);
  	auto valueGuid = service::ModifiedArgument<response::Value>::require<service::TypeModifier::Nullable>("guid", value);
  	auto valueTime = service::ModifiedArgument<response::Value>::require<service::TypeModifier::Nullable>("time", value);
  	auto valueBin = service::ModifiedArgument<response::IdType>::require<service::TypeModifier::Nullable>("bin", value);
  	auto valueStream = service::ModifiedArgument<response::Value>::require<service::TypeModifier::Nullable>("stream", value);
  
  	return {
  		std::move(valueInteger),
  		std::move(valueBoolean),
  		std::move(valueString),
  		std::move(valueGuid),
  		std::move(valueTime),
  		std::move(valueBin),
  		std::move(valueStream)
  	};
  }
  
  template <>
  mapi::MultipleItemsInput ModifiedArgument<mapi::MultipleItemsInput>::convert(const response::Value& value)
  {
  	auto valueFolderId = service::ModifiedArgument<mapi::ObjectId>::require("folderId", value);
  	auto valueItemIds = service::ModifiedArgument<response::IdType>::require<service::TypeModifier::List>("itemIds", value);
  
  	return {
  		std::move(valueFolderId),
  		std::move(valueItemIds)
  	};
  }
  
  template <>
  mapi::PropIdInput ModifiedArgument<mapi::PropIdInput>::convert(const response::Value& value)
  {
  	auto valueId = service::ModifiedArgument<int>::require<service::TypeModifier::Nullable>("id", value);
  	auto valueNamed = service::ModifiedArgument<mapi::NamedPropInput>::require<service::TypeModifier::Nullable>("named", value);
  
  	return {
  		std::move(valueId),
  		std::move(valueNamed)
  	};
  }
  
  template <>
  mapi::PropertyInput ModifiedArgument<mapi::PropertyInput>::convert(const response::Value& value)
  {
  	auto valueId = service::ModifiedArgument<mapi::PropIdInput>::require("id", value);
  	auto valueValue = service::ModifiedArgument<mapi::PropValueInput>::require("value", value);
  
  	return {
  		std::move(valueId),
  		std::move(valueValue)
  	};
  }
  
  template <>
  mapi::Order ModifiedArgument<mapi::Order>::convert(const response::Value& value)
  {
  	const auto defaultValue = []()
  	{
  		response::Value values(response::Type::Map);
  		response::Value entry;
  
  		entry = response::Value(false);
  		values.emplace_back("descending", std::move(entry));
  
  		return values;
  	}();
  
  	auto pairDescending = service::ModifiedArgument<bool>::find("descending", value);
  	auto valueDescending = (pairDescending.second
  		? std::move(pairDescending.first)
  		: service::ModifiedArgument<bool>::require("descending", defaultValue));
  	auto valueProperty = service::ModifiedArgument<mapi::PropIdInput>::require("property", value);
  	auto valueType = service::ModifiedArgument<mapi::PropType>::require("type", value);
  
  	return {
  		std::move(valueDescending),
  		std::move(valueProperty),
  		std::move(valueType)
  	};
  }
  
  template <>
  mapi::Column ModifiedArgument<mapi::Column>::convert(const response::Value& value)
  {
  	auto valueProperty = service::ModifiedArgument<mapi::PropIdInput>::require("property", value);
  	auto valueType = service::ModifiedArgument<mapi::PropType>::require("type", value);
  
  	return {
  		std::move(valueProperty),
  		std::move(valueType)
  	};
  }
  
  template <>
  mapi::CreateItemInput ModifiedArgument<mapi::CreateItemInput>::convert(const response::Value& value)
  {
  	const auto defaultValue = []()
  	{
  		response::Value values(response::Type::Map);
  		response::Value entry;
  
  		entry = response::Value(false);
  		values.emplace_back("read", std::move(entry));
  
  		return values;
  	}();
  
  	auto valueFolderId = service::ModifiedArgument<mapi::ObjectId>::require("folderId", value);
  	auto valueSubject = service::ModifiedArgument<std::string>::require("subject", value);
  	auto valueConversationId = service::ModifiedArgument<response::IdType>::require<service::TypeModifier::Nullable>("conversationId", value);
  	auto pairRead = service::ModifiedArgument<bool>::find("read", value);
  	auto valueRead = (pairRead.second
  		? std::move(pairRead.first)
  		: service::ModifiedArgument<bool>::require("read", defaultValue));
  	auto valueReceived = service::ModifiedArgument<response::Value>::require<service::TypeModifier::Nullable>("received", value);
  	auto valueModified = service::ModifiedArgument<response::Value>::require<service::TypeModifier::Nullable>("modified", value);
  	auto valueProperties = service::ModifiedArgument<mapi::PropertyInput>::require<service::TypeModifier::Nullable, service::TypeModifier::List>("properties", value);
  
  	return {
  		std::move(valueFolderId),
  		std::move(valueSubject),
  		std::move(valueConversationId),
  		std::move(valueRead),
  		std::move(valueReceived),
  		std::move(valueModified),
  		std::move(valueProperties)
  	};
  }
  
  template <>
  mapi::CreateSubFolderInput ModifiedArgument<mapi::CreateSubFolderInput>::convert(const response::Value& value)
  {
  	auto valueFolderId = service::ModifiedArgument<mapi::ObjectId>::require("folderId", value);
  	auto valueName = service::ModifiedArgument<std::string>::require("name", value);
  	auto valueProperties = service::ModifiedArgument<mapi::PropertyInput>::require<service::TypeModifier::Nullable, service::TypeModifier::List>("properties", value);
  
  	return {
  		std::move(valueFolderId),
  		std::move(valueName),
  		std::move(valueProperties)
  	};
  }
  
  template <>
  mapi::ModifyItemInput ModifiedArgument<mapi::ModifyItemInput>::convert(const response::Value& value)
  {
  	auto valueId = service::ModifiedArgument<mapi::ObjectId>::require("id", value);
  	auto valueSubject = service::ModifiedArgument<std::string>::require<service::TypeModifier::Nullable>("subject", value);
  	auto valueRead = service::ModifiedArgument<bool>::require<service::TypeModifier::Nullable>("read", value);
  	auto valueProperties = service::ModifiedArgument<mapi::PropertyInput>::require<service::TypeModifier::Nullable, service::TypeModifier::List>("properties", value);
  	auto valueDeleted = service::ModifiedArgument<mapi::PropIdInput>::require<service::TypeModifier::Nullable, service::TypeModifier::List>("deleted", value);
  
  	return {
  		std::move(valueId),
  		std::move(valueSubject),
  		std::move(valueRead),
  		std::move(valueProperties),
  		std::move(valueDeleted)
  	};
  }
  
  template <>
  mapi::ModifyFolderInput ModifiedArgument<mapi::ModifyFolderInput>::convert(const response::Value& value)
  {
  	auto valueFolderId = service::ModifiedArgument<mapi::ObjectId>::require("folderId", value);
  	auto valueName = service::ModifiedArgument<std::string>::require<service::TypeModifier::Nullable>("name", value);
  	auto valueProperties = service::ModifiedArgument<mapi::PropertyInput>::require<service::TypeModifier::Nullable, service::TypeModifier::List>("properties", value);
  	auto valueDeleted = service::ModifiedArgument<mapi::PropIdInput>::require<service::TypeModifier::Nullable, service::TypeModifier::List>("deleted", value);
  
  	return {
  		std::move(valueFolderId),
  		std::move(valueName),
  		std::move(valueProperties),
  		std::move(valueDeleted)
  	};
  }
  
  } // namespace service
  
  namespace mapi {
  
  Operations::Operations(std::shared_ptr<object::Query> query, std::shared_ptr<object::Mutation> mutation, std::shared_ptr<object::Subscription> subscription)
  	: service::Request({
  		{ "query", query },
  		{ "mutation", mutation },
  		{ "subscription", subscription }
  	}, GetSchema())
  	, _query(std::move(query))
  	, _mutation(std::move(mutation))
  	, _subscription(std::move(subscription))
  {
  }
  
  void AddTypesToSchema(const std::shared_ptr<schema::Schema>& schema)
  {
  	schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md([ISO 8601](https://en.m.wikipedia.org/wiki/ISO_8601) date/time format)md", R"url()url"sv));
  	schema->AddType(R"gql(Guid)gql"sv, schema::ScalarType::Make(R"gql(Guid)gql"sv, R"md(128-bit Guid type)md", R"url()url"sv));
  	schema->AddType(R"gql(Stream)gql"sv, schema::ScalarType::Make(R"gql(Stream)gql"sv, R"md(Opaque stream descriptor with enough information to read/write the stream outside of GraphQL, e.g. through native module or fetch APIs.)md", R"url()url"sv));
  	auto typeSpecialFolder = schema::EnumType::Make(R"gql(SpecialFolder)gql"sv, R"md(Special folders are created by default in most stores.)md"sv);
  	schema->AddType(R"gql(SpecialFolder)gql"sv, typeSpecialFolder);
  	auto typePropType = schema::EnumType::Make(R"gql(PropType)gql"sv, R"md(When sorting by a property ID you need to include the expected property type.)md"sv);
  	schema->AddType(R"gql(PropType)gql"sv, typePropType);
  	auto typeObjectId = schema::InputObjectType::Make(R"gql(ObjectId)gql"sv, R"md(Pair of IDs which uniquely identify a folder or item across all stores)md"sv);
  	schema->AddType(R"gql(ObjectId)gql"sv, typeObjectId);
  	auto typeNamedPropInput = schema::InputObjectType::Make(R"gql(NamedPropInput)gql"sv, R"md(Named property ID description)md"sv);
  	schema->AddType(R"gql(NamedPropInput)gql"sv, typeNamedPropInput);
  	auto typePropValueInput = schema::InputObjectType::Make(R"gql(PropValueInput)gql"sv, R"md(Property value variant type)md"sv);
  	schema->AddType(R"gql(PropValueInput)gql"sv, typePropValueInput);
  	auto typeMultipleItemsInput = schema::InputObjectType::Make(R"gql(MultipleItemsInput)gql"sv, R"md(Properties which can be used to identify multiple items in the same folder for bulk operations)md"sv);
  	schema->AddType(R"gql(MultipleItemsInput)gql"sv, typeMultipleItemsInput);
  	auto typePropIdInput = schema::InputObjectType::Make(R"gql(PropIdInput)gql"sv, R"md(Property ID for either a built-in or named property)md"sv);
  	schema->AddType(R"gql(PropIdInput)gql"sv, typePropIdInput);
  	auto typePropertyInput = schema::InputObjectType::Make(R"gql(PropertyInput)gql"sv, R"md(Complete property type used for setting properties on items or folders)md"sv);
  	schema->AddType(R"gql(PropertyInput)gql"sv, typePropertyInput);
  	auto typeOrder = schema::InputObjectType::Make(R"gql(Order)gql"sv, R"md(Sort in ascending or descending order based on a single property.)md"sv);
  	schema->AddType(R"gql(Order)gql"sv, typeOrder);
  	auto typeColumn = schema::InputObjectType::Make(R"gql(Column)gql"sv, R"md(Add a column to the columns property on an object collection.)md"sv);
  	schema->AddType(R"gql(Column)gql"sv, typeColumn);
  	auto typeCreateItemInput = schema::InputObjectType::Make(R"gql(CreateItemInput)gql"sv, R"md(Properties which can be used to create a new item)md"sv);
  	schema->AddType(R"gql(CreateItemInput)gql"sv, typeCreateItemInput);
  	auto typeCreateSubFolderInput = schema::InputObjectType::Make(R"gql(CreateSubFolderInput)gql"sv, R"md(Properties which can be used to create a new sub-folder)md"sv);
  	schema->AddType(R"gql(CreateSubFolderInput)gql"sv, typeCreateSubFolderInput);
  	auto typeModifyItemInput = schema::InputObjectType::Make(R"gql(ModifyItemInput)gql"sv, R"md(Properties which can be used to modify an existing item)md"sv);
  	schema->AddType(R"gql(ModifyItemInput)gql"sv, typeModifyItemInput);
  	auto typeModifyFolderInput = schema::InputObjectType::Make(R"gql(ModifyFolderInput)gql"sv, R"md(Properties which can be used to modify an existing folder)md"sv);
  	schema->AddType(R"gql(ModifyFolderInput)gql"sv, typeModifyFolderInput);
  	auto typeAttachment = schema::UnionType::Make(R"gql(Attachment)gql"sv, R"md(Attachments can be either a file or another item.)md"sv);
  	schema->AddType(R"gql(Attachment)gql"sv, typeAttachment);
  	auto typeNamedPropId = schema::UnionType::Make(R"gql(NamedPropId)gql"sv, R"md()md"sv);
  	schema->AddType(R"gql(NamedPropId)gql"sv, typeNamedPropId);
  	auto typePropId = schema::UnionType::Make(R"gql(PropId)gql"sv, R"md(Property IDs are either built-in integer IDs or named property descriptions.)md"sv);
  	schema->AddType(R"gql(PropId)gql"sv, typePropId);
  	auto typePropValue = schema::UnionType::Make(R"gql(PropValue)gql"sv, R"md(Property values are a variant of these types.)md"sv);
  	schema->AddType(R"gql(PropValue)gql"sv, typePropValue);
  	auto typeItemChange = schema::UnionType::Make(R"gql(ItemChange)gql"sv, R"md(Subscriptions on items can deliver any of these payloads when a matching item changes.)md"sv);
  	schema->AddType(R"gql(ItemChange)gql"sv, typeItemChange);
  	auto typeFolderChange = schema::UnionType::Make(R"gql(FolderChange)gql"sv, R"md(Subscriptions on folders can deliver any of these payloads when a matching folder changes.)md"sv);
  	schema->AddType(R"gql(FolderChange)gql"sv, typeFolderChange);
  	auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"sv);
  	schema->AddType(R"gql(Query)gql"sv, typeQuery);
  	auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"sv);
  	schema->AddType(R"gql(Mutation)gql"sv, typeMutation);
  	auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"sv);
  	schema->AddType(R"gql(Subscription)gql"sv, typeSubscription);
  	auto typeStore = schema::ObjectType::Make(R"gql(Store)gql"sv, R"md(Each MAPI session might have multiple stores.)md"sv);
  	schema->AddType(R"gql(Store)gql"sv, typeStore);
  	auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md(Folders create a hierarchy within each store.)md"sv);
  	schema->AddType(R"gql(Folder)gql"sv, typeFolder);
  	auto typeItem = schema::ObjectType::Make(R"gql(Item)gql"sv, R"md(Items are contained in folders.)md"sv);
  	schema->AddType(R"gql(Item)gql"sv, typeItem);
  	auto typeFileAttachment = schema::ObjectType::Make(R"gql(FileAttachment)gql"sv, R"md(Files may be attached to Items.)md"sv);
  	schema->AddType(R"gql(FileAttachment)gql"sv, typeFileAttachment);
  	auto typeConversation = schema::ObjectType::Make(R"gql(Conversation)gql"sv, R"md(Items may be grouped into conversations which roll-up properties from the items.)md"sv);
  	schema->AddType(R"gql(Conversation)gql"sv, typeConversation);
  	auto typeIntId = schema::ObjectType::Make(R"gql(IntId)gql"sv, R"md(This type represents a built-in or named property integer ID in a union.)md"sv);
  	schema->AddType(R"gql(IntId)gql"sv, typeIntId);
  	auto typeStringId = schema::ObjectType::Make(R"gql(StringId)gql"sv, R"md(This type represents a named property string name in a union.)md"sv);
  	schema->AddType(R"gql(StringId)gql"sv, typeStringId);
  	auto typeNamedId = schema::ObjectType::Make(R"gql(NamedId)gql"sv, R"md(This type represents a complete named property ID.)md"sv);
  	schema->AddType(R"gql(NamedId)gql"sv, typeNamedId);
  	auto typeIntValue = schema::ObjectType::Make(R"gql(IntValue)gql"sv, R"md(This type represents an Int value in a property value variant union.)md"sv);
  	schema->AddType(R"gql(IntValue)gql"sv, typeIntValue);
  	auto typeBoolValue = schema::ObjectType::Make(R"gql(BoolValue)gql"sv, R"md(This type represents a Boolean value in a property value variant union.)md"sv);
  	schema->AddType(R"gql(BoolValue)gql"sv, typeBoolValue);
  	auto typeStringValue = schema::ObjectType::Make(R"gql(StringValue)gql"sv, R"md(This type represents a String value in a property value variant union.)md"sv);
  	schema->AddType(R"gql(StringValue)gql"sv, typeStringValue);
  	auto typeGuidValue = schema::ObjectType::Make(R"gql(GuidValue)gql"sv, R"md(This type represents a Guid value in a property value variant union.)md"sv);
  	schema->AddType(R"gql(GuidValue)gql"sv, typeGuidValue);
  	auto typeDateTimeValue = schema::ObjectType::Make(R"gql(DateTimeValue)gql"sv, R"md(This type represents a DateTime value in a property value variant union.)md"sv);
  	schema->AddType(R"gql(DateTimeValue)gql"sv, typeDateTimeValue);
  	auto typeBinaryValue = schema::ObjectType::Make(R"gql(BinaryValue)gql"sv, R"md(This type represents an ID value in a property value variant union.)md"sv);
  	schema->AddType(R"gql(BinaryValue)gql"sv, typeBinaryValue);
  	auto typeStreamValue = schema::ObjectType::Make(R"gql(StreamValue)gql"sv, R"md(This type represents a Stream value in a property value variant union.)md"sv);
  	schema->AddType(R"gql(StreamValue)gql"sv, typeStreamValue);
  	auto typeProperty = schema::ObjectType::Make(R"gql(Property)gql"sv, R"md(A complete property includes the property ID and the property value.)md"sv);
  	schema->AddType(R"gql(Property)gql"sv, typeProperty);
  	auto typeItemAdded = schema::ObjectType::Make(R"gql(ItemAdded)gql"sv, R"md(Payload for subscription events when an `Item` is added)md"sv);
  	schema->AddType(R"gql(ItemAdded)gql"sv, typeItemAdded);
  	auto typeItemUpdated = schema::ObjectType::Make(R"gql(ItemUpdated)gql"sv, R"md(Payload for subscription events when an `Item` is updated)md"sv);
  	schema->AddType(R"gql(ItemUpdated)gql"sv, typeItemUpdated);
  	auto typeItemRemoved = schema::ObjectType::Make(R"gql(ItemRemoved)gql"sv, R"md(Payload for subscription events when an `Item` is removed)md"sv);
  	schema->AddType(R"gql(ItemRemoved)gql"sv, typeItemRemoved);
  	auto typeItemsReloaded = schema::ObjectType::Make(R"gql(ItemsReloaded)gql"sv, R"md(Payload for subscription events when all of the `Item` rows have been reloaded)md"sv);
  	schema->AddType(R"gql(ItemsReloaded)gql"sv, typeItemsReloaded);
  	auto typeFolderAdded = schema::ObjectType::Make(R"gql(FolderAdded)gql"sv, R"md(Payload for subscription events when an `Folder` is added)md"sv);
  	schema->AddType(R"gql(FolderAdded)gql"sv, typeFolderAdded);
  	auto typeFolderUpdated = schema::ObjectType::Make(R"gql(FolderUpdated)gql"sv, R"md(Payload for subscription events when an `Folder` is updated)md"sv);
  	schema->AddType(R"gql(FolderUpdated)gql"sv, typeFolderUpdated);
  	auto typeFolderRemoved = schema::ObjectType::Make(R"gql(FolderRemoved)gql"sv, R"md(Payload for subscription events when an `Folder` is removed)md"sv);
  	schema->AddType(R"gql(FolderRemoved)gql"sv, typeFolderRemoved);
  	auto typeFoldersReloaded = schema::ObjectType::Make(R"gql(FoldersReloaded)gql"sv, R"md(Payload for subscription events when all of the `Folder` rows have been reloaded)md"sv);
  	schema->AddType(R"gql(FoldersReloaded)gql"sv, typeFoldersReloaded);
  
  	typeSpecialFolder->AddEnumValues({
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::INBOX)], R"md(Default delivery location for new mail items)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::CALENDAR)], R"md(Default calendar folder containing appointment items)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::CONTACTS)], R"md(Default contacts folder containing names, addresses, email, and notes about people or organizations)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::TASKS)], R"md(Default tasks folder containing a list of tasks to be completed)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::ARCHIVE)], R"md(Default archive folder for items which have been archived instead of deleted)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::DELETED)], R"md(Deleted items folder for this store which is periodically emptied)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::DRAFTS)], R"md(Drafts of items which have not been sent yet)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::OUTBOX)], R"md(Folder containing sent items which have not been delivered yet)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::SENT)], R"md(Folder containing sent items which have been delivered)md"sv, std::nullopt },
  		{ service::s_namesSpecialFolder[static_cast<size_t>(mapi::SpecialFolder::SPAM)], R"md(Junk email folder containing messages that have been marked as spam)md"sv, std::nullopt }
  	});
  	typePropType->AddEnumValues({
  		{ service::s_namesPropType[static_cast<size_t>(mapi::PropType::INT)], R"md(This property expects an `IntValue`)md"sv, std::nullopt },
  		{ service::s_namesPropType[static_cast<size_t>(mapi::PropType::BOOL)], R"md(This property expects a `BoolValue`)md"sv, std::nullopt },
  		{ service::s_namesPropType[static_cast<size_t>(mapi::PropType::STRING)], R"md(This property expects a `StringValue`)md"sv, std::nullopt },
  		{ service::s_namesPropType[static_cast<size_t>(mapi::PropType::GUID)], R"md(This property expects a `GuidValue`)md"sv, std::nullopt },
  		{ service::s_namesPropType[static_cast<size_t>(mapi::PropType::DATETIME)], R"md(This property expects a `DateTimeValue`)md"sv, std::nullopt },
  		{ service::s_namesPropType[static_cast<size_t>(mapi::PropType::BINARY)], R"md(This property expects a `BinaryValue`)md"sv, std::nullopt },
  		{ service::s_namesPropType[static_cast<size_t>(mapi::PropType::STREAM)], R"md(This property expects a `StreamValue`)md"sv, std::make_optional(R"md(You can't sort on a `StreamValue`)md"sv) }
  	});
  
  	typeObjectId->AddInputValues({
  		schema::InputValue::Make(R"gql(storeId)gql"sv, R"md(ID of the store containing the object)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(objectId)gql"sv, R"md(ID of the object)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)), R"gql()gql"sv)
  	});
  	typeNamedPropInput->AddInputValues({
  		schema::InputValue::Make(R"gql(propset)gql"sv, R"md(Property set Guid)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Guid)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(id)gql"sv, R"md(Integer ID, mutually exclusive with `name`)md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(name)gql"sv, R"md(String name, mutually exclusive with `id`)md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv)
  	});
  	typePropValueInput->AddInputValues({
  		schema::InputValue::Make(R"gql(integer)gql"sv, R"md(Integer value, mutually exclusive with all other fields)md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(boolean)gql"sv, R"md(Boolean value, mutually exclusive with all other fields)md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(string)gql"sv, R"md(String value, mutually exclusive with all other fields)md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(guid)gql"sv, R"md(Guid value, mutually exclusive with all other fields)md"sv, schema->LookupType(R"gql(Guid)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(time)gql"sv, R"md(DateTime value, mutually exclusive with all other fields)md"sv, schema->LookupType(R"gql(DateTime)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(bin)gql"sv, R"md(Binary value, mutually exclusive with all other fields)md"sv, schema->LookupType(R"gql(ID)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(stream)gql"sv, R"md(Stream value, mutually exclusive with all other fields)md"sv, schema->LookupType(R"gql(Stream)gql"sv), R"gql()gql"sv)
  	});
  	typeMultipleItemsInput->AddInputValues({
  		schema::InputValue::Make(R"gql(folderId)gql"sv, R"md(Parent folder ID)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ObjectId)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(itemIds)gql"sv, R"md(List of item IDs on which to perform the bulk operation)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ID)gql"sv)))), R"gql()gql"sv)
  	});
  	typePropIdInput->AddInputValues({
  		schema::InputValue::Make(R"gql(id)gql"sv, R"md(Built-in property ID, mutually exclusive with `named`)md"sv, schema->LookupType(R"gql(Int)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(named)gql"sv, R"md(Named property ID, mutually exclusive with `id`)md"sv, schema->LookupType(R"gql(NamedPropInput)gql"sv), R"gql()gql"sv)
  	});
  	typePropertyInput->AddInputValues({
  		schema::InputValue::Make(R"gql(id)gql"sv, R"md(Property ID)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropIdInput)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(value)gql"sv, R"md(Property value)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropValueInput)gql"sv)), R"gql()gql"sv)
  	});
  	typeOrder->AddInputValues({
  		schema::InputValue::Make(R"gql(descending)gql"sv, R"md(True if the property values should be sorted in descending order, false if they should be sorted in ascending order (default))md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), R"gql(false)gql"sv),
  		schema::InputValue::Make(R"gql(property)gql"sv, R"md(Property ID of the sorted value)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropIdInput)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(type)gql"sv, R"md(Expected type of the sorted value)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropType)gql"sv)), R"gql()gql"sv)
  	});
  	typeColumn->AddInputValues({
  		schema::InputValue::Make(R"gql(property)gql"sv, R"md(Property ID of the sorted value)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropIdInput)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(type)gql"sv, R"md(Expected type of the sorted value)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropType)gql"sv)), R"gql()gql"sv)
  	});
  	typeCreateItemInput->AddInputValues({
  		schema::InputValue::Make(R"gql(folderId)gql"sv, R"md(Target folder ID)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ObjectId)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(subject)gql"sv, R"md(Subject of the new item)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(conversationId)gql"sv, R"md(Immutable conversation ID, optional but must be set at creation)md"sv, schema->LookupType(R"gql(ID)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(read)gql"sv, R"md(True if the item is marked as read, false if it is unread)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Boolean)gql"sv)), R"gql(false)gql"sv),
  		schema::InputValue::Make(R"gql(received)gql"sv, R"md(Immutable received/creation time, optional but must be set at creation, defaults to current time)md"sv, schema->LookupType(R"gql(DateTime)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(modified)gql"sv, R"md(Optional last modified time, defaults to current time)md"sv, schema->LookupType(R"gql(DateTime)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(properties)gql"sv, R"md(List of properties to set on the item at the time of creation)md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropertyInput)gql"sv))), R"gql()gql"sv)
  	});
  	typeCreateSubFolderInput->AddInputValues({
  		schema::InputValue::Make(R"gql(folderId)gql"sv, R"md(Target parent folder ID)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ObjectId)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(name)gql"sv, R"md(Name of the new folder)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(String)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(properties)gql"sv, R"md(List of properties to set on the folder at the time of creation)md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropertyInput)gql"sv))), R"gql()gql"sv)
  	});
  	typeModifyItemInput->AddInputValues({
  		schema::InputValue::Make(R"gql(id)gql"sv, R"md(ID of an existing item)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ObjectId)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(subject)gql"sv, R"md(Optionally change the item subject)md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(read)gql"sv, R"md(Optionally mark the item as read/unread)md"sv, schema->LookupType(R"gql(Boolean)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(properties)gql"sv, R"md(List of properties to set/overwrite on the existing item)md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropertyInput)gql"sv))), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(deleted)gql"sv, R"md(List of properties to remove from the existing item)md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropIdInput)gql"sv))), R"gql()gql"sv)
  	});
  	typeModifyFolderInput->AddInputValues({
  		schema::InputValue::Make(R"gql(folderId)gql"sv, R"md(ID of an existing folder)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(ObjectId)gql"sv)), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(name)gql"sv, R"md(Optionally rename the folder)md"sv, schema->LookupType(R"gql(String)gql"sv), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(properties)gql"sv, R"md(List of properties to set/overwrite on the existing folder)md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropertyInput)gql"sv))), R"gql()gql"sv),
  		schema::InputValue::Make(R"gql(deleted)gql"sv, R"md(List of properties to remove from the existing folder)md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(PropIdInput)gql"sv))), R"gql()gql"sv)
  	});
  
  	AddAttachmentDetails(typeAttachment, schema);
  	AddNamedPropIdDetails(typeNamedPropId, schema);
  	AddPropIdDetails(typePropId, schema);
  	AddPropValueDetails(typePropValue, schema);
  	AddItemChangeDetails(typeItemChange, schema);
  	AddFolderChangeDetails(typeFolderChange, schema);
  
  	AddQueryDetails(typeQuery, schema);
  	AddMutationDetails(typeMutation, schema);
  	AddSubscriptionDetails(typeSubscription, schema);
  	AddStoreDetails(typeStore, schema);
  	AddFolderDetails(typeFolder, schema);
  	AddItemDetails(typeItem, schema);
  	AddFileAttachmentDetails(typeFileAttachment, schema);
  	AddConversationDetails(typeConversation, schema);
  	AddIntIdDetails(typeIntId, schema);
  	AddStringIdDetails(typeStringId, schema);
  	AddNamedIdDetails(typeNamedId, schema);
  	AddIntValueDetails(typeIntValue, schema);
  	AddBoolValueDetails(typeBoolValue, schema);
  	AddStringValueDetails(typeStringValue, schema);
  	AddGuidValueDetails(typeGuidValue, schema);
  	AddDateTimeValueDetails(typeDateTimeValue, schema);
  	AddBinaryValueDetails(typeBinaryValue, schema);
  	AddStreamValueDetails(typeStreamValue, schema);
  	AddPropertyDetails(typeProperty, schema);
  	AddItemAddedDetails(typeItemAdded, schema);
  	AddItemUpdatedDetails(typeItemUpdated, schema);
  	AddItemRemovedDetails(typeItemRemoved, schema);
  	AddItemsReloadedDetails(typeItemsReloaded, schema);
  	AddFolderAddedDetails(typeFolderAdded, schema);
  	AddFolderUpdatedDetails(typeFolderUpdated, schema);
  	AddFolderRemovedDetails(typeFolderRemoved, schema);
  	AddFoldersReloadedDetails(typeFoldersReloaded, schema);
  
  	schema->AddDirective(schema::Directive::Make(R"gql(orderBy)gql"sv, R"md(Sort the results of any object collection by the values of these properties.)md"sv, {
  		introspection::DirectiveLocation::FIELD
  	}, {
  		schema::InputValue::Make(R"gql(sorts)gql"sv, R"md(Sort and sub-sort orders)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Order)gql"sv)))), R"gql()gql"sv)
  	}, false));
  	schema->AddDirective(schema::Directive::Make(R"gql(columns)gql"sv, R"md(Add columns to the columns field in any object collection.)md"sv, {
  		introspection::DirectiveLocation::FIELD
  	}, {
  		schema::InputValue::Make(R"gql(ids)gql"sv, R"md(Additional column property IDs)md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Column)gql"sv)))), R"gql()gql"sv)
  	}, false));
  	schema->AddDirective(schema::Directive::Make(R"gql(seek)gql"sv, R"md(Seek to the element with `id`, or after the last element if `id` is `null`. If combined with `@skip`, first the cursor will be placed on the element with `id`, then the `count` offset will be applied relative to that starting point.)md"sv, {
  		introspection::DirectiveLocation::FIELD
  	}, {
  		schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->LookupType(R"gql(ID)gql"sv), R"gql(null)gql"sv)
  	}, false));
  	schema->AddDirective(schema::Directive::Make(R"gql(offset)gql"sv, R"md(Define a window on any non-property field by skipping `count` elements. The `count` argument may be negative when combined with `@seek`.)md"sv, {
  		introspection::DirectiveLocation::FIELD
  	}, {
  		schema::InputValue::Make(R"gql(count)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv)), R"gql()gql"sv)
  	}, false));
  	schema->AddDirective(schema::Directive::Make(R"gql(take)gql"sv, R"md(Define a window on any non-property field by taking a maximum of `count` elements. The `count` argument may be negative when combined with `@seek` or `@offset`, but in that case it will not take any elements beyond the starting point.)md"sv, {
  		introspection::DirectiveLocation::FIELD
  	}, {
  		schema::InputValue::Make(R"gql(count)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType(R"gql(Int)gql"sv)), R"gql()gql"sv)
  	}, false));
  
  	schema->AddQueryType(typeQuery);
  	schema->AddMutationType(typeMutation);
  	schema->AddSubscriptionType(typeSubscription);
  }
  
  std::shared_ptr<schema::Schema> GetSchema()
  {
  	static std::weak_ptr<schema::Schema> s_wpSchema;
  	auto schema = s_wpSchema.lock();
  
  	if (!schema)
  	{
  		schema = std::make_shared<schema::Schema>(false, R"md()md"sv);
  		introspection::AddTypesToSchema(schema);
  		AddTypesToSchema(schema);
  		s_wpSchema = schema;
  	}
  
  	return schema;
  }
  
  } // namespace mapi
  } // namespace graphql
  