diff --git a/MarketService/GraphTypes/AddressType.cs b/MarketService/GraphTypes/AddressType.cs
new file mode 100644
index 0000000..23a9af4
--- /dev/null
+++ b/MarketService/GraphTypes/AddressType.cs
@@ -0,0 +1,67 @@
+using HotChocolate.Language;
+using Libplanet.Crypto;
+
+namespace MarketService.GraphTypes;
+
+public class AddressType : ScalarType
+{
+ public AddressType() : base("address")
+ {
+ }
+
+ public override IValueNode ParseResult(object? resultValue)
+ {
+ return ParseValue(resultValue);
+ }
+
+ protected override Address ParseLiteral(StringValueNode valueSyntax)
+ {
+ return new Address(valueSyntax.Value);
+ }
+
+ protected override StringValueNode ParseValue(Address runtimeValue)
+ {
+ return new(Serialize(runtimeValue));
+ }
+
+ private static string Serialize(Address runtimeValue)
+ {
+ return runtimeValue.ToString();
+ }
+
+ public override bool TrySerialize(object? runtimeValue, out object? resultValue)
+ {
+ if (runtimeValue is null)
+ {
+ resultValue = null;
+ return true;
+ }
+
+ if (runtimeValue is Address a)
+ {
+ resultValue = Serialize(a);
+ return true;
+ }
+
+ resultValue = null;
+ return false;
+ }
+
+ public override bool TryDeserialize(object? resultValue, out object? runtimeValue)
+ {
+ if (resultValue is null)
+ {
+ runtimeValue = null;
+ return true;
+ }
+
+ if (resultValue is Address)
+ {
+ runtimeValue = resultValue;
+ return true;
+ }
+
+ runtimeValue = null;
+ return false;
+ }
+}
diff --git a/MarketService/GraphTypes/FungibleAssetValueProductFilterType.cs b/MarketService/GraphTypes/FungibleAssetValueProductFilterType.cs
new file mode 100644
index 0000000..941877e
--- /dev/null
+++ b/MarketService/GraphTypes/FungibleAssetValueProductFilterType.cs
@@ -0,0 +1,13 @@
+using HotChocolate.Data.Filters;
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class FungibleAssetValueProductFilterType: FilterInputType
+{
+ protected override void Configure(IFilterInputTypeDescriptor descriptor)
+ {
+ descriptor.Field(f => f.SellerAgentAddress).Type();
+ descriptor.Field(f => f.SellerAvatarAddress).Type();
+ }
+}
diff --git a/MarketService/GraphTypes/FungibleAssetValueProductModelType.cs b/MarketService/GraphTypes/FungibleAssetValueProductModelType.cs
new file mode 100644
index 0000000..36c7962
--- /dev/null
+++ b/MarketService/GraphTypes/FungibleAssetValueProductModelType.cs
@@ -0,0 +1,45 @@
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class FungibleAssetValueProductModelType : ObjectType
+{
+ protected override void Configure(IObjectTypeDescriptor descriptor)
+ {
+ descriptor.BindFieldsExplicitly();
+ descriptor
+ .Field(f => f.ProductId)
+ .Type();
+ descriptor
+ .Field(f => f.SellerAgentAddress)
+ .Type();
+ descriptor
+ .Field(f => f.SellerAvatarAddress)
+ .Type();
+ descriptor
+ .Field(f => f.Price)
+ .Type();
+ descriptor
+ .Field(f => f.Quantity)
+ .Type();
+ descriptor
+ .Field(f => f.RegisteredBlockIndex)
+ .Type();
+ descriptor
+ .Field(f => f.Exist)
+ .Type();
+ descriptor
+ .Field(f => f.Legacy)
+ .Type();
+ descriptor
+ .Field(f => f.CreatedAt)
+ .Type();
+ descriptor
+ .Field(f => f.UnitPrice)
+ .Type();
+ descriptor.Field(f => f.DecimalPlaces)
+ .Type>();
+ descriptor.Field(f => f.Ticker)
+ .Type();
+ }
+}
diff --git a/MarketService/GraphTypes/ItemProductFilterType.cs b/MarketService/GraphTypes/ItemProductFilterType.cs
new file mode 100644
index 0000000..e2e98e7
--- /dev/null
+++ b/MarketService/GraphTypes/ItemProductFilterType.cs
@@ -0,0 +1,13 @@
+using HotChocolate.Data.Filters;
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class ItemProductFilterType : FilterInputType
+{
+ protected override void Configure(IFilterInputTypeDescriptor descriptor)
+ {
+ descriptor.Field(f => f.SellerAgentAddress).Type();
+ descriptor.Field(f => f.SellerAvatarAddress).Type();
+ }
+}
diff --git a/MarketService/GraphTypes/ItemProductModelType.cs b/MarketService/GraphTypes/ItemProductModelType.cs
new file mode 100644
index 0000000..5450ed5
--- /dev/null
+++ b/MarketService/GraphTypes/ItemProductModelType.cs
@@ -0,0 +1,60 @@
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class ItemProductModelType : ObjectType
+{
+ protected override void Configure(IObjectTypeDescriptor descriptor)
+ {
+ descriptor.BindFieldsExplicitly();
+ descriptor
+ .Field(f => f.ProductId)
+ .Type();
+ descriptor
+ .Field(f => f.SellerAgentAddress)
+ .Type();
+ descriptor
+ .Field(f => f.SellerAvatarAddress)
+ .Type();
+ descriptor
+ .Field(f => f.Price)
+ .Type();
+ descriptor
+ .Field(f => f.Quantity)
+ .Type();
+ descriptor
+ .Field(f => f.RegisteredBlockIndex)
+ .Type();
+ descriptor
+ .Field(f => f.Exist)
+ .Type();
+ descriptor
+ .Field(f => f.Legacy)
+ .Type();
+ descriptor
+ .Field(f => f.CreatedAt)
+ .Type();
+ descriptor
+ .Field(f => f.UnitPrice)
+ .Type();
+ descriptor.Field(f => f.ItemId)
+ .Type>();
+ descriptor.Field(f => f.Grade)
+ .Type>();
+ descriptor
+ .Field(f => f.CreatedAt)
+ .Type();
+ descriptor.Field(f => f.ItemType);
+ descriptor.Field(f => f.ItemSubType);
+ descriptor.Field(f => f.ElementalType);
+ descriptor.Field(f => f.SetId);
+ descriptor.Field(f => f.CombatPoint);
+ descriptor.Field(f => f.Level);
+ descriptor.Field(f => f.Crystal);
+ descriptor.Field(f => f.CrystalPerPrice);
+ descriptor.Field(f => f.OptionCountFromCombination);
+ descriptor
+ .Field(f => f.Skills)
+ .Type>();
+ }
+}
diff --git a/MarketService/GraphTypes/ProductFilterType.cs b/MarketService/GraphTypes/ProductFilterType.cs
new file mode 100644
index 0000000..d9da218
--- /dev/null
+++ b/MarketService/GraphTypes/ProductFilterType.cs
@@ -0,0 +1,22 @@
+using HotChocolate.Data.Filters;
+using Libplanet.Crypto;
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class ProductFilterType : FilterInputType
+{
+ protected override void Configure(IFilterInputTypeDescriptor descriptor)
+ {
+ descriptor.Field(f => f.SellerAgentAddress).Type();
+ descriptor.Field(f => f.SellerAvatarAddress).Type();
+ }
+
+ public class CustomAddressOperationFilterInputType : StringOperationFilterInputType
+ {
+ protected override void Configure(IFilterInputTypeDescriptor descriptor)
+ {
+ descriptor.Operation(DefaultFilterOperations.Equals).Type();
+ }
+ }
+}
diff --git a/MarketService/GraphTypes/ProductModelType.cs b/MarketService/GraphTypes/ProductModelType.cs
new file mode 100644
index 0000000..f2a6bd8
--- /dev/null
+++ b/MarketService/GraphTypes/ProductModelType.cs
@@ -0,0 +1,12 @@
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class ProductModelType : UnionType
+{
+ protected override void Configure(IUnionTypeDescriptor descriptor)
+ {
+ descriptor.Type();
+ descriptor.Type();
+ }
+}
diff --git a/MarketService/GraphTypes/QueryType.cs b/MarketService/GraphTypes/QueryType.cs
new file mode 100644
index 0000000..e26d14d
--- /dev/null
+++ b/MarketService/GraphTypes/QueryType.cs
@@ -0,0 +1,31 @@
+namespace MarketService.GraphTypes;
+
+public class QueryType : ObjectType
+{
+ protected override void Configure(IObjectTypeDescriptor descriptor)
+ {
+ descriptor
+ .Field(f => Query.GetProducts(default!))
+ .Type>()
+ .UsePaging()
+ .UseProjection()
+ .UseFiltering()
+ .UseSorting();
+
+ descriptor
+ .Field(f => Query.GetFavProducts(default!))
+ .Type>()
+ .UsePaging()
+ .UseProjection()
+ .UseFiltering()
+ .UseSorting();
+
+ descriptor
+ .Field(f => Query.GetItemProducts(default!))
+ .Type>()
+ .UsePaging()
+ .UseProjection()
+ .UseFiltering()
+ .UseSorting();
+ }
+}
diff --git a/MarketService/GraphTypes/SkillModelType.cs b/MarketService/GraphTypes/SkillModelType.cs
new file mode 100644
index 0000000..e255995
--- /dev/null
+++ b/MarketService/GraphTypes/SkillModelType.cs
@@ -0,0 +1,11 @@
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class SkillModelType : ObjectType
+{
+ protected override void Configure(IObjectTypeDescriptor descriptor)
+ {
+ descriptor.Ignore(f => f.ToResponse());
+ }
+}
diff --git a/MarketService/GraphTypes/StatModelType.cs b/MarketService/GraphTypes/StatModelType.cs
new file mode 100644
index 0000000..13ec9cb
--- /dev/null
+++ b/MarketService/GraphTypes/StatModelType.cs
@@ -0,0 +1,11 @@
+using MarketService.Models;
+
+namespace MarketService.GraphTypes;
+
+public class StatModelType: ObjectType
+{
+ protected override void Configure(IObjectTypeDescriptor descriptor)
+ {
+ descriptor.Ignore(f => f.ToResponse());
+ }
+}
diff --git a/MarketService/MarketService.csproj b/MarketService/MarketService.csproj
index 33b45f5..9e59b84 100644
--- a/MarketService/MarketService.csproj
+++ b/MarketService/MarketService.csproj
@@ -13,6 +13,8 @@
+
+
diff --git a/MarketService/Program.cs b/MarketService/Program.cs
index 4770ccb..0cd031b 100644
--- a/MarketService/Program.cs
+++ b/MarketService/Program.cs
@@ -1,4 +1,6 @@
using System.Text.Json.Serialization;
+using HotChocolate.Types.Pagination;
+using MarketService.GraphTypes;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
@@ -88,6 +90,15 @@ public void ConfigureServices(IServiceCollection services)
services.AddHealthChecks()
.AddDbContextCheck()
.AddCheck(nameof(RpcNodeHealthCheck));
+ services
+ .AddGraphQLServer()
+ .RegisterDbContext()
+ .AddQueryType()
+ .AddErrorFilter()
+ .AddProjections()
+ .AddFiltering()
+ .AddSorting()
+ .SetPagingOptions(new PagingOptions());
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@@ -101,8 +112,18 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseRouting();
app.UseEndpoints(endpoints =>
{
+ endpoints.MapGraphQL();
endpoints.MapControllers();
endpoints.MapHealthChecks("/ping");
});
}
+
+ public class GraphqlErrorFilter : IErrorFilter
+ {
+ public IError OnError(IError error)
+ {
+ var msg = error.Exception?.Message ?? error.Message;
+ return error.WithMessage(msg);
+ }
+ }
}
diff --git a/MarketService/Query.cs b/MarketService/Query.cs
new file mode 100644
index 0000000..c6f27a1
--- /dev/null
+++ b/MarketService/Query.cs
@@ -0,0 +1,22 @@
+using MarketService.Models;
+using Microsoft.EntityFrameworkCore;
+
+namespace MarketService;
+
+public class Query
+{
+ public static IQueryable GetProducts([Service] MarketContext dbContext)
+ {
+ return dbContext.Products.AsNoTracking().AsQueryable();
+ }
+
+ public static IQueryable GetFavProducts([Service] MarketContext dbContext)
+ {
+ return dbContext.FungibleAssetValueProducts.AsNoTracking().AsQueryable();
+ }
+
+ public static IQueryable GetItemProducts([Service] MarketContext dbContext)
+ {
+ return dbContext.ItemProducts.AsNoTracking().AsQueryable();
+ }
+}