Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

collection-cards #2059

Merged
merged 11 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;

namespace NexusMods.Abstractions.NexusModsLibrary.Attributes;

public class FloatAttribute(string ns, string name) : ScalarAttribute<float, float>(ValueTags.Float32, ns, name)
{
protected override float ToLowLevel(float value)
{
return value;
}

protected override float FromLowLevel(float value, ValueTags tags, RegistryId registryId)
{
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Buffers;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;

namespace NexusMods.Abstractions.NexusModsLibrary.Attributes;

/// <summary>
/// A hashed blob attribute for <see cref="Memory{T}"/>.
/// </summary>
public class MemoryAttribute(string ns, string name) : HashedBlobAttribute<Memory<byte>>(ns, name)
{
/// <inheritdoc />
protected override Memory<byte> FromLowLevel(ReadOnlySpan<byte> value, ValueTags tags, RegistryId registryId)
{
return new Memory<byte>(value.ToArray());
}

/// <inheritdoc />
protected override void WriteValue<TWriter>(Memory<byte> value, TWriter writer)
{
writer.Write(value.Span);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;

namespace NexusMods.Abstractions.NexusModsLibrary;

/// <summary>
/// A tag for a collection.
/// </summary>
public partial class CollectionTag : IModelDefinition
{
private const string Namespace = "NexusMods.Abstractions.NexusModsLibrary.CollectionTag";

/// <summary>
/// The name of the collection tag.
/// </summary>
public static readonly StringAttribute Name = new(Namespace, nameof(Name)) { IsIndexed = true };

/// <summary>
/// The Nexus mods id of the collection tag.
/// </summary>
public static readonly ULongAttribute NexusId = new(Namespace, nameof(NexusId)) { IsIndexed = true };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
using Splat.ModeDetection;

namespace NexusMods.Abstractions.NexusModsLibrary;

/// <summary>
/// A helper for upserting entities in the database. When created, you must define a "pimary key" attribute and value,
/// these are used to determine if the entity already exists in the database. If it does, the existing entity is updated,
/// otherwise a new entity is created.
///
/// For each attribute you want to add to the entity, call the Add method with the attribute and value and any duplicate values
/// will not be added.
/// </summary>
// ReSharper disable once InconsistentNaming
public readonly struct GraphQLResolver(ITransaction Tx, ReadOnlyModel Model)
{
/// <summary>
/// Create a new resolver using the given primary key attribute and value.
/// </summary>
public static GraphQLResolver Create<THighLevel, TLowLevel>(IDb referenceDb, ITransaction tx, ScalarAttribute<THighLevel, TLowLevel> primaryKeyAttribute, THighLevel primaryKeyValue) where THighLevel : notnull
{
var existing = referenceDb.Datoms(primaryKeyAttribute, primaryKeyValue);
var exists = existing.Count > 0;
var id = existing.Count == 0 ? tx.TempId() : existing[0].E;
if (!exists)
tx.Add(id, primaryKeyAttribute, primaryKeyValue);
return new GraphQLResolver(tx, new ReadOnlyModel(referenceDb, id));
}

/// <summary>
/// The id of the entity, may be temporary if this is a new entity.
/// </summary>
public EntityId Id => Model.Id;

/// <summary>
/// Add a value to the entity. If the value already exists, it will not be added again.
/// </summary>
public void Add<THighLevel, TLowLevel>(ScalarAttribute<THighLevel, TLowLevel> attribute, THighLevel value)
where THighLevel : notnull
{
if (attribute.TryGet(Model, out var foundValue))
{
// Deduplicate values
if (foundValue.Equals(value))
return;
}
// Else add the value
Tx.Add(Model.Id, attribute, value);
}

/// <summary>
/// Add a value to the entity. If the value already exists, it will not be added again.
/// </summary>
public void Add<TOther>(ReferencesAttribute<TOther> attribute, EntityId id)
where TOther : IModelDefinition
{
if (PartitionId.Temp == id.Partition)
{
Tx.Add(Model.Id, attribute, id);
return;
}

if (attribute.Get(Model).Contains(id))
return;

// Else add the value
Tx.Add(Model.Id, attribute, id);
}

/// <summary>
/// Add a value to the entity. If the value already exists, it will not be added again.
/// </summary>
public void Add<TOther>(ReferenceAttribute<TOther> attribute, EntityId id)
where TOther : IModelDefinition
{
if (PartitionId.Temp == id.Partition)
{
Tx.Add(Model.Id, attribute, id);
return;
}

if (attribute.Get(Model).Equals(id))
return;

// Else add the value
Tx.Add(Model.Id, attribute, id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.Abstractions.NexusModsLibrary.Attributes;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;

namespace NexusMods.Abstractions.NexusModsLibrary.Models;

/// <summary>
/// Metadata about a collection on Nexus Mods.
/// </summary>
public partial class Collection : IModelDefinition
halgari marked this conversation as resolved.
Show resolved Hide resolved
{
private const string Namespace = "NexusMods.Library.NexusModsCollectionMetadata";

/// <summary>
/// The collection slug.
/// </summary>
public static readonly CollectionsSlugAttribute Slug = new(Namespace, nameof(Slug)) { IsIndexed = true };

/// <summary>
/// The name of the collection.
/// </summary>
public static readonly StringAttribute Name = new(Namespace, nameof(Name));

/// <summary>
/// The short description of the collection
/// </summary>
public static readonly StringAttribute Summary = new(Namespace, nameof(Summary));

/// <summary>
/// The Curating user of the collection.
/// </summary>
public static readonly ReferenceAttribute<User> User = new(Namespace, nameof(User));
halgari marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// The revisions of the collection.
/// </summary>
public static readonly BackReferenceAttribute<CollectionRevision> Revisions = new(CollectionRevision.Collection);

/// <summary>
/// The tags on the collection.
/// </summary>
public static readonly ReferencesAttribute<CollectionTag> Tags = new(Namespace, nameof(Tags));

/// <summary>
/// The number of endorsements the collection has.
/// </summary>
public static readonly ULongAttribute Endorsements = new(Namespace, nameof(Endorsements));

/// <summary>
/// The collections' image.
/// </summary>
public static readonly MemoryAttribute TileImage = new(Namespace, nameof(TileImage));
halgari marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.Abstractions.NexusModsLibrary.Attributes;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;

namespace NexusMods.Abstractions.NexusModsLibrary.Models;

/// <summary>
/// Metadata about a collection revision on Nexus Mods. A revision references a collection, but is itself immutable.
/// Each change to a collection is expressed as a separate revision.
/// </summary>
public partial class CollectionRevision : IModelDefinition
{
private const string Namespace = "NexusMods.Library.NexusModsCollectionRevision";

/// <summary>
/// The globally unique id identifying a specific revision of a collection.
/// </summary>
public static readonly RevisionIdAttribute RevisionId = new(Namespace, nameof(RevisionId)) { IsIndexed = true };

/// <summary>
/// The locally unique revision number (aka "version") of a collection. Only unique within one collection.
/// </summary>
public static readonly RevisionNumberAttribute RevisionNumber = new(Namespace, nameof(RevisionNumber));

/// <summary>
/// The collection this revision belongs to.
/// </summary>
public static readonly ReferenceAttribute<Collection> Collection = new(Namespace, nameof(Collection));

/// <summary>
/// The number of downloads this revision has.
/// </summary>
public static readonly ULongAttribute Downloads = new(Namespace, nameof(Downloads));

/// <summary>
/// Total size of all files in this revision, including the size of the revision's files.
/// </summary>
public static readonly SizeAttribute TotalSize = new(Namespace, nameof(TotalSize));
halgari marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// The overall rating of this revision (often displayed as a percentage).
/// </summary>
public static readonly FloatAttribute OverallRating = new(Namespace, nameof(OverallRating));

/// <summary>
/// The total number of ratings this revision has.
/// </summary>
public static readonly ULongAttribute TotalRatings = new(Namespace, nameof(TotalRatings));

/// <summary>
/// The total number of mods in this revision.
/// </summary>
public static readonly ULongAttribute ModCount = new(Namespace, nameof(ModCount));
halgari marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using NexusMods.Abstractions.MnemonicDB.Attributes;
using NexusMods.Abstractions.NexusModsLibrary.Attributes;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;

namespace NexusMods.Abstractions.NexusModsLibrary.Models;

/// <summary>
/// A user on Nexus Mods.
/// </summary>
public partial class User : IModelDefinition
{
private const string Namespace = "NexusMods.Abstractions.NexusModsLibrary.User";

/// <summary>
/// The user's username.
/// </summary>
public static readonly StringAttribute Name = new(Namespace, nameof(Name)) { IsIndexed = true };

/// <summary>
/// The nexus id of the user.
/// </summary>
public static readonly ULongAttribute NexusId = new(Namespace, nameof(NexusId)) { IsIndexed = true };

/// <summary>
/// The user's avatar URL.
/// </summary>
public static readonly UriAttribute Avatar = new(Namespace, nameof(Avatar));

/// <summary>
/// The user's avatar image.
/// </summary>
public static readonly MemoryAttribute AvatarImage = new(Namespace, nameof(AvatarImage));
erri120 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ public partial class NexusModsCollectionLibraryFile : IModelDefinition
/// <summary>
/// The collection revision this file belongs to.
/// </summary>
public static readonly ReferenceAttribute<NexusModsCollectionRevision> CollectionRevision = new(Namespace, nameof(CollectionRevision));
public static readonly ReferenceAttribute<Models.CollectionRevision> CollectionRevision = new(Namespace, nameof(CollectionRevision));
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using NexusMods.Abstractions.NexusModsLibrary.Models;

namespace NexusMods.Abstractions.NexusModsLibrary;

Expand All @@ -18,8 +19,10 @@ public static IServiceCollection AddNexusModsLibraryModels(this IServiceCollecti
.AddNexusModsFileMetadataModel()
.AddNexusModsModPageMetadataModel()
.AddNexusModsLibraryFileModel()
.AddNexusModsCollectionMetadataModel()
.AddNexusModsCollectionRevisionModel()
.AddCollectionModel()
.AddCollectionRevisionModel()
.AddCollectionTagModel()
.AddUserModel()
.AddNexusModsCollectionLibraryFileModel();
}
}
Loading
Loading