types.h Example FileΒΆ

<@comment>// Copyright (C) 2022 The Qt Company Ltd.</@comment>
<@comment>// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause</@comment>
<@preprocessor>#ifndef TYPES_H</@preprocessor>
<@preprocessor>#define TYPES_H</@preprocessor>

<@preprocessor>#include &lt;QtGui/QColor&gt;</@preprocessor>
<@preprocessor>#include &lt;QtCore/QDateTime&gt;</@preprocessor>
<@preprocessor>#include &lt;QtCore/QJsonArray&gt;</@preprocessor>
<@preprocessor>#include &lt;QtCore/QJsonObject&gt;</@preprocessor>
<@preprocessor>#include &lt;QtCore/QJsonParseError&gt;</@preprocessor>
<@preprocessor>#include &lt;QtCore/QString&gt;</@preprocessor>
<@preprocessor>#include &lt;QtCore/qtypes.h&gt;</@preprocessor>

<@preprocessor>#include &lt;algorithm&gt;</@preprocessor>
<@preprocessor>#include &lt;optional&gt;</@preprocessor>

<@keyword>struct</@keyword> Jsonable
{
    <@keyword>virtual</@keyword> <@type>QJsonObject</@type> toJson() <@keyword>const</@keyword> <@op>=</@op> <@number>0</@number>;
    <@keyword>virtual</@keyword> <@op>~</@op>Jsonable() <@op>=</@op> <@keyword>default</@keyword>;
};

<@keyword>struct</@keyword> Updatable
{
    <@keyword>virtual</@keyword> <@type>bool</@type> update(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) <@op>=</@op> <@number>0</@number>;
    <@keyword>virtual</@keyword> <@type>void</@type> updateFields(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) <@op>=</@op> <@number>0</@number>;
    <@keyword>virtual</@keyword> <@op>~</@op>Updatable() <@op>=</@op> <@keyword>default</@keyword>;
};

<@keyword>template</@keyword><@op>&lt;</@op><@keyword>typename</@keyword> T<@op>&gt;</@op>
<@keyword>struct</@keyword> FromJsonFactory
{
    <@keyword>virtual</@keyword> std<@op>::</@op>optional<@op>&lt;</@op>T<@op>&gt;</@op> fromJson(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) <@keyword>const</@keyword> <@op>=</@op> <@number>0</@number>;
    <@keyword>virtual</@keyword> <@op>~</@op>FromJsonFactory() <@op>=</@op> <@keyword>default</@keyword>;
};

<@keyword>struct</@keyword> User : <@keyword>public</@keyword> Jsonable<@op>,</@op> <@keyword>public</@keyword> Updatable
{
    <@type>qint64</@type> id;
    <@type>QString</@type> email;
    <@type>QString</@type> firstName;
    <@type>QString</@type> lastName;
    <@type>QUrl</@type> avatarUrl;
    <@type>QDateTime</@type> createdAt;
    <@type>QDateTime</@type> updatedAt;

    <@keyword>explicit</@keyword> User(<@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>email<@op>,</@op> <@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>firstName<@op>,</@op> <@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>lastName<@op>,</@op>
                  <@keyword>const</@keyword> <@type>QUrl</@type> <@op>&amp;</@op>avatarUrl<@op>,</@op>
                  <@keyword>const</@keyword> <@type>QDateTime</@type> <@op>&amp;</@op>createdAt <@op>=</@op> <@type>QDateTime</@type><@op>::</@op>currentDateTimeUtc()<@op>,</@op>
                  <@keyword>const</@keyword> <@type>QDateTime</@type> <@op>&amp;</@op>updatedAt <@op>=</@op> <@type>QDateTime</@type><@op>::</@op>currentDateTimeUtc())
        : id(nextId())<@op>,</@op>
          email(email)<@op>,</@op>
          firstName(firstName)<@op>,</@op>
          lastName(lastName)<@op>,</@op>
          avatarUrl(avatarUrl)<@op>,</@op>
          createdAt(createdAt)<@op>,</@op>
          updatedAt(updatedAt)
    {
    }

    <@type>bool</@type> update(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) override
    {
        <@keyword>if</@keyword> (<@op>!</@op>json<@op>.</@op>contains(<@string>&quot;email&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;first_name&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;last_name&quot;</@string>)
            <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;avatar&quot;</@string>))
            <@keyword>return</@keyword> <@keyword>false</@keyword>;

        email <@op>=</@op> json<@op>.</@op>value(<@string>&quot;email&quot;</@string>)<@op>.</@op>toString();
        firstName <@op>=</@op> json<@op>.</@op>value(<@string>&quot;first_name&quot;</@string>)<@op>.</@op>toString();
        lastName <@op>=</@op> json<@op>.</@op>value(<@string>&quot;last_name&quot;</@string>)<@op>.</@op>toString();
        avatarUrl<@op>.</@op>setPath(json<@op>.</@op>value(<@string>&quot;avatar&quot;</@string>)<@op>.</@op>toString());
        updateTimestamp();
        <@keyword>return</@keyword> <@keyword>true</@keyword>;
    }

    <@type>void</@type> updateFields(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) override
    {
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;email&quot;</@string>))
            email <@op>=</@op> json<@op>.</@op>value(<@string>&quot;email&quot;</@string>)<@op>.</@op>toString();
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;first_name&quot;</@string>))
            firstName <@op>=</@op> json<@op>.</@op>value(<@string>&quot;first_name&quot;</@string>)<@op>.</@op>toString();
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;last_name&quot;</@string>))
            lastName <@op>=</@op> json<@op>.</@op>value(<@string>&quot;last_name&quot;</@string>)<@op>.</@op>toString();
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;avatar&quot;</@string>))
            avatarUrl<@op>.</@op>setPath(json<@op>.</@op>value(<@string>&quot;avatar&quot;</@string>)<@op>.</@op>toString());
        updateTimestamp();
    }

    <@type>QJsonObject</@type> toJson() <@keyword>const</@keyword> override
    {
        <@keyword>return</@keyword> <@type>QJsonObject</@type>{ { <@string>&quot;id&quot;</@string><@op>,</@op> id }<@op>,</@op>
                            { <@string>&quot;email&quot;</@string><@op>,</@op> email }<@op>,</@op>
                            { <@string>&quot;first_name&quot;</@string><@op>,</@op> firstName }<@op>,</@op>
                            { <@string>&quot;last_name&quot;</@string><@op>,</@op> lastName }<@op>,</@op>
                            { <@string>&quot;avatar&quot;</@string><@op>,</@op> avatarUrl<@op>.</@op>toString() }<@op>,</@op>
                            { <@string>&quot;createdAt&quot;</@string><@op>,</@op> createdAt<@op>.</@op>toString(<@type>Qt</@type><@op>::</@op>ISODateWithMs) }<@op>,</@op>
                            { <@string>&quot;updatedAt&quot;</@string><@op>,</@op> updatedAt<@op>.</@op>toString(<@type>Qt</@type><@op>::</@op>ISODateWithMs) } };
    }

<@keyword>private</@keyword>:
    <@type>void</@type> updateTimestamp() { updatedAt <@op>=</@op> <@type>QDateTime</@type><@op>::</@op>currentDateTimeUtc(); }

    <@keyword>static</@keyword> <@type>qint64</@type> nextId()
    {
        <@keyword>static</@keyword> <@type>qint64</@type> lastId <@op>=</@op> <@number>1</@number>;
        <@keyword>return</@keyword> lastId<@op>+</@op><@op>+</@op>;
    }
};

<@keyword>struct</@keyword> UserFactory : <@keyword>public</@keyword> FromJsonFactory<@op>&lt;</@op>User<@op>&gt;</@op>
{
    UserFactory(<@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>scheme<@op>,</@op> <@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>hostName<@op>,</@op> <@type>int</@type> port)
        : scheme(scheme)<@op>,</@op> hostName(hostName)<@op>,</@op> port(port)
    {
    }

    std<@op>::</@op>optional<@op>&lt;</@op>User<@op>&gt;</@op> fromJson(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) <@keyword>const</@keyword> override
    {
        <@keyword>if</@keyword> (<@op>!</@op>json<@op>.</@op>contains(<@string>&quot;email&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;first_name&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;last_name&quot;</@string>)
            <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;avatar&quot;</@string>)) {
            <@keyword>return</@keyword> std<@op>::</@op>nullopt;
        }

        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;createdAt&quot;</@string>) <@op>&amp;</@op><@op>&amp;</@op> json<@op>.</@op>contains(<@string>&quot;updatedAt&quot;</@string>)) {
            <@keyword>return</@keyword> User(
                    json<@op>.</@op>value(<@string>&quot;email&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> json<@op>.</@op>value(<@string>&quot;first_name&quot;</@string>)<@op>.</@op>toString()<@op>,</@op>
                    json<@op>.</@op>value(<@string>&quot;last_name&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> json<@op>.</@op>value(<@string>&quot;avatar&quot;</@string>)<@op>.</@op>toString()<@op>,</@op>
                    <@type>QDateTime</@type><@op>::</@op>fromString(json<@op>.</@op>value(<@string>&quot;createdAt&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> <@type>Qt</@type><@op>::</@op>ISODateWithMs)<@op>,</@op>
                    <@type>QDateTime</@type><@op>::</@op>fromString(json<@op>.</@op>value(<@string>&quot;updatedAt&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> <@type>Qt</@type><@op>::</@op>ISODateWithMs));
        }
        <@type>QUrl</@type> avatarUrl(json<@op>.</@op>value(<@string>&quot;avatar&quot;</@string>)<@op>.</@op>toString());
        <@keyword>if</@keyword> (<@op>!</@op>avatarUrl<@op>.</@op>isValid()) {
            avatarUrl<@op>.</@op>setPath(json<@op>.</@op>value(<@string>&quot;avatar&quot;</@string>)<@op>.</@op>toString());
        }
        avatarUrl<@op>.</@op>setScheme(scheme);
        avatarUrl<@op>.</@op>setHost(hostName);
        avatarUrl<@op>.</@op>setPort(port);

        <@keyword>return</@keyword> User(json<@op>.</@op>value(<@string>&quot;email&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> json<@op>.</@op>value(<@string>&quot;first_name&quot;</@string>)<@op>.</@op>toString()<@op>,</@op>
                    json<@op>.</@op>value(<@string>&quot;last_name&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> avatarUrl);
    }

<@keyword>private</@keyword>:
    <@type>QString</@type> scheme;
    <@type>QString</@type> hostName;
    <@type>int</@type> port;
};

<@keyword>struct</@keyword> Color : <@keyword>public</@keyword> Jsonable<@op>,</@op> <@keyword>public</@keyword> Updatable
{
    <@type>qint64</@type> id;
    <@type>QString</@type> name;
    <@type>QColor</@type> color;
    <@type>QString</@type> pantone;
    <@type>QDateTime</@type> createdAt;
    <@type>QDateTime</@type> updatedAt;

    <@keyword>explicit</@keyword> Color(<@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>name<@op>,</@op> <@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>color<@op>,</@op> <@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>pantone<@op>,</@op>
                   <@keyword>const</@keyword> <@type>QDateTime</@type> <@op>&amp;</@op>createdAt <@op>=</@op> <@type>QDateTime</@type><@op>::</@op>currentDateTimeUtc()<@op>,</@op>
                   <@keyword>const</@keyword> <@type>QDateTime</@type> <@op>&amp;</@op>updatedAt <@op>=</@op> <@type>QDateTime</@type><@op>::</@op>currentDateTimeUtc())
        : id(nextId())<@op>,</@op>
          name(name)<@op>,</@op>
          color(<@type>QColor</@type>(color))<@op>,</@op>
          pantone(pantone)<@op>,</@op>
          createdAt(createdAt)<@op>,</@op>
          updatedAt(updatedAt)
    {
    }

    <@type>QJsonObject</@type> toJson() <@keyword>const</@keyword> override
    {
        <@keyword>return</@keyword> <@type>QJsonObject</@type>{ { <@string>&quot;id&quot;</@string><@op>,</@op> id }<@op>,</@op>
                            { <@string>&quot;name&quot;</@string><@op>,</@op> name }<@op>,</@op>
                            { <@string>&quot;color&quot;</@string><@op>,</@op> color<@op>.</@op>name() }<@op>,</@op>
                            { <@string>&quot;pantone_value&quot;</@string><@op>,</@op> pantone }<@op>,</@op>
                            { <@string>&quot;createdAt&quot;</@string><@op>,</@op> createdAt<@op>.</@op>toString(<@type>Qt</@type><@op>::</@op>ISODateWithMs) }<@op>,</@op>
                            { <@string>&quot;updatedAt&quot;</@string><@op>,</@op> updatedAt<@op>.</@op>toString(<@type>Qt</@type><@op>::</@op>ISODateWithMs) } };
    }

    <@type>bool</@type> update(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) override
    {
        <@keyword>if</@keyword> (<@op>!</@op>json<@op>.</@op>contains(<@string>&quot;name&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;color&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;pantone_value&quot;</@string>))
            <@keyword>return</@keyword> <@keyword>false</@keyword>;

        name <@op>=</@op> json<@op>.</@op>value(<@string>&quot;name&quot;</@string>)<@op>.</@op>toString();
        color <@op>=</@op> <@type>QColor</@type>(json<@op>.</@op>value(<@string>&quot;color&quot;</@string>)<@op>.</@op>toString());
        pantone <@op>=</@op> json<@op>.</@op>value(<@string>&quot;pantone_value&quot;</@string>)<@op>.</@op>toString();
        updateTimestamp();
        <@keyword>return</@keyword> <@keyword>true</@keyword>;
    }

    <@type>void</@type> updateFields(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) override
    {
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;name&quot;</@string>))
            name <@op>=</@op> json<@op>.</@op>value(<@string>&quot;name&quot;</@string>)<@op>.</@op>toString();
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;color&quot;</@string>))
            color <@op>=</@op> <@type>QColor</@type>(json<@op>.</@op>value(<@string>&quot;color&quot;</@string>)<@op>.</@op>toString());
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;pantone_value&quot;</@string>))
            pantone <@op>=</@op> json<@op>.</@op>value(<@string>&quot;pantone_value&quot;</@string>)<@op>.</@op>toString();
        updateTimestamp();
    }

<@keyword>private</@keyword>:
    <@type>void</@type> updateTimestamp() { updatedAt <@op>=</@op> <@type>QDateTime</@type><@op>::</@op>currentDateTimeUtc(); }

    <@keyword>static</@keyword> <@type>qint64</@type> nextId()
    {
        <@keyword>static</@keyword> <@type>qint64</@type> lastId <@op>=</@op> <@number>1</@number>;
        <@keyword>return</@keyword> lastId<@op>+</@op><@op>+</@op>;
    }
};

<@keyword>struct</@keyword> ColorFactory : <@keyword>public</@keyword> FromJsonFactory<@op>&lt;</@op>Color<@op>&gt;</@op>
{
    std<@op>::</@op>optional<@op>&lt;</@op>Color<@op>&gt;</@op> fromJson(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) <@keyword>const</@keyword> override
    {
        <@keyword>if</@keyword> (<@op>!</@op>json<@op>.</@op>contains(<@string>&quot;name&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;color&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;pantone_value&quot;</@string>))
            <@keyword>return</@keyword> std<@op>::</@op>nullopt;
        <@keyword>if</@keyword> (json<@op>.</@op>contains(<@string>&quot;createdAt&quot;</@string>) <@op>&amp;</@op><@op>&amp;</@op> json<@op>.</@op>contains(<@string>&quot;updatedAt&quot;</@string>)) {
            <@keyword>return</@keyword> Color(
                    json<@op>.</@op>value(<@string>&quot;name&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> json<@op>.</@op>value(<@string>&quot;color&quot;</@string>)<@op>.</@op>toString()<@op>,</@op>
                    json<@op>.</@op>value(<@string>&quot;pantone_value&quot;</@string>)<@op>.</@op>toString()<@op>,</@op>
                    <@type>QDateTime</@type><@op>::</@op>fromString(json<@op>.</@op>value(<@string>&quot;createdAt&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> <@type>Qt</@type><@op>::</@op>ISODateWithMs)<@op>,</@op>
                    <@type>QDateTime</@type><@op>::</@op>fromString(json<@op>.</@op>value(<@string>&quot;updatedAt&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> <@type>Qt</@type><@op>::</@op>ISODateWithMs));
        }
        <@keyword>return</@keyword> Color(json<@op>.</@op>value(<@string>&quot;name&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> json<@op>.</@op>value(<@string>&quot;color&quot;</@string>)<@op>.</@op>toString()<@op>,</@op>
                     json<@op>.</@op>value(<@string>&quot;pantone_value&quot;</@string>)<@op>.</@op>toString());
    }
};

<@keyword>struct</@keyword> SessionEntry : <@keyword>public</@keyword> Jsonable
{
    <@type>qint64</@type> id;
    <@type>QString</@type> email;
    <@type>QString</@type> password;
    std<@op>::</@op>optional<@op>&lt;</@op><@type>QUuid</@type><@op>&gt;</@op> token;

    <@keyword>explicit</@keyword> SessionEntry(<@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>email<@op>,</@op> <@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>password)
        : id(nextId())<@op>,</@op> email(email)<@op>,</@op> password(password)
    {
    }

    <@type>void</@type> startSession() { token <@op>=</@op> generateToken(); }

    <@type>void</@type> endSession() { token <@op>=</@op> std<@op>::</@op>nullopt; }

    <@type>QJsonObject</@type> toJson() <@keyword>const</@keyword> override
    {
        <@keyword>return</@keyword> token
                <@op>?</@op> <@type>QJsonObject</@type>{ { <@string>&quot;id&quot;</@string><@op>,</@op> id }<@op>,</@op>
                               { <@string>&quot;token&quot;</@string><@op>,</@op> token<@op>-</@op><@op>&gt;</@op>toString(<@type>QUuid</@type><@op>::</@op>StringFormat<@op>::</@op>WithoutBraces) } }
                : <@type>QJsonObject</@type>{};
    }

    <@type>bool</@type> <@keyword>operator</@keyword><@op>=</@op><@op>=</@op>(<@keyword>const</@keyword> <@type>QString</@type> <@op>&amp;</@op>otherToken) <@keyword>const</@keyword>
    {
        <@keyword>return</@keyword> token <@op>&amp;</@op><@op>&amp;</@op> <@op>*</@op>token <@op>=</@op><@op>=</@op> <@type>QUuid</@type><@op>::</@op>fromString(otherToken);
    }

<@keyword>private</@keyword>:
    <@type>QUuid</@type> generateToken() { <@keyword>return</@keyword> <@type>QUuid</@type><@op>::</@op>createUuid(); }

    <@keyword>static</@keyword> <@type>qint64</@type> nextId()
    {
        <@keyword>static</@keyword> <@type>qint64</@type> lastId <@op>=</@op> <@number>1</@number>;
        <@keyword>return</@keyword> lastId<@op>+</@op><@op>+</@op>;
    }
};

<@keyword>struct</@keyword> SessionEntryFactory : <@keyword>public</@keyword> FromJsonFactory<@op>&lt;</@op>SessionEntry<@op>&gt;</@op>
{
    std<@op>::</@op>optional<@op>&lt;</@op>SessionEntry<@op>&gt;</@op> fromJson(<@keyword>const</@keyword> <@type>QJsonObject</@type> <@op>&amp;</@op>json) <@keyword>const</@keyword> override
    {
        <@keyword>if</@keyword> (<@op>!</@op>json<@op>.</@op>contains(<@string>&quot;email&quot;</@string>) <@op>|</@op><@op>|</@op> <@op>!</@op>json<@op>.</@op>contains(<@string>&quot;password&quot;</@string>))
            <@keyword>return</@keyword> std<@op>::</@op>nullopt;

        <@keyword>return</@keyword> SessionEntry(json<@op>.</@op>value(<@string>&quot;email&quot;</@string>)<@op>.</@op>toString()<@op>,</@op> json<@op>.</@op>value(<@string>&quot;password&quot;</@string>)<@op>.</@op>toString());
    }
};

<@keyword>template</@keyword><@op>&lt;</@op><@keyword>typename</@keyword> T<@op>&gt;</@op>
<@keyword>class</@keyword> IdMap : <@keyword>public</@keyword> <@type>QMap</@type><@op>&lt;</@op><@type>qint64</@type><@op>,</@op> T<@op>&gt;</@op>
{
<@keyword>public</@keyword>:
    IdMap() <@op>=</@op> <@keyword>default</@keyword>;
    <@keyword>explicit</@keyword> IdMap(<@keyword>const</@keyword> FromJsonFactory<@op>&lt;</@op>T<@op>&gt;</@op> <@op>&amp;</@op>factory<@op>,</@op> <@keyword>const</@keyword> <@type>QJsonArray</@type> <@op>&amp;</@op>array) : <@type>QMap</@type><@op>&lt;</@op><@type>qint64</@type><@op>,</@op> T<@op>&gt;</@op>()
    {
        <@keyword>for</@keyword> (<@keyword>const</@keyword> <@keyword>auto</@keyword> <@op>&amp;</@op>jsonValue : array) {
            <@keyword>if</@keyword> (jsonValue<@op>.</@op>isObject()) {
                <@keyword>const</@keyword> <@keyword>auto</@keyword> maybeT <@op>=</@op> factory<@op>.</@op>fromJson(jsonValue<@op>.</@op>toObject());
                <@keyword>if</@keyword> (maybeT) {
                    <@type>QMap</@type><@op>&lt;</@op><@type>qint64</@type><@op>,</@op> T<@op>&gt;</@op><@op>::</@op>insert(maybeT<@op>-</@op><@op>&gt;</@op>id<@op>,</@op> <@op>*</@op>maybeT);
                }
            }
        }
    }
};

<@keyword>template</@keyword><@op>&lt;</@op><@keyword>typename</@keyword> T<@op>&gt;</@op>
<@keyword>class</@keyword> Paginator : <@keyword>public</@keyword> Jsonable
{
<@keyword>public</@keyword>:
    <@keyword>static</@keyword> constexpr qsizetype defaultPage <@op>=</@op> <@number>1</@number>;
    <@keyword>static</@keyword> constexpr qsizetype defaultPageSize <@op>=</@op> <@number>6</@number>;

    <@keyword>explicit</@keyword> Paginator(<@keyword>const</@keyword> T <@op>&amp;</@op>container<@op>,</@op> qsizetype page<@op>,</@op> qsizetype size)
    {
        <@keyword>const</@keyword> <@keyword>auto</@keyword> containerSize <@op>=</@op> container<@op>.</@op>size();
        <@keyword>const</@keyword> <@keyword>auto</@keyword> pageIndex <@op>=</@op> page <@op>-</@op> <@number>1</@number>;
        <@keyword>const</@keyword> <@keyword>auto</@keyword> pageSize <@op>=</@op> <@func target="qMin()">qMin</@func>(size<@op>,</@op> containerSize);
        <@keyword>const</@keyword> <@keyword>auto</@keyword> totalPages <@op>=</@op> (containerSize <@op>%</@op> pageSize) <@op>=</@op><@op>=</@op> <@number>0</@number> <@op>?</@op> (containerSize <@op>/</@op> pageSize)
                                                                : (containerSize <@op>/</@op> pageSize) <@op>+</@op> <@number>1</@number>;
        valid <@op>=</@op> containerSize <@op>&gt;</@op> (pageIndex <@op>*</@op> pageSize);
        <@keyword>if</@keyword> (valid) {
            <@type>QJsonArray</@type> data;

            <@keyword>auto</@keyword> iter <@op>=</@op> container<@op>.</@op>begin();
            std<@op>::</@op>advance(iter<@op>,</@op> std<@op>::</@op>min(pageIndex <@op>*</@op> pageSize<@op>,</@op> containerSize));
            <@keyword>for</@keyword> (qsizetype i <@op>=</@op> <@number>0</@number>; i <@op>&lt;</@op> pageSize <@op>&amp;</@op><@op>&amp;</@op> iter <@op>!</@op><@op>=</@op> container<@op>.</@op>end(); <@op>+</@op><@op>+</@op>i<@op>,</@op> <@op>+</@op><@op>+</@op>iter) {
                data<@op>.</@op>push_back(iter<@op>-</@op><@op>&gt;</@op>toJson());
            }
            json <@op>=</@op> <@type>QJsonObject</@type>{ { <@string>&quot;page&quot;</@string><@op>,</@op> pageIndex <@op>+</@op> <@number>1</@number> }<@op>,</@op>
                                { <@string>&quot;per_page&quot;</@string><@op>,</@op> pageSize }<@op>,</@op>
                                { <@string>&quot;total&quot;</@string><@op>,</@op> containerSize }<@op>,</@op>
                                { <@string>&quot;total_pages&quot;</@string><@op>,</@op> totalPages }<@op>,</@op>
                                { <@string>&quot;data&quot;</@string><@op>,</@op> data } };
        } <@keyword>else</@keyword> {
            json <@op>=</@op> <@type>QJsonObject</@type>{};
        }
    }

    <@type>QJsonObject</@type> toJson() <@keyword>const</@keyword> { <@keyword>return</@keyword> json; }

    constexpr <@type>bool</@type> isValid() <@keyword>const</@keyword> { <@keyword>return</@keyword> valid; }

<@keyword>private</@keyword>:
    <@type>QJsonObject</@type> json;
    <@type>bool</@type> valid;
};

<@preprocessor>#endif // TYPES_H</@preprocessor>