From 3f6d641239fcac14ec97f95cd557039bba95f185 Mon Sep 17 00:00:00 2001 From: silverqx Date: Fri, 16 Aug 2024 18:08:32 +0200 Subject: [PATCH] Deploy website - based on 0ec398e7b39696d432c506bf81cb85fafadb5cf4 --- 404.html | 2 +- assets/js/{3dd307b5.7f7edc87.js => 3dd307b5.dc00c88e.js} | 2 +- .../js/{runtime~main.2fc83ba1.js => runtime~main.fa672130.js} | 2 +- building/hello-world.html | 2 +- building/migrations.html | 2 +- building/tinyorm.html | 2 +- database/getting-started.html | 2 +- database/migrations.html | 2 +- database/query-builder.html | 2 +- database/seeding.html | 2 +- dependencies.html | 2 +- features-summary.html | 2 +- index.html | 2 +- search.html | 2 +- sponsors.html | 2 +- stability.html | 2 +- supported-compilers.html | 2 +- tinydrivers/getting-started.html | 2 +- tinyorm/casts.html | 2 +- tinyorm/collections.html | 4 ++-- tinyorm/getting-started.html | 2 +- tinyorm/relationships.html | 2 +- tinyorm/serialization.html | 2 +- 23 files changed, 24 insertions(+), 24 deletions(-) rename assets/js/{3dd307b5.7f7edc87.js => 3dd307b5.dc00c88e.js} (97%) rename assets/js/{runtime~main.2fc83ba1.js => runtime~main.fa672130.js} (98%) diff --git a/404.html b/404.html index 0cbbaf40b..05f5f9a60 100644 --- a/404.html +++ b/404.html @@ -14,7 +14,7 @@ - + diff --git a/assets/js/3dd307b5.7f7edc87.js b/assets/js/3dd307b5.dc00c88e.js similarity index 97% rename from assets/js/3dd307b5.7f7edc87.js rename to assets/js/3dd307b5.dc00c88e.js index 8e720b0b2..97ccf800c 100644 --- a/assets/js/3dd307b5.7f7edc87.js +++ b/assets/js/3dd307b5.dc00c88e.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[117],{4251:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>l,metadata:()=>d,toc:()=>a});var s=t(4848),o=t(8453),r=t(8774);const l={sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},i="TinyORM: Collections",d={id:"tinyorm/collections",title:"TinyORM: Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",source:"@site/docs/tinyorm/collections.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/collections",permalink:"/tinyorm/collections",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Relationships",permalink:"/tinyorm/relationships"},next:{title:"Casts",permalink:"/tinyorm/casts"}},c={},a=[{value:"Introduction",id:"introduction",level:2},{value:"Collection Conversion",id:"collection-conversion",level:4},{value:"Creating Collections",id:"creating-collections",level:3},{value:"Available Methods",id:"available-methods",level:2},{value:"all()",id:"method-all",level:4},{value:"contains()",id:"method-contains",level:4},{value:"doesntContain()",id:"method-doesntcontain",level:4},{value:"each()",id:"method-each",level:4},{value:"except()",id:"method-except",level:4},{value:"filter()",id:"method-filter",level:4},{value:"find()",id:"method-find",level:4},{value:"first()",id:"method-first",level:4},{value:"firstWhere()",id:"method-first-where",level:4},{value:"fresh()",id:"method-fresh",level:4},{value:"implode()",id:"method-implode",level:4},{value:"isEmpty()",id:"method-isempty",level:4},{value:"isNotEmpty()",id:"method-isnotempty",level:4},{value:"last()",id:"method-last",level:4},{value:"load()",id:"method-load",level:4},{value:"map()",id:"method-map",level:4},{value:"mapWithKeys()",id:"method-mapwithkeys",level:4},{value:"mapWithModelKeys()",id:"method-mapwithmodelkeys",level:4},{value:"modelKeys()",id:"method-modelkeys",level:4},{value:"only()",id:"method-only",level:4},{value:"pluck()",id:"method-pluck",level:4},{value:"reject()",id:"method-reject",level:4},{value:"sort()",id:"method-sort",level:4},{value:"sortBy()",id:"method-sortby",level:4},{value:"sortByDesc()",id:"method-sortbydesc",level:4},{value:"sortDesc()",id:"method-sortdesc",level:4},{value:"stableSort()",id:"method-stablesort",level:4},{value:"stableSortBy()",id:"method-stablesortby",level:4},{value:"stableSortByDesc()",id:"method-stablesortbydesc",level:4},{value:"stableSortDesc()",id:"method-stablesortdesc",level:4},{value:"tap()",id:"method-tap",level:4},{value:"toBase()",id:"method-tobase",level:4},{value:"toJson()",id:"method-tojson",level:4},{value:"toJsonArray()",id:"method-tojsonarray",level:4},{value:"toJsonDocument()",id:"method-tojsondocument",level:4},{value:"toMap()",id:"method-tomap",level:4},{value:"toMapVariantList()",id:"method-tomapvariantlist",level:4},{value:"toQuery()",id:"method-toquery",level:4},{value:"toList()",id:"method-tolist",level:4},{value:"toListVariantList()",id:"method-tolistvariantlist",level:4},{value:"unique()",id:"method-unique",level:4},{value:"uniqueBy()",id:"method-uniqueby",level:4},{value:"uniqueRelaxed()",id:"method-uniquerelaxed",level:4},{value:"uniqueRelaxedBy()",id:"method-uniquerelaxedby",level:4},{value:"value()",id:"method-value",level:4},{value:"where()",id:"method-where",level:4},{value:"whereBetween()",id:"method-wherebetween",level:4},{value:"whereIn()",id:"method-wherein",level:4},{value:"whereNotBetween()",id:"method-wherenotbetween",level:4},{value:"whereNotIn()",id:"method-wherenotin",level:4},{value:"whereNotNull()",id:"method-wherenotnull",level:4},{value:"whereNull()",id:"method-wherenull",level:4}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"tinyorm-collections",children:"TinyORM: Collections"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#introduction",children:"Introduction"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#creating-collections",children:"Creating Collections"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#available-methods",children:"Available Methods"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsx)("div",{class:"api-stability alert alert--success",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(r.A,{to:"/stability#stability-indexes",children:(0,s.jsx)(n.strong,{children:"Stability: 2"})})," - Stable"]})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Types::ModelsCollection"})," is specialized container which provides a fluent, convenient wrapper for working with vector of models. All TinyORM methods that return more than one model result, will return instances of the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class, including results retrieved via the ",(0,s.jsx)(n.code,{children:"get"})," method or methods that return relationships like the ",(0,s.jsx)(n.code,{children:"getRelation"})," and ",(0,s.jsx)(n.code,{children:"getRelationValue"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class extends ",(0,s.jsx)(n.code,{children:"QList"}),", so it naturally inherits dozens of methods used to work with the underlying vector of TinyORM models. Be sure to review the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html",children:(0,s.jsx)(n.code,{children:"QList"})})," documentation to learn all about these helpful methods!"]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," template parameter can be declared only with the model type or a model type pointer, it also can't be ",(0,s.jsx)(n.code,{children:"const"})," and can't be a reference. It's constrained using the ",(0,s.jsx)(n.code,{children:"DerivedCollectionModel"})," concept."]})}),"\n",(0,s.jsxs)(n.p,{children:["You can iterate over the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," the same way as over the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nModelsCollection users = User::whereEq("active", true)->get();\n\nfor (const auto &user : users)\n qDebug() << user.getAttribute("name");\n'})}),"\n",(0,s.jsx)(n.p,{children:"However, as previously mentioned, collections are much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, we may remove all active users and then gather the first name of each remaining user:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto names = User::all().reject([](User *const user)\n{\n return user->getAttribute("active");\n})\n .pluck("name");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["As you can see, the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class allows you to chain its methods to perform fluent mapping and reducing of the underlying vector. In general, collections are immutable, meaning every ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," method returns an entirely new ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," instance."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is returning from the Models' methods like ",(0,s.jsx)(n.code,{children:"get"}),", ",(0,s.jsx)(n.code,{children:"all"}),", ",(0,s.jsx)(n.code,{children:"findMany"}),", ",(0,s.jsx)(n.code,{children:"chunk"}),"; the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is returning from the relationship-related methods as ",(0,s.jsx)(n.code,{children:"getRelation"})," and ",(0,s.jsx)(n.code,{children:"getRelationValue"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"collection-conversion",children:"Collection Conversion"}),"\n",(0,s.jsxs)(n.p,{children:["While most TinyORM collection methods return a new instance of ",(0,s.jsx)(n.code,{children:"ModelsCollection"}),", the ",(0,s.jsx)(n.code,{children:"modelKeys"}),", ",(0,s.jsx)(n.code,{children:"mapWithKeys"}),", and ",(0,s.jsx)(n.code,{children:"pluck"})," methods return a base QList or std unordered/map instances. Likewise, one of the ",(0,s.jsx)(n.code,{children:"map"})," methods overload returns the ",(0,s.jsx)(n.code,{children:"QList"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"creating-collections",children:"Creating Collections"}),"\n",(0,s.jsxs)(n.p,{children:["Creating a ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is as simple as:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n'})}),"\n",(0,s.jsxs)(n.p,{children:["You can also create a collection of pointers, eg. ",(0,s.jsx)(n.code,{children:"ModelsCollection"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection userPointers {\n &users[0], &users[1],\n};\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is implicitly convertible and assignable from the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'QList usersVector {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n\nModelsCollection users(usersVector);\nusers = usersVector;\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Alternatively, you can use the ",(0,s.jsx)(n.code,{children:"Orm::collect"})," helper function to create a ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," from the given attributes:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users = Orm::collect({\n {{"name", "Kate"}, {"added_on", QDateTime::currentDateTimeUtc()}},\n {{"name", "John"}, {"added_on", QDateTime({2023, 6, 1}, {13, 46, 15}, QTimeZone::UTC)}},\n});\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Orm::collect"})," function is ",(0,s.jsx)(n.strong,{children:"mandatory"})," if your attributes contain the ",(0,s.jsx)(n.code,{children:"QDateTime"})," instance, you can read more about this problem ",(0,s.jsx)(n.a,{href:"/tinyorm/getting-started#qdatetime-and-connection-name-problem",children:"here"}),"."]})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The results of ",(0,s.jsx)(n.a,{href:"/tinyorm/getting-started",children:"TinyORM"})," queries are always returned as ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," instances."]})}),"\n",(0,s.jsx)(n.h2,{id:"available-methods",children:"Available Methods"}),"\n",(0,s.jsxs)(n.p,{children:["For the majority of the remaining collection documentation, we'll discuss each method available on the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class. Remember, all of these methods may be chained to fluently manipulate the underlying vector."]}),"\n",(0,s.jsxs)(n.p,{children:["Furthermore, almost every method returns a new ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," instance, allowing you to preserve the original copy of the collection when necessary:"]}),"\n",(0,s.jsx)("div",{className:"collection-methods-list",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"#method-all",children:"all"}),"\n",(0,s.jsx)(n.a,{href:"#method-contains",children:"contains"}),"\n",(0,s.jsx)(n.a,{href:"#method-doesntcontain",children:"doesntContain"}),"\n",(0,s.jsx)(n.a,{href:"#method-each",children:"each"}),"\n",(0,s.jsx)(n.a,{href:"#method-except",children:"except"}),"\n",(0,s.jsx)(n.a,{href:"#method-filter",children:"filter"}),"\n",(0,s.jsx)(n.a,{href:"#method-find",children:"find"}),"\n",(0,s.jsx)(n.a,{href:"#method-first",children:"first"}),"\n",(0,s.jsx)(n.a,{href:"#method-first-where",children:"firstWhere"}),"\n",(0,s.jsx)(n.a,{href:"#method-fresh",children:"fresh"}),"\n",(0,s.jsx)(n.a,{href:"#method-implode",children:"implode"}),"\n",(0,s.jsx)(n.a,{href:"#method-isempty",children:"isEmpty"}),"\n",(0,s.jsx)(n.a,{href:"#method-isnotempty",children:"isNotEmpty"}),"\n",(0,s.jsx)(n.a,{href:"#method-last",children:"last"}),"\n",(0,s.jsx)(n.a,{href:"#method-load",children:"load"}),"\n",(0,s.jsx)(n.a,{href:"#method-map",children:"map"}),"\n",(0,s.jsx)(n.a,{href:"#method-mapwithkeys",children:"mapWithKeys"}),"\n",(0,s.jsx)(n.a,{href:"#method-mapwithmodelkeys",children:"mapWithModelKeys"}),"\n",(0,s.jsx)(n.a,{href:"#method-modelkeys",children:"modelKeys"}),"\n",(0,s.jsx)(n.a,{href:"#method-only",children:"only"}),"\n",(0,s.jsx)(n.a,{href:"#method-pluck",children:"pluck"}),"\n",(0,s.jsx)(n.a,{href:"#method-reject",children:"reject"}),"\n",(0,s.jsx)(n.a,{href:"#method-sort",children:"sort"}),"\n",(0,s.jsx)(n.a,{href:"#method-sortby",children:"sortBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-sortbydesc",children:"sortByDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-sortdesc",children:"sortDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesort",children:"stableSort"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesortby",children:"stableSortBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesortbydesc",children:"stableSortByDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesortdesc",children:"stableSortDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-tap",children:"tap"}),"\n",(0,s.jsx)(n.a,{href:"#method-tobase",children:"toBase"}),"\n",(0,s.jsx)(n.a,{href:"#method-tojson",children:"toJson"}),"\n",(0,s.jsx)(n.a,{href:"#method-tojsonarray",children:"toJsonArray"}),"\n",(0,s.jsx)(n.a,{href:"#method-tojsondocument",children:"toJsonDocument"}),"\n",(0,s.jsx)(n.a,{href:"#method-tomap",children:"toMap"}),"\n",(0,s.jsx)(n.a,{href:"#method-tomapvariantlist",children:"toMapVariantList"}),"\n",(0,s.jsx)(n.a,{href:"#method-toquery",children:"toQuery"}),"\n",(0,s.jsx)(n.a,{href:"#method-tolist",children:"toList"}),"\n",(0,s.jsx)(n.a,{href:"#method-tolistvariantlist",children:"toListVariantList"}),"\n",(0,s.jsx)(n.a,{href:"#method-unique",children:"unique"}),"\n",(0,s.jsx)(n.a,{href:"#method-uniqueby",children:"uniqueBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-uniquerelaxed",children:"uniqueRelaxed"}),"\n",(0,s.jsx)(n.a,{href:"#method-uniquerelaxedby",children:"uniqueRelaxedBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-value",children:"value"}),"\n",(0,s.jsx)(n.a,{href:"#method-where",children:"where"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherebetween",children:"whereBetween"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherein",children:"whereIn"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenotbetween",children:"whereNotBetween"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenotin",children:"whereNotIn"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenotnull",children:"whereNotNull"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenull",children:"whereNull"})]})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["For a better understanding of the following examples, many of the variable declarations below use actual types instead of the ",(0,s.jsx)(n.code,{children:"auto"})," keyword."]})}),"\n",(0,s.jsxs)("div",{className:"collection-methods",children:[(0,s.jsx)(n.h4,{id:"method-all",children:(0,s.jsx)(n.code,{children:"all()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"all"})," method returns a copy of the underlying vector represented by the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"QList = users.all();\n"})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#method-tobase",children:(0,s.jsx)(n.code,{children:"toBase"})})," is an alias to the ",(0,s.jsx)(n.code,{children:"all"})," method."]})}),(0,s.jsx)(n.h4,{id:"method-contains",children:(0,s.jsx)(n.code,{children:"contains()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"contains"})," method may be used to determine if a given model instance is contained by the collection. This method accepts a primary key or a model instance:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.contains(1);\n\nusers.contains(User::find(1));\n"})}),(0,s.jsxs)(n.p,{children:["Alternatively, you may pass a lambda expression to the ",(0,s.jsx)(n.code,{children:"contains"})," method to determine if a model exists in the collection matching a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.contains([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n"})}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"contains"}),", see the ",(0,s.jsx)(n.a,{href:"#method-doesntcontain",children:"doesntContain"})," method."]}),(0,s.jsx)(n.h4,{id:"method-doesntcontain",children:(0,s.jsx)(n.code,{children:"doesntContain()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"doesntContain"})," method determines whether the collection does not contain a given item. This method accepts a primary key or a model instance:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.doesntContain(1);\n\nusers.doesntContain(User::find(1));\n"})}),(0,s.jsxs)(n.p,{children:["Alternatively, you may pass a lambda expression to the ",(0,s.jsx)(n.code,{children:"doesntContain"})," method to determine if a model does not exist in the collection matching a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.doesntContain([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n"})}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"doesntContain"}),", see the ",(0,s.jsx)(n.a,{href:"#method-contains",children:"contains"})," method."]}),(0,s.jsx)(n.h4,{id:"method-each",children:(0,s.jsx)(n.code,{children:"each()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"each"})," method iterates over the models in the collection and passes each model to the lambda expression:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users = Post::whereEq("user_id", 1)->get();\n\nusers.each([](User *const user)\n{\n // ...\n});\n'})}),(0,s.jsxs)(n.p,{children:["If you would like to stop iterating through the models, you may return ",(0,s.jsx)(n.code,{children:"false"})," from your lambda expression:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.each([](User *const user)\n{\n if (/* condition */)\n return false;\n\n // Some logic\n\n return true;\n});\n"})}),(0,s.jsx)(n.p,{children:"You may also pass the lambda expression with two parameters, whereas the second one is an index:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.each([](User *const user, const std::size_t index)\n{\n // ...\n});\n"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"each"})," method returns an lvalue ",(0,s.jsx)(n.strong,{children:"reference"})," to the currently processed collection."]}),(0,s.jsxs)(n.p,{children:["It can be also called on ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," rvalues, it returns an rvalue reference in this case."]}),(0,s.jsx)(n.h4,{id:"method-except",children:(0,s.jsx)(n.code,{children:"except()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"except"})," method returns all of the models that do not have the given primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersResult = users.except({1, 2, 3});\n"})}),(0,s.jsxs)(n.p,{children:["All of the models are returned if the ",(0,s.jsx)(n.code,{children:"ids"})," argument is empty ",(0,s.jsx)(n.code,{children:"except({})"}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"except"}),", see the ",(0,s.jsx)(n.a,{href:"#method-only",children:"only"})," method."]}),(0,s.jsx)(n.h4,{id:"method-filter",children:(0,s.jsx)(n.code,{children:"filter()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"filter"})," method filters the collection using the lambda expression, keeping only those models that pass a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersBanned = users.filter([](const User *const user)\n{\n return user->getAttribute("is_banned");\n});\n'})}),(0,s.jsx)(n.p,{children:"You may also pass the lambda expression with two parameters, whereas the second one is an index:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersBanned = users.filter([](const User *const user,\n const std::size_t index)\n{\n return index < 10 && user->getAttribute("is_banned");\n});\n'})}),(0,s.jsxs)(n.p,{children:["If no lambda expression is supplied, all models of the collection that are equivalent to the ",(0,s.jsx)(n.code,{children:"nullptr"})," will be removed:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersRaw = User::findMany({1, 2});\nModelsCollection users {&usersRaw[0], nullptr, &usersRaw[1]};\n\nModelsCollection filtered = users.filter();\n\n// {1, 2}\n"})}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"filter"}),", see the ",(0,s.jsx)(n.a,{href:"#method-reject",children:"reject"})," method."]}),(0,s.jsx)(n.h4,{id:"method-find",children:(0,s.jsx)(n.code,{children:"find()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"find"})," method returns the model that has a primary key matching the given key:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"User *const user = users.find(1);\n"})}),(0,s.jsxs)(n.p,{children:["If you pass a model instance, ",(0,s.jsx)(n.code,{children:"find"})," will attempt to return a model matching the primary key:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"User *user = users.find(anotherUser);\n"})}),(0,s.jsxs)(n.p,{children:["The two overloads above also accept the second ",(0,s.jsx)(n.code,{children:"defaultModel"})," model argument, which will be returned if a model was not found in the collection, its default value is the ",(0,s.jsx)(n.code,{children:"nullptr"}),"."]}),(0,s.jsxs)(n.p,{children:["Alternatively, may pass more IDs and ",(0,s.jsx)(n.code,{children:"find"})," will return all models which have a primary key within the given unordered set:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersMany = users.find({1, 2});\n"})}),(0,s.jsxs)(n.p,{children:["This overload internally calls the ",(0,s.jsx)(n.a,{href:"#method-only",children:(0,s.jsx)(n.code,{children:"only"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-first",children:(0,s.jsx)(n.code,{children:"first()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"first"})," method returns the first model in the collection that passes a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute("votes") > 150;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n'})}),(0,s.jsxs)(n.p,{children:["If no model passes a given truth test then the value of the second ",(0,s.jsx)(n.code,{children:"defaultModel"})," argument will be returned, its default value is the ",(0,s.jsx)(n.code,{children:"nullptr"}),"."]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute("votes") > 500;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n'})}),(0,s.jsxs)(n.p,{children:["You can also call all ",(0,s.jsx)(n.code,{children:"first"})," overloads provided by the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#first",children:(0,s.jsx)(n.code,{children:"QList::first"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-first-where",children:(0,s.jsx)(n.code,{children:"firstWhere()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"firstWhere"})," method returns the first model in the collection with the given column / value pair:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection users {\n {{"name", "Leon"}, {"age", NullVariant::UShort()}},\n {{"name", "Jill"}, {"age", 14}},\n {{"name", "Jack"}, {"age", 23}},\n {{"name", "Jill"}, {"age", 84}},\n};\n\nauto user = users.firstWhereEq("name", "Linda");\n\n// {{"name", "Jill"}, {"age", 14}}\n'})}),(0,s.jsxs)(n.p,{children:["You may also call the ",(0,s.jsx)(n.code,{children:"firstWhere"})," method with a comparison operator:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'users.firstWhere("age", ">=", 18);\n\n// {{"name", "Jack"}, {"age", 23}}\n'})}),(0,s.jsx)(n.h4,{id:"method-fresh",children:(0,s.jsx)(n.code,{children:"fresh()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fresh"})," method retrieves a fresh instance of each model in the collection from the database. In addition, any specified relationships will be eager loaded:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersFresh = users.fresh();\n\nauto usersFresh = users.fresh("comments");\n\nauto usersFresh = users.fresh("posts:id,name");\n\nauto usersFresh = users.fresh({"comments", "posts:id,name"});\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"relations"})," argument format is the same as for TinyBuilder's ",(0,s.jsx)(n.a,{href:"/tinyorm/relationships#lazy-eager-loading",children:(0,s.jsx)(n.code,{children:"load"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-implode",children:(0,s.jsx)(n.code,{children:"implode()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"implode"}),' method joins attributes by the given column and the "glue" string you wish to place between the values:']}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n};\n\nproducts.implode("product", ", ");\n\n// {Desk, Chair}\n'})}),(0,s.jsx)(n.p,{children:'The default "glue" value is an empty string "".'}),(0,s.jsx)(n.h4,{id:"method-isempty",children:(0,s.jsx)(n.code,{children:"isEmpty()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"isEmpty"})," method returns ",(0,s.jsx)(n.code,{children:"true"})," if the collection is empty; otherwise, ",(0,s.jsx)(n.code,{children:"false"})," is returned:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection().isEmpty();\n\n// true\n"})}),(0,s.jsx)(n.h4,{id:"method-isnotempty",children:(0,s.jsx)(n.code,{children:"isNotEmpty()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"isNotEmpty"})," method returns ",(0,s.jsx)(n.code,{children:"true"})," if the collection is not empty; otherwise, ",(0,s.jsx)(n.code,{children:"false"})," is returned:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection().isNotEmpty();\n\n// false\n"})}),(0,s.jsx)(n.h4,{id:"method-last",children:(0,s.jsx)(n.code,{children:"last()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"last"})," method returns the last model in the collection that passes a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "Rose"}, {"votes", 350}},\n};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute("votes") < 300;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n'})}),(0,s.jsxs)(n.p,{children:["If no model passes a given truth test then the value of the second ",(0,s.jsx)(n.code,{children:"defaultModel"})," argument will be returned, its default value is the ",(0,s.jsx)(n.code,{children:"nullptr"}),"."]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute("votes") < 100;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n'})}),(0,s.jsxs)(n.p,{children:["You can also call all ",(0,s.jsx)(n.code,{children:"last"})," overloads provided by the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#last",children:(0,s.jsx)(n.code,{children:"QList::last"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-load",children:(0,s.jsx)(n.code,{children:"load()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"load"})," method eager loads the given relationships for all models in the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'users.load({"comments", "posts"});\n\nusers.load("comments.author");\n\nusers.load({{"comments"}, {"posts", [](auto &query)\n{\n query.whereEq("active", true);\n}}});\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"relations"})," argument format is the same as for TinyBuilder's ",(0,s.jsx)(n.a,{href:"/tinyorm/relationships#lazy-eager-loading",children:(0,s.jsx)(n.code,{children:"load"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-map",children:(0,s.jsx)(n.code,{children:"map()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"map"})," method iterates through the collection and passes a ",(0,s.jsx)(n.strong,{children:"copy"})," of each model to the given lambda expression. The lambda expression is free to modify the model and return it, thus forming a new collection of modified models:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto usersAdded = users.map([](User &&userCopy)\n{\n if (userCopy.getAttribute("name") == "John")\n userCopy["votes"] = userCopy.getAttribute("votes") + 1;\n\n return std::move(userCopy);\n});\n\n/*\n {\n {{"name", "John"}, {"price", 201}},\n {{"name", "Jack"}, {"price", 400}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["The second ",(0,s.jsx)(n.code,{children:"map"})," overload allows to return the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'QList usersAdded = users.map([](User &&userCopy)\n{\n const auto votesRef = userCopy["votes"];\n\n if (userCopy.getAttribute("name") == "John")\n votesRef = userCopy.getAttribute("votes") + 1;\n\n return votesRef->value();\n});\n\n// {201, 400}\n'})}),(0,s.jsxs)(n.p,{children:["Both overloads allow to pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,s.jsx)(n.code,{children:"std::size_t"})," type."]}),(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:["Like most other collection methods, ",(0,s.jsx)(n.code,{children:"map"})," returns a new collection instance; it does not modify the collection it is called on. If you want to modify the original collection in place, use the ",(0,s.jsx)(n.a,{href:"#method-each",children:(0,s.jsx)(n.code,{children:"each"})})," method."]})}),(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The model copy is passed to the lambda expression even if the ",(0,s.jsx)(n.code,{children:"map"})," iterates over a collection of model pointers ",(0,s.jsx)(n.code,{children:"ModelsCollection"}),". The models are dereferenced behind the scene."]})}),(0,s.jsx)(n.h4,{id:"method-mapwithkeys",children:(0,s.jsx)(n.code,{children:"mapWithKeys()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"mapWithKeys"})," method iterates through the collection and passes each model to the given lambda expression. It returns the ",(0,s.jsx)(n.code,{children:"std::unordered_map"})," and the lambda expression should return the ",(0,s.jsx)(n.code,{children:"std::pair"})," containing a single column / value pair:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 1}, {"name", "John"}, {"email", "john@example.com"}},\n {{"id", 2}, {"name", "Jill"}, {"email", "jill@example.com"}},\n};\n\nauto usersMap = users.mapWithKeys(\n [](User *const user) -> std::pair\n{\n return {user->getKeyCasted(), user->getAttribute("name")};\n});\n\n// {{1, \'John\'}, {2, \'Jill\'}}\n'})}),(0,s.jsx)(n.p,{children:"You can also map IDs to the model pointers:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"auto usersMap = users.mapWithKeys(\n [](User *const user) -> std::pair\n{\n return {user->getKeyCasted(), user};\n});\n"})}),(0,s.jsx)(n.h4,{id:"method-mapwithmodelkeys",children:(0,s.jsx)(n.code,{children:"mapWithModelKeys()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"mapWithModelKeys"})," maps the primary keys to the ",(0,s.jsx)(n.code,{children:"Model *"}),", it returns the ",(0,s.jsx)(n.code,{children:"std::unordered_map"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"auto usersMap = users.mapWithModelKeys();\n"})}),(0,s.jsx)(n.h4,{id:"method-modelkeys",children:(0,s.jsx)(n.code,{children:"modelKeys()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"modelKeys"})," method returns the primary keys for all models in the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 1}, {"name", "John"}},\n {{"id", 2}, {"name", "Jill"}},\n {{"id", 3}, {"name", "Kate"}},\n {{"id", 5}, {"name", "Rose"}},\n};\n\nusers.modelKeys(); // Returns QList\nusers.modelKeys();\n\n// {1, 2, 3, 5}\n'})}),(0,s.jsx)(n.h4,{id:"method-only",children:(0,s.jsx)(n.code,{children:"only()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"only"})," method returns all of the models that have the given primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersResult = users.only({1, 2, 3});\n"})}),(0,s.jsxs)(n.p,{children:["An empty collection is returned if the ",(0,s.jsx)(n.code,{children:"ids"})," argument is empty ",(0,s.jsx)(n.code,{children:"only({})"}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"only"}),", see the ",(0,s.jsx)(n.a,{href:"#method-except",children:"except"})," method."]}),(0,s.jsx)(n.h4,{id:"method-pluck",children:(0,s.jsx)(n.code,{children:"pluck()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"pluck"})," method retrieves all of the values for a given column, the following overload returns the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"id", 1}, {"name", "Desk"}},\n {{"id", 2}, {"name", "Chair"}},\n};\n\nauto plucked = products.pluck("name");\n\n// {Desk, Chair}\n'})}),(0,s.jsxs)(n.p,{children:["The second overload allows returning the custom type ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto plucked = products.pluck("name");\n'})}),(0,s.jsxs)(n.p,{children:["You may also specify how you wish the resulting collection to be keyed, this overload returns the ",(0,s.jsx)(n.code,{children:"std::map"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto plucked = products.pluck("name", "id");\n\n// {{1, "Desk"}, {2, "Chair"}}\n'})}),(0,s.jsx)(n.p,{children:"If duplicate keys exist, the last matching attribute will be inserted into the plucked collection:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection collection {\n {{"brand", "Tesla"}, {"color", "red"}},\n {{"brand", "Pagani"}, {"color", "white"}},\n {{"brand", "Tesla"}, {"color", "black"}},\n {{"brand", "Pagani"}, {"color", "orange"}},\n};\n\nauto plucked = collection.pluck("color", "brand");\n\n// {{\'Tesla\', \'black\'}, {\'Pagani\', \'orange"}}\n'})}),(0,s.jsx)(n.h4,{id:"method-reject",children:(0,s.jsx)(n.code,{children:"reject()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"reject"})," method filters the collection using the given lambda expression. The lambda should return ",(0,s.jsx)(n.code,{children:"true"})," if the model should be removed from the resulting collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersWithNote = users.reject([](const User *const user)\n{\n return user->getAttribute("note").isNull();\n});\n'})}),(0,s.jsxs)(n.p,{children:["You may also pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,s.jsx)(n.code,{children:"std::size_t"})," type."]}),(0,s.jsxs)(n.p,{children:["For the inverse of the ",(0,s.jsx)(n.code,{children:"reject"})," method, see the ",(0,s.jsx)(n.a,{href:"#method-filter",children:(0,s.jsx)(n.code,{children:"filter"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-sort",children:(0,s.jsx)(n.code,{children:"sort()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"sort"})," method sorts the models collection by primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sort();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["You may pass a predicate and projection callbacks to the ",(0,s.jsx)(n.code,{children:"sort"})," method with your own algorithms. Refer to the CPP reference documentation on ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/sort",children:(0,s.jsx)(n.code,{children:"ranges::sort"})}),", which is what the ",(0,s.jsx)(n.code,{children:"sort"})," method calls internally."]}),(0,s.jsxs)(n.p,{children:["You can eg. sort by multiple columns, for an alternative method of multi-column sorting look at ",(0,s.jsx)(n.a,{href:"#method-sortby",children:"sortBy"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sort([](const User *const left,\n const User *const right)\n{\n const auto leftValue = left->getAttribute("name");\n const auto rightValue = right->getAttribute("name");\n\n if (leftValue == rightValue)\n return left->getAttribute("votes") <\n right->getAttribute("votes");\n\n return leftValue < rightValue;\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 350}},\n }\n*/\n'})}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can use the ",(0,s.jsx)(n.a,{href:"#method-stablesort",children:"stable"})," sort method variants to preserve the order of equal models."]})}),(0,s.jsx)(n.h4,{id:"method-sortby",children:(0,s.jsx)(n.code,{children:"sortBy()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"sortBy"})," method sorts the collection by the given column, this overload needs the template argument so it can cast the attribute value before comparing:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto sorted = users.sortBy("name");\n\n/*\n {\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 150}},\n }\n*/\n'})}),(0,s.jsx)(n.p,{children:"You may pass the projection callback to determine how to sort the collection's models:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto sorted = users.sortBy([](User *const user)\n{\n return user->getAttribute("votes");\n});\n\n/*\n {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["If you would like to sort your collection by multiple columns, you may pass a vector of comparison lambda expressions that define each sort operation to the ",(0,s.jsx)(n.code,{children:"sortBy"})," method, in the following example is the ",(0,s.jsx)(n.code,{children:"name"})," column sorted in ascending order and the second ",(0,s.jsx)(n.code,{children:"votes"})," column is sorted in descending order:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using AttributeUtils = Orm::Tiny::Utils::Attribute;\n\nModelsCollection users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sortBy({\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortBy(\n left->getAttribute("name"),\n right->getAttribute("name"));\n },\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortByDesc(\n left->getAttribute("votes"),\n right->getAttribute("votes"));\n },\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "Kate"}, {"votes", 200}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"AttributeUtils::compareForSortBy"})," and ",(0,s.jsx)(n.code,{children:"compareForSortByDesc"})," methods are helper methods, they are needed because the Qt framework doesn't define ",(0,s.jsx)(n.code,{children:"<=>"})," spaceship operator on its types, it doesn't support the three-way comparison."]}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.h4,{id:"method-sortbydesc",children:(0,s.jsx)(n.code,{children:"sortByDesc()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortby",children:(0,s.jsx)(n.code,{children:"sortBy"})})," method but will sort the collection in the opposite order."]}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.h4,{id:"method-sortdesc",children:(0,s.jsx)(n.code,{children:"sortDesc()"})}),(0,s.jsxs)(n.p,{children:["This method will sort the collection in the opposite order as the ",(0,s.jsx)(n.a,{href:"#method-sort",children:(0,s.jsx)(n.code,{children:"sort"})})," method:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sortDesc();\n\n/*\n {\n {{"id", 3}, {"name", "John"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n }\n*/\n'})}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.h4,{id:"method-stablesort",children:(0,s.jsx)(n.code,{children:"stableSort()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sort",children:(0,s.jsx)(n.code,{children:"sort"})})," method but will preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-stablesortby",children:(0,s.jsx)(n.code,{children:"stableSortBy()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortby",children:(0,s.jsx)(n.code,{children:"sortBy"})})," method but will preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-stablesortbydesc",children:(0,s.jsx)(n.code,{children:"stableSortByDesc()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortbydesc",children:(0,s.jsx)(n.code,{children:"sortByDesc"})})," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-stablesortdesc",children:(0,s.jsx)(n.code,{children:"stableSortDesc()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortdesc",children:(0,s.jsx)(n.code,{children:"sortDesc"})})," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-tap",children:(0,s.jsx)(n.code,{children:"tap()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tap"}),' method passes a collection to the given lambda expression, allowing you to "tap" into the collection at a specific point and do something with the models while not affecting the collection itself:']}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nusers.sort()\n .tap([](/*const */ModelsCollection &usersRef)\n{\n qDebug() << "IDs after sorting:"\n << usersRef.template modelKeys();\n})\n .value("id");\n\n// 1\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tap"})," method returns an lvalue ",(0,s.jsx)(n.strong,{children:"reference"})," to the currently processed collection."]}),(0,s.jsxs)(n.p,{children:["It can be also called on ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," rvalues, it returns an rvalue reference in this case."]}),(0,s.jsx)(n.h4,{id:"method-tobase",children:(0,s.jsx)(n.code,{children:"toBase()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toBase"})," method returns a copy of the underlying vector represented by the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"QList = users.toBase();\n"})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#method-tobase",children:(0,s.jsx)(n.code,{children:"toBase"})})," is an alias to the ",(0,s.jsx)(n.code,{children:"all"})," method."]})}),(0,s.jsx)(n.h4,{id:"method-tojson",children:(0,s.jsx)(n.code,{children:"toJson()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJson"})," method converts the collection of models with all nested relations into a JSON serialized ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qbytearray.html",children:(0,s.jsx)(n.code,{children:"QByteArray"})}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty array for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and ",(0,s.jsx)(n.code,{children:"null"})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJson"})," method accepts the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html#JsonFormat-enum",children:(0,s.jsx)(n.code,{children:"QJsonDocument::JsonFormat"})}),", possible values are ",(0,s.jsx)(n.code,{children:"QJsonDocument::Indented"})," or ",(0,s.jsx)(n.code,{children:"QJsonDocument::Compact"}),"."]})}),(0,s.jsx)(n.h4,{id:"method-tojsonarray",children:(0,s.jsx)(n.code,{children:"toJsonArray()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJsonArray"})," method converts the collection of models with all nested relations into a ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsonarray.html",children:(0,s.jsx)(n.code,{children:"QJsonArray"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-tojsondocument",children:(0,s.jsx)(n.code,{children:"toJsonDocument()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJsonDocument"})," method converts the collection of models with all nested relations into a ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html",children:(0,s.jsx)(n.code,{children:"QJsonDocument"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-tomap",children:(0,s.jsx)(n.code,{children:"toMap()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toMap"})," method converts the collection of models with all nested relations into an attributes map ",(0,s.jsx)(n.code,{children:"QList"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.h4,{id:"method-tomapvariantlist",children:(0,s.jsx)(n.code,{children:"toMapVariantList()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toMapVariantList"})," method converts the collection of models with all nested relations into an attributes map, but it returns the ",(0,s.jsx)("abbr",{title:"QList",children:(0,s.jsx)(n.code,{children:"QVariantList"})})," instead of the ",(0,s.jsx)(n.code,{children:"QList"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toMapVariantList"})," method is internally needed by the ",(0,s.jsx)(n.code,{children:"toJson"})," related methods."]})}),(0,s.jsx)(n.h4,{id:"method-toquery",children:(0,s.jsx)(n.code,{children:"toQuery()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toQuery"})," method returns the ",(0,s.jsx)(n.code,{children:"TinyBuilder"})," instance containing a ",(0,s.jsx)(n.code,{children:"whereIn"})," constraint with the collection of models' primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nModelsCollection users = User::whereEq("status", "VIP")->get();\n\nusers.toQuery()->update({\n {"status", "Administrator"},\n});\n'})}),(0,s.jsx)(n.h4,{id:"method-tolist",children:(0,s.jsx)(n.code,{children:"toList()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toList"})," method converts the collection of models with all nested relations into an attributes vector ",(0,s.jsx)(n.code,{children:"QList>"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.h4,{id:"method-tolistvariantlist",children:(0,s.jsx)(n.code,{children:"toListVariantList()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toListVariantList"})," method converts the collection of models with all nested relations into an attributes vector, but it returns the ",(0,s.jsx)("abbr",{title:"QList",children:(0,s.jsx)(n.code,{children:"QVariantList"})})," instead of the ",(0,s.jsx)(n.code,{children:"QList>"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toListVariantList"})," method is internally needed by the ",(0,s.jsx)(n.code,{children:"toJson"})," related methods."]})}),(0,s.jsx)(n.h4,{id:"method-unique",children:(0,s.jsx)(n.code,{children:"unique()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"unique"})," method returns all of the unique models in the ",(0,s.jsx)(n.strong,{children:"sorted"})," collection. Any models with the same primary key as another model in the collection are removed:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.unique();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["It sorts the collection internally because the ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique",children:(0,s.jsx)(n.code,{children:"ranges::unique"})})," can correctly operate only on the sorted container. You can disable it by passing ",(0,s.jsx)(n.code,{children:"false"})," using the first ",(0,s.jsx)(n.code,{children:"sort"})," parameter:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto unique = users.sort().unique(false);\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-uniqueby",children:(0,s.jsx)(n.code,{children:"uniqueBy()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"uniqueBy"})," method returns all of the unique models in the ",(0,s.jsx)(n.strong,{children:"sorted"})," collection by the given column. Any models with the same column value as another model in the collection are removed. It needs the template argument, so it can cast the attribute value before comparing:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueBy("name");\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["It sorts the collection internally because the ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique",children:(0,s.jsx)(n.code,{children:"ranges::unique"})})," can correctly operate only on the sorted container. You can disable it by passing ",(0,s.jsx)(n.code,{children:"false"})," using the second ",(0,s.jsx)(n.code,{children:"sort"})," parameter:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto unique = users.sortBy("name")\n .uniqueBy("name", false);\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-uniquerelaxed",children:(0,s.jsx)(n.code,{children:"uniqueRelaxed()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"uniqueRelaxed"})," method returns all of the unique models in the collection, it doesn't need a sorted collection. Any models with the same primary key as another model in the collection are removed:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxed();\n\n/*\n {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-uniquerelaxedby",children:(0,s.jsx)(n.code,{children:"uniqueRelaxedBy()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"uniqueRelaxedBy"})," method returns all of the unique models in the collection by the given column, it doesn't need a sorted collection, but it needs the template argument, so it can cast the attribute value before comparing:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxedBy("name");\n\n/*\n {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-value",children:(0,s.jsx)(n.code,{children:"value()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"value"})," method retrieves a given value from the first model of the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nQVariant votes = users.value("votes");\n\n// 200\n'})}),(0,s.jsxs)(n.p,{children:["Alternatively, you can cast an obtained ",(0,s.jsx)(n.code,{children:"QVariant"})," value to the given type by the second ",(0,s.jsx)(n.code,{children:"value"})," overload:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'quint64 votes = users.value("votes");\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"value"})," method also accepts the second ",(0,s.jsx)(n.code,{children:"defaultValue"})," argument, which will be returned if a collection is empty, the first model is ",(0,s.jsx)(n.code,{children:"nullptr"}),", or a model doesn't contain the given column:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto votes = ModelsCollection().value("votes", 0);\n\n// 0\n'})}),(0,s.jsxs)(n.p,{children:["You can also call all ",(0,s.jsx)(n.code,{children:"value"})," overloads provided by the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#value",children:(0,s.jsx)(n.code,{children:"QList::value"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-where",children:(0,s.jsx)(n.code,{children:"where()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"where"})," method filters the collection by a given column / value pair:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.where("price", "=", 100);\n\n/*\n {\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["For convenience, if you want to verify that a column is ",(0,s.jsx)(n.code,{children:"="})," to a given value, you may call ",(0,s.jsx)(n.code,{children:"whereEq"})," method. Similar ",(0,s.jsx)(n.code,{children:"XxxEq"})," methods are also defined for other commands:"]}),(0,s.jsx)(n.p,{children:'auto filtered = products.whereEq("price", 100);'}),(0,s.jsxs)(n.p,{children:["Optionally, you may pass a comparison operator as the second argument.",(0,s.jsx)("br",{}),"Supported operators are ",(0,s.jsx)(n.code,{children:"="}),", ",(0,s.jsx)(n.code,{children:"!="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:"<="}),", and ",(0,s.jsx)(n.code,{children:">="}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.where("price", ">", 150);\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-wherebetween",children:(0,s.jsx)(n.code,{children:"whereBetween()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereBetween"})," method filters the collection by determining if a specified models' attribute value is within a given range:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereBetween("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-wherein",children:(0,s.jsx)(n.code,{children:"whereIn()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereIn"})," method filters models from the collection that have a specified attribute value that is contained within the given unordered set:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereIn("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["An empty collection is returned if the ",(0,s.jsx)(n.code,{children:"values"})," argument is empty ",(0,s.jsx)(n.code,{children:'whereIn("price", {})'}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsx)(n.h4,{id:"method-wherenotbetween",children:(0,s.jsx)(n.code,{children:"whereNotBetween()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNotBetween"})," method filters the collection by determining if a specified models' attribute value is outside of a given range:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereNotBetween("price", {100, 200});\n\n/*\n {\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Pencil"}, {"price", 30}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-wherenotin",children:(0,s.jsx)(n.code,{children:"whereNotIn()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNotIn"})," method removes models from the collection that have a specified attribute value that is contained within the given unordered set:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereNotIn("price", {100, 200});\n\n/*\n {\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["All of the models are returned if the ",(0,s.jsx)(n.code,{children:"values"})," argument is empty ",(0,s.jsx)(n.code,{children:'whereNotIn("price", {})'}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsx)(n.h4,{id:"method-wherenotnull",children:(0,s.jsx)(n.code,{children:"whereNotNull()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNotNull"})," method returns models from the collection where the given column is not ",(0,s.jsx)(n.code,{children:"null"})," QVariant:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n/*\n {\n {{"name", "John"}},\n {{"name", "Jack"}},\n }\n*/\n'})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"NullVariant"})," class returns the correct ",(0,s.jsx)(n.code,{children:"null"})," QVariant for both Qt 5 ",(0,s.jsx)(n.code,{children:"QVariant(QVariant::String)"})," and also Qt 6 ",(0,s.jsx)(n.code,{children:"QVariant(QMetaType(QMetaType::QString))"}),"."]})}),(0,s.jsx)(n.h4,{id:"method-wherenull",children:(0,s.jsx)(n.code,{children:"whereNull()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNull"})," method returns models from the collection where the given column is ",(0,s.jsx)(n.code,{children:"null"})," QVariant:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n// {{"name", NullVariant::QString()}}\n'})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"NullVariant"})," class returns the correct ",(0,s.jsx)(n.code,{children:"null"})," QVariant for both Qt 5 ",(0,s.jsx)(n.code,{children:"QVariant(QVariant::String)"})," and also Qt 6 ",(0,s.jsx)(n.code,{children:"QVariant(QMetaType(QMetaType::QString))"}),"."]})})]})]})}function u(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>i});var s=t(6540);const o={},r=s.createContext(o);function l(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:l(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[117],{4251:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>l,metadata:()=>d,toc:()=>a});var s=t(4848),o=t(8453),r=t(8774);const l={sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},i="TinyORM: Collections",d={id:"tinyorm/collections",title:"TinyORM: Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",source:"@site/docs/tinyorm/collections.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/collections",permalink:"/tinyorm/collections",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Relationships",permalink:"/tinyorm/relationships"},next:{title:"Casts",permalink:"/tinyorm/casts"}},c={},a=[{value:"Introduction",id:"introduction",level:2},{value:"Collection Conversion",id:"collection-conversion",level:4},{value:"Creating Collections",id:"creating-collections",level:3},{value:"Available Methods",id:"available-methods",level:2},{value:"all()",id:"method-all",level:4},{value:"contains()",id:"method-contains",level:4},{value:"doesntContain()",id:"method-doesntcontain",level:4},{value:"each()",id:"method-each",level:4},{value:"except()",id:"method-except",level:4},{value:"filter()",id:"method-filter",level:4},{value:"find()",id:"method-find",level:4},{value:"first()",id:"method-first",level:4},{value:"firstWhere()",id:"method-first-where",level:4},{value:"fresh()",id:"method-fresh",level:4},{value:"implode()",id:"method-implode",level:4},{value:"isEmpty()",id:"method-isempty",level:4},{value:"isNotEmpty()",id:"method-isnotempty",level:4},{value:"last()",id:"method-last",level:4},{value:"load()",id:"method-load",level:4},{value:"map()",id:"method-map",level:4},{value:"mapWithKeys()",id:"method-mapwithkeys",level:4},{value:"mapWithModelKeys()",id:"method-mapwithmodelkeys",level:4},{value:"modelKeys()",id:"method-modelkeys",level:4},{value:"only()",id:"method-only",level:4},{value:"pluck()",id:"method-pluck",level:4},{value:"reject()",id:"method-reject",level:4},{value:"sort()",id:"method-sort",level:4},{value:"sortBy()",id:"method-sortby",level:4},{value:"sortByDesc()",id:"method-sortbydesc",level:4},{value:"sortDesc()",id:"method-sortdesc",level:4},{value:"stableSort()",id:"method-stablesort",level:4},{value:"stableSortBy()",id:"method-stablesortby",level:4},{value:"stableSortByDesc()",id:"method-stablesortbydesc",level:4},{value:"stableSortDesc()",id:"method-stablesortdesc",level:4},{value:"tap()",id:"method-tap",level:4},{value:"toBase()",id:"method-tobase",level:4},{value:"toJson()",id:"method-tojson",level:4},{value:"toJsonArray()",id:"method-tojsonarray",level:4},{value:"toJsonDocument()",id:"method-tojsondocument",level:4},{value:"toMap()",id:"method-tomap",level:4},{value:"toMapVariantList()",id:"method-tomapvariantlist",level:4},{value:"toQuery()",id:"method-toquery",level:4},{value:"toList()",id:"method-tolist",level:4},{value:"toListVariantList()",id:"method-tolistvariantlist",level:4},{value:"unique()",id:"method-unique",level:4},{value:"uniqueBy()",id:"method-uniqueby",level:4},{value:"uniqueRelaxed()",id:"method-uniquerelaxed",level:4},{value:"uniqueRelaxedBy()",id:"method-uniquerelaxedby",level:4},{value:"value()",id:"method-value",level:4},{value:"where()",id:"method-where",level:4},{value:"whereBetween()",id:"method-wherebetween",level:4},{value:"whereIn()",id:"method-wherein",level:4},{value:"whereNotBetween()",id:"method-wherenotbetween",level:4},{value:"whereNotIn()",id:"method-wherenotin",level:4},{value:"whereNotNull()",id:"method-wherenotnull",level:4},{value:"whereNull()",id:"method-wherenull",level:4}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"tinyorm-collections",children:"TinyORM: Collections"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#introduction",children:"Introduction"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#creating-collections",children:"Creating Collections"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#available-methods",children:"Available Methods"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsx)("div",{class:"api-stability alert alert--success",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(r.A,{to:"/stability#stability-indexes",children:(0,s.jsx)(n.strong,{children:"Stability: 2"})})," - Stable"]})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Types::ModelsCollection"})," is specialized container which provides a fluent, convenient wrapper for working with vector of models. All TinyORM methods that return more than one model result, will return instances of the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class, including results retrieved via the ",(0,s.jsx)(n.code,{children:"get"})," method or methods that return relationships like the ",(0,s.jsx)(n.code,{children:"getRelation"})," and ",(0,s.jsx)(n.code,{children:"getRelationValue"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class extends ",(0,s.jsx)(n.code,{children:"QList"}),", so it naturally inherits dozens of methods used to work with the underlying vector of TinyORM models. Be sure to review the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html",children:(0,s.jsx)(n.code,{children:"QList"})})," documentation to learn all about these helpful methods!"]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," template parameter can be declared only with the model type or a model type pointer, it also can't be ",(0,s.jsx)(n.code,{children:"const"})," and can't be a reference. It's constrained using the ",(0,s.jsx)(n.code,{children:"DerivedCollectionModel"})," concept."]})}),"\n",(0,s.jsxs)(n.p,{children:["You can iterate over the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," the same way as over the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nModelsCollection users = User::whereEq("active", true)->get();\n\nfor (const auto &user : users)\n qDebug() << user.getAttribute("name");\n'})}),"\n",(0,s.jsx)(n.p,{children:"However, as previously mentioned, collections are much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, we may remove all active users and then gather the first name of each remaining user:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto names = User::all().reject([](User *const user)\n{\n return user->getAttribute("active");\n})\n .pluck("name");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["As you can see, the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class allows you to chain its methods to perform fluent mapping and reducing of the underlying vector. In general, collections are immutable, meaning every ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," method returns an entirely new ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," instance."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is returning from the Models' methods like ",(0,s.jsx)(n.code,{children:"get"}),", ",(0,s.jsx)(n.code,{children:"all"}),", ",(0,s.jsx)(n.code,{children:"findMany"}),", ",(0,s.jsx)(n.code,{children:"chunk"}),"; the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is returning from the relationship-related methods as ",(0,s.jsx)(n.code,{children:"getRelation"})," and ",(0,s.jsx)(n.code,{children:"getRelationValue"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"collection-conversion",children:"Collection Conversion"}),"\n",(0,s.jsxs)(n.p,{children:["While most TinyORM collection methods return a new instance of ",(0,s.jsx)(n.code,{children:"ModelsCollection"}),", the ",(0,s.jsx)(n.code,{children:"modelKeys"}),", ",(0,s.jsx)(n.code,{children:"mapWithKeys"}),", and ",(0,s.jsx)(n.code,{children:"pluck"})," methods return a base QList or std unordered/map instances. Likewise, one of the ",(0,s.jsx)(n.code,{children:"map"})," methods overload returns the ",(0,s.jsx)(n.code,{children:"QList"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"creating-collections",children:"Creating Collections"}),"\n",(0,s.jsxs)(n.p,{children:["Creating a ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is as simple as:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n'})}),"\n",(0,s.jsxs)(n.p,{children:["You can also create a collection of pointers, eg. ",(0,s.jsx)(n.code,{children:"ModelsCollection"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection userPointers {\n &users[0], &users[1],\n};\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," is implicitly convertible and assignable from the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'QList usersVector {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n\nModelsCollection users(usersVector);\nusers = usersVector;\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Alternatively, you can use the ",(0,s.jsx)(n.code,{children:"Orm::collect"})," helper function to create a ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," from the given attributes:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users = Orm::collect({\n {{"name", "Kate"}, {"added_on", QDateTime::currentDateTimeUtc()}},\n {{"name", "John"}, {"added_on", QDateTime({2023, 6, 1}, {13, 46, 15}, QTimeZone::UTC)}},\n});\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Orm::collect"})," function is ",(0,s.jsx)(n.strong,{children:"mandatory"})," if your attributes contain the ",(0,s.jsx)(n.code,{children:"QDateTime"})," instance, you can read more about this problem ",(0,s.jsx)(n.a,{href:"/tinyorm/getting-started#qdatetime-and-connection-name-problem",children:"here"}),"."]})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The results of ",(0,s.jsx)(n.a,{href:"/tinyorm/getting-started",children:"TinyORM"})," queries are always returned as ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," instances."]})}),"\n",(0,s.jsx)(n.h2,{id:"available-methods",children:"Available Methods"}),"\n",(0,s.jsxs)(n.p,{children:["For the majority of the remaining collection documentation, we'll discuss each method available on the ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," class. Remember, all of these methods may be chained to fluently manipulate the underlying vector."]}),"\n",(0,s.jsxs)(n.p,{children:["Furthermore, almost every method returns a new ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," instance, allowing you to preserve the original copy of the collection when necessary:"]}),"\n",(0,s.jsx)("div",{className:"collection-methods-list",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"#method-all",children:"all"}),"\n",(0,s.jsx)(n.a,{href:"#method-contains",children:"contains"}),"\n",(0,s.jsx)(n.a,{href:"#method-doesntcontain",children:"doesntContain"}),"\n",(0,s.jsx)(n.a,{href:"#method-each",children:"each"}),"\n",(0,s.jsx)(n.a,{href:"#method-except",children:"except"}),"\n",(0,s.jsx)(n.a,{href:"#method-filter",children:"filter"}),"\n",(0,s.jsx)(n.a,{href:"#method-find",children:"find"}),"\n",(0,s.jsx)(n.a,{href:"#method-first",children:"first"}),"\n",(0,s.jsx)(n.a,{href:"#method-first-where",children:"firstWhere"}),"\n",(0,s.jsx)(n.a,{href:"#method-fresh",children:"fresh"}),"\n",(0,s.jsx)(n.a,{href:"#method-implode",children:"implode"}),"\n",(0,s.jsx)(n.a,{href:"#method-isempty",children:"isEmpty"}),"\n",(0,s.jsx)(n.a,{href:"#method-isnotempty",children:"isNotEmpty"}),"\n",(0,s.jsx)(n.a,{href:"#method-last",children:"last"}),"\n",(0,s.jsx)(n.a,{href:"#method-load",children:"load"}),"\n",(0,s.jsx)(n.a,{href:"#method-map",children:"map"}),"\n",(0,s.jsx)(n.a,{href:"#method-mapwithkeys",children:"mapWithKeys"}),"\n",(0,s.jsx)(n.a,{href:"#method-mapwithmodelkeys",children:"mapWithModelKeys"}),"\n",(0,s.jsx)(n.a,{href:"#method-modelkeys",children:"modelKeys"}),"\n",(0,s.jsx)(n.a,{href:"#method-only",children:"only"}),"\n",(0,s.jsx)(n.a,{href:"#method-pluck",children:"pluck"}),"\n",(0,s.jsx)(n.a,{href:"#method-reject",children:"reject"}),"\n",(0,s.jsx)(n.a,{href:"#method-sort",children:"sort"}),"\n",(0,s.jsx)(n.a,{href:"#method-sortby",children:"sortBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-sortbydesc",children:"sortByDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-sortdesc",children:"sortDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesort",children:"stableSort"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesortby",children:"stableSortBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesortbydesc",children:"stableSortByDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-stablesortdesc",children:"stableSortDesc"}),"\n",(0,s.jsx)(n.a,{href:"#method-tap",children:"tap"}),"\n",(0,s.jsx)(n.a,{href:"#method-tobase",children:"toBase"}),"\n",(0,s.jsx)(n.a,{href:"#method-tojson",children:"toJson"}),"\n",(0,s.jsx)(n.a,{href:"#method-tojsonarray",children:"toJsonArray"}),"\n",(0,s.jsx)(n.a,{href:"#method-tojsondocument",children:"toJsonDocument"}),"\n",(0,s.jsx)(n.a,{href:"#method-tomap",children:"toMap"}),"\n",(0,s.jsx)(n.a,{href:"#method-tomapvariantlist",children:"toMapVariantList"}),"\n",(0,s.jsx)(n.a,{href:"#method-toquery",children:"toQuery"}),"\n",(0,s.jsx)(n.a,{href:"#method-tolist",children:"toList"}),"\n",(0,s.jsx)(n.a,{href:"#method-tolistvariantlist",children:"toListVariantList"}),"\n",(0,s.jsx)(n.a,{href:"#method-unique",children:"unique"}),"\n",(0,s.jsx)(n.a,{href:"#method-uniqueby",children:"uniqueBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-uniquerelaxed",children:"uniqueRelaxed"}),"\n",(0,s.jsx)(n.a,{href:"#method-uniquerelaxedby",children:"uniqueRelaxedBy"}),"\n",(0,s.jsx)(n.a,{href:"#method-value",children:"value"}),"\n",(0,s.jsx)(n.a,{href:"#method-where",children:"where"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherebetween",children:"whereBetween"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherein",children:"whereIn"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenotbetween",children:"whereNotBetween"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenotin",children:"whereNotIn"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenotnull",children:"whereNotNull"}),"\n",(0,s.jsx)(n.a,{href:"#method-wherenull",children:"whereNull"})]})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["For a better understanding of the following examples, many of the variable declarations below use actual types instead of the ",(0,s.jsx)(n.code,{children:"auto"})," keyword."]})}),"\n",(0,s.jsxs)("div",{className:"collection-methods",children:[(0,s.jsx)(n.h4,{id:"method-all",children:(0,s.jsx)(n.code,{children:"all()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"all"})," method returns a copy of the underlying vector represented by the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"QList = users.all();\n"})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#method-tobase",children:(0,s.jsx)(n.code,{children:"toBase"})})," is an alias to the ",(0,s.jsx)(n.code,{children:"all"})," method."]})}),(0,s.jsx)(n.h4,{id:"method-contains",children:(0,s.jsx)(n.code,{children:"contains()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"contains"})," method may be used to determine if a given model instance is contained by the collection. This method accepts a primary key or a model instance:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.contains(1);\n\nusers.contains(User::find(1));\n"})}),(0,s.jsxs)(n.p,{children:["Alternatively, you may pass a lambda expression to the ",(0,s.jsx)(n.code,{children:"contains"})," method to determine if a model exists in the collection matching a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.contains([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n"})}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"contains"}),", see the ",(0,s.jsx)(n.a,{href:"#method-doesntcontain",children:"doesntContain"})," method."]}),(0,s.jsx)(n.h4,{id:"method-doesntcontain",children:(0,s.jsx)(n.code,{children:"doesntContain()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"doesntContain"})," method determines whether the collection does not contain a given item. This method accepts a primary key or a model instance:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.doesntContain(1);\n\nusers.doesntContain(User::find(1));\n"})}),(0,s.jsxs)(n.p,{children:["Alternatively, you may pass a lambda expression to the ",(0,s.jsx)(n.code,{children:"doesntContain"})," method to determine if a model does not exist in the collection matching a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.doesntContain([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n"})}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"doesntContain"}),", see the ",(0,s.jsx)(n.a,{href:"#method-contains",children:"contains"})," method."]}),(0,s.jsx)(n.h4,{id:"method-each",children:(0,s.jsx)(n.code,{children:"each()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"each"})," method iterates over the models in the collection and passes each model to the lambda expression:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users = Post::whereEq("user_id", 1)->get();\n\nusers.each([](User *const user)\n{\n // ...\n});\n'})}),(0,s.jsxs)(n.p,{children:["If you would like to stop iterating through the models, you may return ",(0,s.jsx)(n.code,{children:"false"})," from your lambda expression:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.each([](User *const user)\n{\n if (/* condition */)\n return false;\n\n // Some logic\n\n return true;\n});\n"})}),(0,s.jsx)(n.p,{children:"You may also pass the lambda expression with two parameters, whereas the second one is an index:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"users.each([](User *const user, const std::size_t index)\n{\n // ...\n});\n"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"each"})," method returns an lvalue ",(0,s.jsx)(n.strong,{children:"reference"})," to the currently processed collection."]}),(0,s.jsxs)(n.p,{children:["It can be also called on ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," rvalues, it returns an rvalue reference in this case."]}),(0,s.jsx)(n.h4,{id:"method-except",children:(0,s.jsx)(n.code,{children:"except()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"except"})," method returns all of the models that do not have the given primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersResult = users.except({1, 2, 3});\n"})}),(0,s.jsxs)(n.p,{children:["All of the models are returned if the ",(0,s.jsx)(n.code,{children:"ids"})," argument is empty ",(0,s.jsx)(n.code,{children:"except({})"}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"except"}),", see the ",(0,s.jsx)(n.a,{href:"#method-only",children:"only"})," method."]}),(0,s.jsx)(n.h4,{id:"method-filter",children:(0,s.jsx)(n.code,{children:"filter()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"filter"})," method filters the collection using the lambda expression, keeping only those models that pass a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersBanned = users.filter([](const User *const user)\n{\n return user->getAttribute("is_banned");\n});\n'})}),(0,s.jsx)(n.p,{children:"You may also pass the lambda expression with two parameters, whereas the second one is an index:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersBanned = users.filter([](const User *const user,\n const std::size_t index)\n{\n return index < 10 && user->getAttribute("is_banned");\n});\n'})}),(0,s.jsxs)(n.p,{children:["If no lambda expression is supplied, all models of the collection that are equivalent to the ",(0,s.jsx)(n.code,{children:"nullptr"})," will be removed:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersRaw = User::findMany({1, 2});\nModelsCollection users {&usersRaw[0], nullptr, &usersRaw[1]};\n\nModelsCollection filtered = users.filter();\n\n// {1, 2}\n"})}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"filter"}),", see the ",(0,s.jsx)(n.a,{href:"#method-reject",children:"reject"})," method."]}),(0,s.jsx)(n.h4,{id:"method-find",children:(0,s.jsx)(n.code,{children:"find()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"find"})," method returns the model that has a primary key matching the given key:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"User *const user = users.find(1);\n"})}),(0,s.jsxs)(n.p,{children:["If you pass a model instance, ",(0,s.jsx)(n.code,{children:"find"})," will attempt to return a model matching the primary key:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"User *user = users.find(anotherUser);\n"})}),(0,s.jsxs)(n.p,{children:["The two overloads above also accept the second ",(0,s.jsx)(n.code,{children:"defaultModel"})," model argument, which will be returned if a model was not found in the collection, its default value is the ",(0,s.jsx)(n.code,{children:"nullptr"}),"."]}),(0,s.jsxs)(n.p,{children:["Alternatively, may pass more IDs and ",(0,s.jsx)(n.code,{children:"find"})," will return all models which have a primary key within the given unordered set:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersMany = users.find({1, 2});\n"})}),(0,s.jsxs)(n.p,{children:["This overload internally calls the ",(0,s.jsx)(n.a,{href:"#method-only",children:(0,s.jsx)(n.code,{children:"only"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-first",children:(0,s.jsx)(n.code,{children:"first()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"first"})," method returns the first model in the collection that passes a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute("votes") > 150;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n'})}),(0,s.jsxs)(n.p,{children:["If no model passes a given truth test then the value of the second ",(0,s.jsx)(n.code,{children:"defaultModel"})," argument will be returned, its default value is the ",(0,s.jsx)(n.code,{children:"nullptr"}),"."]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute("votes") > 500;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n'})}),(0,s.jsxs)(n.p,{children:["You can also call all ",(0,s.jsx)(n.code,{children:"first"})," overloads provided by the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#first",children:(0,s.jsx)(n.code,{children:"QList::first"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-first-where",children:(0,s.jsx)(n.code,{children:"firstWhere()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"firstWhere"})," method returns the first model in the collection with the given column / value pair:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection users {\n {{"name", "Leon"}, {"age", NullVariant::UShort()}},\n {{"name", "Jill"}, {"age", 14}},\n {{"name", "Jack"}, {"age", 23}},\n {{"name", "Jill"}, {"age", 84}},\n};\n\nauto user = users.firstWhereEq("name", "Linda");\n\n// {{"name", "Jill"}, {"age", 14}}\n'})}),(0,s.jsxs)(n.p,{children:["You may also call the ",(0,s.jsx)(n.code,{children:"firstWhere"})," method with a comparison operator:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'users.firstWhere("age", ">=", 18);\n\n// {{"name", "Jack"}, {"age", 23}}\n'})}),(0,s.jsx)(n.h4,{id:"method-fresh",children:(0,s.jsx)(n.code,{children:"fresh()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"fresh"})," method retrieves a fresh instance of each model in the collection from the database. In addition, any specified relationships will be eager loaded:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersFresh = users.fresh();\n\nauto usersFresh = users.fresh("comments");\n\nauto usersFresh = users.fresh("posts:id,name");\n\nauto usersFresh = users.fresh({"comments", "posts:id,name"});\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"relations"})," argument format is the same as for TinyBuilder's ",(0,s.jsx)(n.a,{href:"/tinyorm/relationships#lazy-eager-loading",children:(0,s.jsx)(n.code,{children:"load"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-implode",children:(0,s.jsx)(n.code,{children:"implode()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"implode"}),' method joins attributes by the given column and the "glue" string you wish to place between the values:']}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n};\n\nproducts.implode("product", ", ");\n\n// {Desk, Chair}\n'})}),(0,s.jsx)(n.p,{children:'The default "glue" value is an empty string "".'}),(0,s.jsx)(n.h4,{id:"method-isempty",children:(0,s.jsx)(n.code,{children:"isEmpty()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"isEmpty"})," method returns ",(0,s.jsx)(n.code,{children:"true"})," if the collection is empty; otherwise, ",(0,s.jsx)(n.code,{children:"false"})," is returned:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection().isEmpty();\n\n// true\n"})}),(0,s.jsx)(n.h4,{id:"method-isnotempty",children:(0,s.jsx)(n.code,{children:"isNotEmpty()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"isNotEmpty"})," method returns ",(0,s.jsx)(n.code,{children:"true"})," if the collection is not empty; otherwise, ",(0,s.jsx)(n.code,{children:"false"})," is returned:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection().isNotEmpty();\n\n// false\n"})}),(0,s.jsx)(n.h4,{id:"method-last",children:(0,s.jsx)(n.code,{children:"last()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"last"})," method returns the last model in the collection that passes a given truth test:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "Rose"}, {"votes", 350}},\n};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute("votes") < 300;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n'})}),(0,s.jsxs)(n.p,{children:["If no model passes a given truth test then the value of the second ",(0,s.jsx)(n.code,{children:"defaultModel"})," argument will be returned, its default value is the ",(0,s.jsx)(n.code,{children:"nullptr"}),"."]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute("votes") < 100;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n'})}),(0,s.jsxs)(n.p,{children:["You can also call all ",(0,s.jsx)(n.code,{children:"last"})," overloads provided by the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#last",children:(0,s.jsx)(n.code,{children:"QList::last"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-load",children:(0,s.jsx)(n.code,{children:"load()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"load"})," method eager loads the given relationships for all models in the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'users.load({"comments", "posts"});\n\nusers.load("comments.author");\n\nusers.load({{"comments"}, {"posts", [](auto &query)\n{\n query.whereEq("active", true);\n}}});\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"relations"})," argument format is the same as for TinyBuilder's ",(0,s.jsx)(n.a,{href:"/tinyorm/relationships#lazy-eager-loading",children:(0,s.jsx)(n.code,{children:"load"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-map",children:(0,s.jsx)(n.code,{children:"map()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"map"})," method iterates through the collection and passes a ",(0,s.jsx)(n.strong,{children:"copy"})," of each model to the given lambda expression. The lambda expression is free to modify the model and return it, thus forming a new collection of modified models:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto usersAdded = users.map([](User &&userCopy)\n{\n if (userCopy.getAttribute("name") == "John")\n userCopy["votes"] = userCopy.getAttribute("votes") + 1;\n\n return std::move(userCopy);\n});\n\n/*\n {\n {{"name", "John"}, {"price", 201}},\n {{"name", "Jack"}, {"price", 400}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["The second ",(0,s.jsx)(n.code,{children:"map"})," overload allows to return the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'QList usersAdded = users.map([](User &&userCopy)\n{\n const auto votesRef = userCopy["votes"];\n\n if (userCopy.getAttribute("name") == "John")\n votesRef = userCopy.getAttribute("votes") + 1;\n\n return votesRef->value();\n});\n\n// {201, 400}\n'})}),(0,s.jsxs)(n.p,{children:["Both overloads allow to pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,s.jsx)(n.code,{children:"std::size_t"})," type."]}),(0,s.jsx)(n.admonition,{type:"caution",children:(0,s.jsxs)(n.p,{children:["Like most other collection methods, ",(0,s.jsx)(n.code,{children:"map"})," returns a new collection instance; it does not modify the collection it is called on. If you want to modify the original collection in place, use the ",(0,s.jsx)(n.a,{href:"#method-each",children:(0,s.jsx)(n.code,{children:"each"})})," method."]})}),(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The model copy is passed to the lambda expression even if the ",(0,s.jsx)(n.code,{children:"map"})," iterates over a collection of model pointers ",(0,s.jsx)(n.code,{children:"ModelsCollection"}),". The models are dereferenced behind the scene."]})}),(0,s.jsx)(n.h4,{id:"method-mapwithkeys",children:(0,s.jsx)(n.code,{children:"mapWithKeys()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"mapWithKeys"})," method iterates through the collection and passes each model to the given lambda expression. It returns the ",(0,s.jsx)(n.code,{children:"std::unordered_map"})," and the lambda expression should return the ",(0,s.jsx)(n.code,{children:"std::pair"})," containing a single column / value pair:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 1}, {"name", "John"}, {"email", "john@example.com"}},\n {{"id", 2}, {"name", "Jill"}, {"email", "jill@example.com"}},\n};\n\nauto usersMap = users.mapWithKeys(\n [](User *const user) -> std::pair\n{\n return {user->getKeyCasted(), user->getAttribute("name")};\n});\n\n// {{1, \'John\'}, {2, \'Jill\'}}\n'})}),(0,s.jsx)(n.p,{children:"You can also map IDs to the model pointers:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"auto usersMap = users.mapWithKeys(\n [](User *const user) -> std::pair\n{\n return {user->getKeyCasted(), user};\n});\n"})}),(0,s.jsx)(n.h4,{id:"method-mapwithmodelkeys",children:(0,s.jsx)(n.code,{children:"mapWithModelKeys()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"mapWithModelKeys"})," maps the primary keys to the ",(0,s.jsx)(n.code,{children:"Model *"}),", it returns the ",(0,s.jsx)(n.code,{children:"std::unordered_map"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"auto usersMap = users.mapWithModelKeys();\n"})}),(0,s.jsx)(n.h4,{id:"method-modelkeys",children:(0,s.jsx)(n.code,{children:"modelKeys()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"modelKeys"})," method returns the primary keys for all models in the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 1}, {"name", "John"}},\n {{"id", 2}, {"name", "Jill"}},\n {{"id", 3}, {"name", "Kate"}},\n {{"id", 5}, {"name", "Rose"}},\n};\n\nusers.modelKeys(); // Returns QList\nusers.modelKeys();\n\n// {1, 2, 3, 5}\n'})}),(0,s.jsx)(n.h4,{id:"method-only",children:(0,s.jsx)(n.code,{children:"only()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"only"})," method returns all of the models that have the given primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection usersResult = users.only({1, 2, 3});\n"})}),(0,s.jsxs)(n.p,{children:["An empty collection is returned if the ",(0,s.jsx)(n.code,{children:"ids"})," argument is empty ",(0,s.jsx)(n.code,{children:"only({})"}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsxs)(n.p,{children:["For the inverse of ",(0,s.jsx)(n.code,{children:"only"}),", see the ",(0,s.jsx)(n.a,{href:"#method-except",children:"except"})," method."]}),(0,s.jsx)(n.h4,{id:"method-pluck",children:(0,s.jsx)(n.code,{children:"pluck()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"pluck"})," method retrieves all of the values for a given column, the following overload returns the ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"id", 1}, {"name", "Desk"}},\n {{"id", 2}, {"name", "Chair"}},\n};\n\nauto plucked = products.pluck("name");\n\n// {Desk, Chair}\n'})}),(0,s.jsxs)(n.p,{children:["The second overload allows returning the custom type ",(0,s.jsx)(n.code,{children:"QList"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto plucked = products.pluck("name");\n'})}),(0,s.jsxs)(n.p,{children:["You may also specify how you wish the resulting collection to be keyed, this overload returns the ",(0,s.jsx)(n.code,{children:"std::map"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto plucked = products.pluck("name", "id");\n\n// {{1, "Desk"}, {2, "Chair"}}\n'})}),(0,s.jsx)(n.p,{children:"If duplicate keys exist, the last matching attribute will be inserted into the plucked collection:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection collection {\n {{"brand", "Tesla"}, {"color", "red"}},\n {{"brand", "Pagani"}, {"color", "white"}},\n {{"brand", "Tesla"}, {"color", "black"}},\n {{"brand", "Pagani"}, {"color", "orange"}},\n};\n\nauto plucked = collection.pluck("color", "brand");\n\n// {{\'Tesla\', \'black\'}, {\'Pagani\', \'orange"}}\n'})}),(0,s.jsx)(n.h4,{id:"method-reject",children:(0,s.jsx)(n.code,{children:"reject()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"reject"})," method filters the collection using the given lambda expression. The lambda should return ",(0,s.jsx)(n.code,{children:"true"})," if the model should be removed from the resulting collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto usersWithNote = users.reject([](const User *const user)\n{\n return user->getAttribute("note").isNull();\n});\n'})}),(0,s.jsxs)(n.p,{children:["You may also pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,s.jsx)(n.code,{children:"std::size_t"})," type."]}),(0,s.jsxs)(n.p,{children:["For the inverse of the ",(0,s.jsx)(n.code,{children:"reject"})," method, see the ",(0,s.jsx)(n.a,{href:"#method-filter",children:(0,s.jsx)(n.code,{children:"filter"})})," method."]}),(0,s.jsx)(n.h4,{id:"method-sort",children:(0,s.jsx)(n.code,{children:"sort()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"sort"})," method sorts the models collection by primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sort();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["You may pass a predicate and projection callbacks to the ",(0,s.jsx)(n.code,{children:"sort"})," method with your own algorithms. Refer to the CPP reference documentation on ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/sort",children:(0,s.jsx)(n.code,{children:"ranges::sort"})}),", which is what the ",(0,s.jsx)(n.code,{children:"sort"})," method calls internally."]}),(0,s.jsxs)(n.p,{children:["You can eg. sort by multiple columns, for an alternative method of multi-column sorting look at ",(0,s.jsx)(n.a,{href:"#method-sortby",children:"sortBy"}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sort([](const User *const left,\n const User *const right)\n{\n const auto leftValue = left->getAttribute("name");\n const auto rightValue = right->getAttribute("name");\n\n if (leftValue == rightValue)\n return left->getAttribute("votes") <\n right->getAttribute("votes");\n\n return leftValue < rightValue;\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 350}},\n }\n*/\n'})}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can use the ",(0,s.jsx)(n.a,{href:"#method-stablesort",children:"stable"})," sort method variants to preserve the order of equal models."]})}),(0,s.jsx)(n.h4,{id:"method-sortby",children:(0,s.jsx)(n.code,{children:"sortBy()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"sortBy"})," method sorts the collection by the given column, this overload needs the template argument so it can cast the attribute value before comparing:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto sorted = users.sortBy("name");\n\n/*\n {\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 150}},\n }\n*/\n'})}),(0,s.jsx)(n.p,{children:"You may pass the projection callback to determine how to sort the collection's models:"}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto sorted = users.sortBy([](User *const user)\n{\n return user->getAttribute("votes");\n});\n\n/*\n {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["If you would like to sort your collection by multiple columns, you may pass a vector of comparison lambda expressions that define each sort operation to the ",(0,s.jsx)(n.code,{children:"sortBy"})," method, in the following example is the ",(0,s.jsx)(n.code,{children:"name"})," column sorted in ascending order and the second ",(0,s.jsx)(n.code,{children:"votes"})," column is sorted in descending order:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using AttributeUtils = Orm::Tiny::Utils::Attribute;\n\nModelsCollection users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sortBy({\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortBy(\n left->getAttribute("name"),\n right->getAttribute("name"));\n },\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortByDesc(\n left->getAttribute("votes"),\n right->getAttribute("votes"));\n },\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "Kate"}, {"votes", 200}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"AttributeUtils::compareForSortBy"})," and ",(0,s.jsx)(n.code,{children:"compareForSortByDesc"})," methods are helper methods, they are needed because the Qt framework doesn't define ",(0,s.jsx)(n.code,{children:"<=>"})," spaceship operator on its types, it doesn't support the three-way comparison."]}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.h4,{id:"method-sortbydesc",children:(0,s.jsx)(n.code,{children:"sortByDesc()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortby",children:(0,s.jsx)(n.code,{children:"sortBy"})})," method but will sort the collection in the opposite order."]}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.h4,{id:"method-sortdesc",children:(0,s.jsx)(n.code,{children:"sortDesc()"})}),(0,s.jsxs)(n.p,{children:["This method will sort the collection in the opposite order as the ",(0,s.jsx)(n.a,{href:"#method-sort",children:(0,s.jsx)(n.code,{children:"sort"})})," method:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sortDesc();\n\n/*\n {\n {{"id", 3}, {"name", "John"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n }\n*/\n'})}),(0,s.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,s.jsx)(n.h4,{id:"method-stablesort",children:(0,s.jsx)(n.code,{children:"stableSort()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sort",children:(0,s.jsx)(n.code,{children:"sort"})})," method but will preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-stablesortby",children:(0,s.jsx)(n.code,{children:"stableSortBy()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortby",children:(0,s.jsx)(n.code,{children:"sortBy"})})," method but will preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-stablesortbydesc",children:(0,s.jsx)(n.code,{children:"stableSortByDesc()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortbydesc",children:(0,s.jsx)(n.code,{children:"sortByDesc"})})," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-stablesortdesc",children:(0,s.jsx)(n.code,{children:"stableSortDesc()"})}),(0,s.jsxs)(n.p,{children:["This method has the same signature as the ",(0,s.jsx)(n.a,{href:"#method-sortdesc",children:(0,s.jsx)(n.code,{children:"sortDesc"})})," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."]}),(0,s.jsx)(n.h4,{id:"method-tap",children:(0,s.jsx)(n.code,{children:"tap()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tap"}),' method passes a collection to the given lambda expression, allowing you to "tap" into the collection at a specific point and do something with the models while not affecting the collection itself:']}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nusers.sort()\n .tap([](/*const */ModelsCollection &usersRef)\n{\n qDebug() << "IDs after sorting:"\n << usersRef.template modelKeys();\n})\n .value("id");\n\n// 1\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tap"})," method returns an lvalue ",(0,s.jsx)(n.strong,{children:"reference"})," to the currently processed collection."]}),(0,s.jsxs)(n.p,{children:["It can be also called on ",(0,s.jsx)(n.code,{children:"ModelsCollection"})," rvalues, it returns an rvalue reference in this case."]}),(0,s.jsx)(n.h4,{id:"method-tobase",children:(0,s.jsx)(n.code,{children:"toBase()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toBase"})," method returns a copy of the underlying vector represented by the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"QList = users.toBase();\n"})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#method-tobase",children:(0,s.jsx)(n.code,{children:"toBase"})})," is an alias to the ",(0,s.jsx)(n.code,{children:"all"})," method."]})}),(0,s.jsx)(n.h4,{id:"method-tojson",children:(0,s.jsx)(n.code,{children:"toJson()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJson"})," method converts the collection of models with all nested relations into a JSON serialized ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qbytearray.html",children:(0,s.jsx)(n.code,{children:"QByteArray"})}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty array for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and ",(0,s.jsx)(n.code,{children:"null"})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJson"})," method accepts the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html#JsonFormat-enum",children:(0,s.jsx)(n.code,{children:"QJsonDocument::JsonFormat"})}),", possible values are ",(0,s.jsx)(n.code,{children:"QJsonDocument::Indented"})," or ",(0,s.jsx)(n.code,{children:"QJsonDocument::Compact"}),"."]})}),(0,s.jsx)(n.h4,{id:"method-tojsonarray",children:(0,s.jsx)(n.code,{children:"toJsonArray()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJsonArray"})," method converts the collection of models with all nested relations into a ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsonarray.html",children:(0,s.jsx)(n.code,{children:"QJsonArray"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-tojsondocument",children:(0,s.jsx)(n.code,{children:"toJsonDocument()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toJsonDocument"})," method converts the collection of models with all nested relations into a ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html",children:(0,s.jsx)(n.code,{children:"QJsonDocument"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-tomap",children:(0,s.jsx)(n.code,{children:"toMap()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toMap"})," method converts the collection of models with all nested relations into an attributes map ",(0,s.jsx)(n.code,{children:"QList"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.h4,{id:"method-tomapvariantlist",children:(0,s.jsx)(n.code,{children:"toMapVariantList()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toMapVariantList"})," method converts the collection of models with all nested relations into an attributes map, but it returns the ",(0,s.jsx)("abbr",{title:"QList",children:(0,s.jsx)(n.code,{children:"QVariantList"})})," instead of the ",(0,s.jsx)(n.code,{children:"QList"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toMapVariantList"})," method is internally needed by the ",(0,s.jsx)(n.code,{children:"toJson"})," related methods."]})}),(0,s.jsx)(n.h4,{id:"method-toquery",children:(0,s.jsx)(n.code,{children:"toQuery()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toQuery"})," method returns the ",(0,s.jsx)(n.code,{children:"TinyBuilder"})," instance containing a ",(0,s.jsx)(n.code,{children:"whereIn"})," constraint with the collection of models' primary keys:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nModelsCollection users = User::whereEq("status", "VIP")->get();\n\nusers.toQuery()->update({\n {"status", "Administrator"},\n});\n'})}),(0,s.jsx)(n.h4,{id:"method-tolist",children:(0,s.jsx)(n.code,{children:"toList()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toList"})," method converts the collection of models with all nested relations into an attributes vector ",(0,s.jsx)(n.code,{children:"QList>"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.h4,{id:"method-tolistvariantlist",children:(0,s.jsx)(n.code,{children:"toListVariantList()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toListVariantList"})," method converts the collection of models with all nested relations into an attributes vector, but it returns the ",(0,s.jsx)("abbr",{title:"QList",children:(0,s.jsx)(n.code,{children:"QVariantList"})})," instead of the ",(0,s.jsx)(n.code,{children:"QList>"}),"."]}),(0,s.jsxs)(n.p,{children:["It returns an empty ",(0,s.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,s.jsx)(n.code,{children:"many"})," type relations and a null ",(0,s.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,s.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,s.jsx)(n.code,{children:"one"})," type relations."]}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"toListVariantList"})," method is internally needed by the ",(0,s.jsx)(n.code,{children:"toJson"})," related methods."]})}),(0,s.jsx)(n.h4,{id:"method-unique",children:(0,s.jsx)(n.code,{children:"unique()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"unique"})," method returns all of the unique models in the ",(0,s.jsx)(n.strong,{children:"sorted"})," collection. Any models with the same primary key as another model in the collection are removed:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.unique();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["It sorts the collection internally because the ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique",children:(0,s.jsx)(n.code,{children:"ranges::unique"})})," can correctly operate only on the sorted container. You can disable it by passing ",(0,s.jsx)(n.code,{children:"false"})," using the first ",(0,s.jsx)(n.code,{children:"sort"})," parameter:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto unique = users.sort().unique(false);\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-uniqueby",children:(0,s.jsx)(n.code,{children:"uniqueBy()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"uniqueBy"})," method returns all of the unique models in the ",(0,s.jsx)(n.strong,{children:"sorted"})," collection by the given column. Any models with the same column value as another model in the collection are removed. It needs the template argument, so it can cast the attribute value before comparing:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueBy("name");\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["It sorts the collection internally because the ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique",children:(0,s.jsx)(n.code,{children:"ranges::unique"})})," can correctly operate only on the sorted container. You can disable it by passing ",(0,s.jsx)(n.code,{children:"false"})," using the second ",(0,s.jsx)(n.code,{children:"sort"})," parameter:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto unique = users.sortBy("name")\n .uniqueBy("name", false);\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-uniquerelaxed",children:(0,s.jsx)(n.code,{children:"uniqueRelaxed()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"uniqueRelaxed"})," method returns all of the unique models in the collection, it doesn't need a sorted collection. Any models with the same primary key as another model in the collection are removed:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxed();\n\n/*\n {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-uniquerelaxedby",children:(0,s.jsx)(n.code,{children:"uniqueRelaxedBy()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"uniqueRelaxedBy"})," method returns all of the unique models in the collection by the given column, it doesn't need a sorted collection, but it needs the template argument, so it can cast the attribute value before comparing:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxedBy("name");\n\n/*\n {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-value",children:(0,s.jsx)(n.code,{children:"value()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"value"})," method retrieves a given value from the first model of the collection:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nQVariant votes = users.value("votes");\n\n// 200\n'})}),(0,s.jsxs)(n.p,{children:["Alternatively, you can cast an obtained ",(0,s.jsx)(n.code,{children:"QVariant"})," value to the given type by the second ",(0,s.jsx)(n.code,{children:"value"})," overload:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'quint64 votes = users.value("votes");\n'})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"value"})," method also accepts the second ",(0,s.jsx)(n.code,{children:"defaultValue"})," argument, which will be returned if a collection is empty, the first model is ",(0,s.jsx)(n.code,{children:"nullptr"}),", or a model doesn't contain the given column:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto votes = ModelsCollection().value("votes", 0);\n\n// 0\n'})}),(0,s.jsxs)(n.p,{children:["You can also call all ",(0,s.jsx)(n.code,{children:"value"})," overloads provided by the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#value",children:(0,s.jsx)(n.code,{children:"QList::value"})}),"."]}),(0,s.jsx)(n.h4,{id:"method-where",children:(0,s.jsx)(n.code,{children:"where()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"where"})," method filters the collection by a given column / value pair:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.where("price", "=", 100);\n\n/*\n {\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["For convenience, if you want to verify that a column is ",(0,s.jsx)(n.code,{children:"="})," to a given value, you may call ",(0,s.jsx)(n.code,{children:"whereEq"})," method. Similar ",(0,s.jsx)(n.code,{children:"XxxEq"})," methods are also defined for other commands:"]}),(0,s.jsx)(n.p,{children:'auto filtered = products.whereEq("price", 100);'}),(0,s.jsxs)(n.p,{children:["Optionally, you may pass a comparison operator as the second argument.",(0,s.jsx)("br",{}),"Supported operators are ",(0,s.jsx)(n.code,{children:"="}),", ",(0,s.jsx)(n.code,{children:"!="}),", ",(0,s.jsx)(n.code,{children:"<"}),", ",(0,s.jsx)(n.code,{children:">"}),", ",(0,s.jsx)(n.code,{children:"<="}),", and ",(0,s.jsx)(n.code,{children:">="}),":"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.where("price", ">", 150);\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-wherebetween",children:(0,s.jsx)(n.code,{children:"whereBetween()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereBetween"})," method filters the collection by determining if a specified models' attribute value is within a given range:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereBetween("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-wherein",children:(0,s.jsx)(n.code,{children:"whereIn()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereIn"})," method filters models from the collection that have a specified attribute value that is contained within the given unordered set:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereIn("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["An empty collection is returned if the ",(0,s.jsx)(n.code,{children:"values"})," argument is empty ",(0,s.jsx)(n.code,{children:'whereIn("price", {})'}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsx)(n.h4,{id:"method-wherenotbetween",children:(0,s.jsx)(n.code,{children:"whereNotBetween()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNotBetween"})," method filters the collection by determining if a specified models' attribute value is outside of a given range:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereNotBetween("price", {100, 200});\n\n/*\n {\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Pencil"}, {"price", 30}},\n }\n*/\n'})}),(0,s.jsx)(n.h4,{id:"method-wherenotin",children:(0,s.jsx)(n.code,{children:"whereNotIn()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNotIn"})," method removes models from the collection that have a specified attribute value that is contained within the given unordered set:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereNotIn("price", {100, 200});\n\n/*\n {\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n'})}),(0,s.jsxs)(n.p,{children:["All of the models are returned if the ",(0,s.jsx)(n.code,{children:"values"})," argument is empty ",(0,s.jsx)(n.code,{children:'whereNotIn("price", {})'}),"."]}),(0,s.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,s.jsx)(n.h4,{id:"method-wherenotnull",children:(0,s.jsx)(n.code,{children:"whereNotNull()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNotNull"})," method returns models from the collection where the given column is not ",(0,s.jsx)(n.code,{children:"null"})," QVariant:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n/*\n {\n {{"name", "John"}},\n {{"name", "Jack"}},\n }\n*/\n'})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"NullVariant"})," class returns the correct ",(0,s.jsx)(n.code,{children:"null"})," QVariant for both Qt 5 ",(0,s.jsx)(n.code,{children:"QVariant(QVariant::String)"})," and also Qt 6 ",(0,s.jsx)(n.code,{children:"QVariant(QMetaType(QMetaType::QString))"}),". The reason why this class still exists even after Qt v5.15 support was removed is the performance boost."]})}),(0,s.jsx)(n.h4,{id:"method-wherenull",children:(0,s.jsx)(n.code,{children:"whereNull()"})}),(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"whereNull"})," method returns models from the collection where the given column is ",(0,s.jsx)(n.code,{children:"null"})," QVariant:"]}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n// {{"name", NullVariant::QString()}}\n'})}),(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"NullVariant"})," class returns the correct ",(0,s.jsx)(n.code,{children:"null"})," QVariant for both Qt 5 ",(0,s.jsx)(n.code,{children:"QVariant(QVariant::String)"})," and also Qt 6 ",(0,s.jsx)(n.code,{children:"QVariant(QMetaType(QMetaType::QString))"}),". The reason why this class still exists even after Qt v5.15 support was removed is the performance boost."]})})]})]})}function u(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>i});var s=t(6540);const o={},r=s.createContext(o);function l(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:l(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.2fc83ba1.js b/assets/js/runtime~main.fa672130.js similarity index 98% rename from assets/js/runtime~main.2fc83ba1.js rename to assets/js/runtime~main.fa672130.js index afc24995a..ec11b1b4d 100644 --- a/assets/js/runtime~main.2fc83ba1.js +++ b/assets/js/runtime~main.fa672130.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,t,r,o,f={},n={};function c(e){var a=n[e];if(void 0!==a)return a.exports;var t=n[e]={exports:{}};return f[e].call(t.exports,t,t.exports,c),t.exports}c.m=f,e=[],c.O=(a,t,r,o)=>{if(!t){var f=1/0;for(i=0;i=o)&&Object.keys(c.O).every((e=>c.O[e](t[d])))?t.splice(d--,1):(n=!1,o0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,r,o]},c.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return c.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var o=Object.create(null);c.r(o);var f={};a=a||[null,t({}),t([]),t(t)];for(var n=2&r&&e;"object"==typeof n&&!~a.indexOf(n);n=t(n))Object.getOwnPropertyNames(n).forEach((a=>f[a]=()=>e[a]));return f.default=()=>e,c.d(o,f),o},c.d=(e,a)=>{for(var t in a)c.o(a,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((a,t)=>(c.f[t](e,a),a)),[])),c.u=e=>"assets/js/"+({27:"d459b1c4",48:"a94703ab",69:"e19c288b",82:"5b254f70",98:"a7bd4aaa",117:"3dd307b5",129:"8a8faf8d",138:"1a4e3797",153:"1222ea4e",170:"ba3d4959",205:"b4f71b2f",258:"cb1e72f9",295:"21dc2778",304:"62a1276f",395:"0ab078a9",401:"17896441",467:"e3ac21cb",485:"59b1a96c",567:"22dd74f7",638:"7333c691",647:"5e95c892",742:"aba21aa0",755:"a4d3e054",871:"fb313d4e",957:"c141421f",983:"feaee7f3",995:"cbe663fe"}[e]||e)+"."+{27:"431acd58",48:"2ad1c777",69:"d0c41dce",82:"d6445683",98:"80cc43c0",117:"7f7edc87",129:"c1f86db1",138:"1fc0de54",153:"a36e63d0",170:"ef27b442",205:"af30ffa7",237:"d109f2ba",258:"206d093e",295:"d15c2f87",304:"2590df53",395:"06fcc850",401:"7e577731",416:"a3ad28f7",446:"d7af1da2",462:"0011555c",467:"5bbce64e",485:"19376fa2",567:"e3956fac",638:"1ebcbeee",647:"7024aad0",742:"cb1d9d7d",755:"c5c4fcd6",871:"2fcd3c4b",913:"3fa60236",957:"2356f0d5",983:"e63c6b5d",995:"81a87eec"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},o="tinyorm.org:",c.l=(e,a,t,f)=>{if(r[e])r[e].push(a);else{var n,d;if(void 0!==t)for(var b=document.getElementsByTagName("script"),i=0;i{n.onerror=n.onload=null,clearTimeout(s);var o=r[e];if(delete r[e],n.parentNode&&n.parentNode.removeChild(n),o&&o.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=l.bind(null,n.onerror),n.onload=l.bind(null,n.onload),d&&document.head.appendChild(n)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/",c.gca=function(e){return e={17896441:"401",d459b1c4:"27",a94703ab:"48",e19c288b:"69","5b254f70":"82",a7bd4aaa:"98","3dd307b5":"117","8a8faf8d":"129","1a4e3797":"138","1222ea4e":"153",ba3d4959:"170",b4f71b2f:"205",cb1e72f9:"258","21dc2778":"295","62a1276f":"304","0ab078a9":"395",e3ac21cb:"467","59b1a96c":"485","22dd74f7":"567","7333c691":"638","5e95c892":"647",aba21aa0:"742",a4d3e054:"755",fb313d4e:"871",c141421f:"957",feaee7f3:"983",cbe663fe:"995"}[e]||e,c.p+c.u(e)},(()=>{var e={354:0,869:0};c.f.j=(a,t)=>{var r=c.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(354|869)$/.test(a))e[a]=0;else{var o=new Promise(((t,o)=>r=e[a]=[t,o]));t.push(r[2]=o);var f=c.p+c.u(a),n=new Error;c.l(f,(t=>{if(c.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var o=t&&("load"===t.type?"missing":t.type),f=t&&t.target&&t.target.src;n.message="Loading chunk "+a+" failed.\n("+o+": "+f+")",n.name="ChunkLoadError",n.type=o,n.request=f,r[1](n)}}),"chunk-"+a,a)}},c.O.j=a=>0===e[a];var a=(a,t)=>{var r,o,f=t[0],n=t[1],d=t[2],b=0;if(f.some((a=>0!==e[a]))){for(r in n)c.o(n,r)&&(c.m[r]=n[r]);if(d)var i=d(c)}for(a&&a(t);b{"use strict";var e,a,t,r,o,f={},n={};function c(e){var a=n[e];if(void 0!==a)return a.exports;var t=n[e]={exports:{}};return f[e].call(t.exports,t,t.exports,c),t.exports}c.m=f,e=[],c.O=(a,t,r,o)=>{if(!t){var f=1/0;for(i=0;i=o)&&Object.keys(c.O).every((e=>c.O[e](t[d])))?t.splice(d--,1):(n=!1,o0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,r,o]},c.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return c.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var o=Object.create(null);c.r(o);var f={};a=a||[null,t({}),t([]),t(t)];for(var n=2&r&&e;"object"==typeof n&&!~a.indexOf(n);n=t(n))Object.getOwnPropertyNames(n).forEach((a=>f[a]=()=>e[a]));return f.default=()=>e,c.d(o,f),o},c.d=(e,a)=>{for(var t in a)c.o(a,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((a,t)=>(c.f[t](e,a),a)),[])),c.u=e=>"assets/js/"+({27:"d459b1c4",48:"a94703ab",69:"e19c288b",82:"5b254f70",98:"a7bd4aaa",117:"3dd307b5",129:"8a8faf8d",138:"1a4e3797",153:"1222ea4e",170:"ba3d4959",205:"b4f71b2f",258:"cb1e72f9",295:"21dc2778",304:"62a1276f",395:"0ab078a9",401:"17896441",467:"e3ac21cb",485:"59b1a96c",567:"22dd74f7",638:"7333c691",647:"5e95c892",742:"aba21aa0",755:"a4d3e054",871:"fb313d4e",957:"c141421f",983:"feaee7f3",995:"cbe663fe"}[e]||e)+"."+{27:"431acd58",48:"2ad1c777",69:"d0c41dce",82:"d6445683",98:"80cc43c0",117:"dc00c88e",129:"c1f86db1",138:"1fc0de54",153:"a36e63d0",170:"ef27b442",205:"af30ffa7",237:"d109f2ba",258:"206d093e",295:"d15c2f87",304:"2590df53",395:"06fcc850",401:"7e577731",416:"a3ad28f7",446:"d7af1da2",462:"0011555c",467:"5bbce64e",485:"19376fa2",567:"e3956fac",638:"1ebcbeee",647:"7024aad0",742:"cb1d9d7d",755:"c5c4fcd6",871:"2fcd3c4b",913:"3fa60236",957:"2356f0d5",983:"e63c6b5d",995:"81a87eec"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},o="tinyorm.org:",c.l=(e,a,t,f)=>{if(r[e])r[e].push(a);else{var n,d;if(void 0!==t)for(var b=document.getElementsByTagName("script"),i=0;i{n.onerror=n.onload=null,clearTimeout(s);var o=r[e];if(delete r[e],n.parentNode&&n.parentNode.removeChild(n),o&&o.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=l.bind(null,n.onerror),n.onload=l.bind(null,n.onload),d&&document.head.appendChild(n)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/",c.gca=function(e){return e={17896441:"401",d459b1c4:"27",a94703ab:"48",e19c288b:"69","5b254f70":"82",a7bd4aaa:"98","3dd307b5":"117","8a8faf8d":"129","1a4e3797":"138","1222ea4e":"153",ba3d4959:"170",b4f71b2f:"205",cb1e72f9:"258","21dc2778":"295","62a1276f":"304","0ab078a9":"395",e3ac21cb:"467","59b1a96c":"485","22dd74f7":"567","7333c691":"638","5e95c892":"647",aba21aa0:"742",a4d3e054:"755",fb313d4e:"871",c141421f:"957",feaee7f3:"983",cbe663fe:"995"}[e]||e,c.p+c.u(e)},(()=>{var e={354:0,869:0};c.f.j=(a,t)=>{var r=c.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(354|869)$/.test(a))e[a]=0;else{var o=new Promise(((t,o)=>r=e[a]=[t,o]));t.push(r[2]=o);var f=c.p+c.u(a),n=new Error;c.l(f,(t=>{if(c.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var o=t&&("load"===t.type?"missing":t.type),f=t&&t.target&&t.target.src;n.message="Loading chunk "+a+" failed.\n("+o+": "+f+")",n.name="ChunkLoadError",n.type=o,n.request=f,r[1](n)}}),"chunk-"+a,a)}},c.O.j=a=>0===e[a];var a=(a,t)=>{var r,o,f=t[0],n=t[1],d=t[2],b=0;if(f.some((a=>0!==e[a]))){for(r in n)c.o(n,r)&&(c.m[r]=n[r]);if(d)var i=d(c)}for(a&&a(t);bgtag("config","AW-989655383"),gtag("event","conversion",{send_to:"AW-989655383/vDYzCM--ks4DENfi89cD"}) - + diff --git a/building/migrations.html b/building/migrations.html index 97dc4c666..de8c5d30a 100644 --- a/building/migrations.html +++ b/building/migrations.html @@ -14,7 +14,7 @@ - + diff --git a/building/tinyorm.html b/building/tinyorm.html index d5615aa46..71f4719e0 100644 --- a/building/tinyorm.html +++ b/building/tinyorm.html @@ -14,7 +14,7 @@ - + diff --git a/database/getting-started.html b/database/getting-started.html index ecbbc3ab3..6734ca9ea 100644 --- a/database/getting-started.html +++ b/database/getting-started.html @@ -14,7 +14,7 @@ - + diff --git a/database/migrations.html b/database/migrations.html index 37a4d01d0..4b2f0de39 100644 --- a/database/migrations.html +++ b/database/migrations.html @@ -14,7 +14,7 @@ - + diff --git a/database/query-builder.html b/database/query-builder.html index cb12214ae..caa9b49cd 100644 --- a/database/query-builder.html +++ b/database/query-builder.html @@ -14,7 +14,7 @@ - + diff --git a/database/seeding.html b/database/seeding.html index 9a4bfe1d7..b96d1c4ac 100644 --- a/database/seeding.html +++ b/database/seeding.html @@ -14,7 +14,7 @@ - + diff --git a/dependencies.html b/dependencies.html index 3ce7d301e..23e88690e 100644 --- a/dependencies.html +++ b/dependencies.html @@ -14,7 +14,7 @@ - + diff --git a/features-summary.html b/features-summary.html index 6612fe9da..37039f05a 100644 --- a/features-summary.html +++ b/features-summary.html @@ -14,7 +14,7 @@ - + diff --git a/index.html b/index.html index 9683e6904..6229f2fa1 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@ - + diff --git a/search.html b/search.html index d3ebecca6..a0c33f408 100644 --- a/search.html +++ b/search.html @@ -14,7 +14,7 @@ - + diff --git a/sponsors.html b/sponsors.html index 1151abcc9..f4f4edb97 100644 --- a/sponsors.html +++ b/sponsors.html @@ -14,7 +14,7 @@ - + diff --git a/stability.html b/stability.html index 123a096b6..b85d8c1b5 100644 --- a/stability.html +++ b/stability.html @@ -14,7 +14,7 @@ - + diff --git a/supported-compilers.html b/supported-compilers.html index 369876b60..0f02c884e 100644 --- a/supported-compilers.html +++ b/supported-compilers.html @@ -14,7 +14,7 @@ - + diff --git a/tinydrivers/getting-started.html b/tinydrivers/getting-started.html index f44f6ca9a..90170d85d 100644 --- a/tinydrivers/getting-started.html +++ b/tinydrivers/getting-started.html @@ -14,7 +14,7 @@ - + diff --git a/tinyorm/casts.html b/tinyorm/casts.html index 8e3ea55ab..a169b3cf1 100644 --- a/tinyorm/casts.html +++ b/tinyorm/casts.html @@ -14,7 +14,7 @@ - + diff --git a/tinyorm/collections.html b/tinyorm/collections.html index 7ba3c8389..f6d677b75 100644 --- a/tinyorm/collections.html +++ b/tinyorm/collections.html @@ -14,7 +14,7 @@ - + @@ -107,6 +107,6 @@

Avai whereNotNull whereNull

note

For a better understanding of the following examples, many of the variable declarations below use actual types instead of the auto keyword.

-

all()

The all method returns a copy of the underlying vector represented by the collection:

QList<User> = users.all();
note

The toBase is an alias to the all method.

contains()

The contains method may be used to determine if a given model instance is contained by the collection. This method accepts a primary key or a model instance:

users.contains(1);

users.contains(User::find(1));

Alternatively, you may pass a lambda expression to the contains method to determine if a model exists in the collection matching a given truth test:

users.contains([](const User *const user)
{
return user->getKeyCasted() == 2;
});

For the inverse of contains, see the doesntContain method.

doesntContain()

The doesntContain method determines whether the collection does not contain a given item. This method accepts a primary key or a model instance:

users.doesntContain(1);

users.doesntContain(User::find(1));

Alternatively, you may pass a lambda expression to the doesntContain method to determine if a model does not exist in the collection matching a given truth test:

users.doesntContain([](const User *const user)
{
return user->getKeyCasted() == 2;
});

For the inverse of doesntContain, see the contains method.

each()

The each method iterates over the models in the collection and passes each model to the lambda expression:

ModelsCollection<User> users = Post::whereEq("user_id", 1)->get();

users.each([](User *const user)
{
// ...
});

If you would like to stop iterating through the models, you may return false from your lambda expression:

users.each([](User *const user)
{
if (/* condition */)
return false;

// Some logic

return true;
});

You may also pass the lambda expression with two parameters, whereas the second one is an index:

users.each([](User *const user, const std::size_t index)
{
// ...
});

The each method returns an lvalue reference to the currently processed collection.

It can be also called on ModelsCollection rvalues, it returns an rvalue reference in this case.

except()

The except method returns all of the models that do not have the given primary keys:

ModelsCollection<User *> usersResult = users.except({1, 2, 3});

All of the models are returned if the ids argument is empty except({}).

The order of models in the collection is preserved.

For the inverse of except, see the only method.

filter()

The filter method filters the collection using the lambda expression, keeping only those models that pass a given truth test:

auto usersBanned = users.filter([](const User *const user)
{
return user->getAttribute<bool>("is_banned");
});

You may also pass the lambda expression with two parameters, whereas the second one is an index:

auto usersBanned = users.filter([](const User *const user,
const std::size_t index)
{
return index < 10 && user->getAttribute<bool>("is_banned");
});

If no lambda expression is supplied, all models of the collection that are equivalent to the nullptr will be removed:

ModelsCollection<User> usersRaw = User::findMany({1, 2});
ModelsCollection<User *> users {&usersRaw[0], nullptr, &usersRaw[1]};

ModelsCollection<User *> filtered = users.filter();

// {1, 2}

For the inverse of filter, see the reject method.

find()

The find method returns the model that has a primary key matching the given key:

User *const user = users.find(1);

If you pass a model instance, find will attempt to return a model matching the primary key:

User *user = users.find(anotherUser);

The two overloads above also accept the second defaultModel model argument, which will be returned if a model was not found in the collection, its default value is the nullptr.

Alternatively, may pass more IDs and find will return all models which have a primary key within the given unordered set:

ModelsCollection<User *> usersMany = users.find({1, 2});

This overload internally calls the only method.

first()

The first method returns the first model in the collection that passes a given truth test:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

User *user = users.first([](User *const user)
{
return user->getAttribute<quint64>("votes") > 150;
});

// {{"name", "John"}, {"votes", 200}}

If no model passes a given truth test then the value of the second defaultModel argument will be returned, its default value is the nullptr.

using NullVariant = Orm::Utils::NullVariant;

User defaultUser {{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}};

User *user = users.first([](User *const user)
{
return user->getAttribute<quint64>("votes") > 500;
},
&defaultUser);

/*
{{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}}
*/

You can also call all first overloads provided by the QList::first.

firstWhere()

The firstWhere method returns the first model in the collection with the given column / value pair:

using NullVariant = Orm::Utils::NullVariant;

ModelsCollection<User> users {
{{"name", "Leon"}, {"age", NullVariant::UShort()}},
{{"name", "Jill"}, {"age", 14}},
{{"name", "Jack"}, {"age", 23}},
{{"name", "Jill"}, {"age", 84}},
};

auto user = users.firstWhereEq("name", "Linda");

// {{"name", "Jill"}, {"age", 14}}

You may also call the firstWhere method with a comparison operator:

users.firstWhere("age", ">=", 18);

// {{"name", "Jack"}, {"age", 23}}

fresh()

The fresh method retrieves a fresh instance of each model in the collection from the database. In addition, any specified relationships will be eager loaded:

auto usersFresh = users.fresh();

auto usersFresh = users.fresh("comments");

auto usersFresh = users.fresh("posts:id,name");

auto usersFresh = users.fresh({"comments", "posts:id,name"});

The relations argument format is the same as for TinyBuilder's load method.

implode()

The implode method joins attributes by the given column and the "glue" string you wish to place between the values:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
};

products.implode("product", ", ");

// {Desk, Chair}

The default "glue" value is an empty string "".

isEmpty()

The isEmpty method returns true if the collection is empty; otherwise, false is returned:

ModelsCollection<User>().isEmpty();

// true

isNotEmpty()

The isNotEmpty method returns true if the collection is not empty; otherwise, false is returned:

ModelsCollection<User>().isNotEmpty();

// false

last()

The last method returns the last model in the collection that passes a given truth test:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
{{"name", "Rose"}, {"votes", 350}},
};

User *user = users.last([](User *const user)
{
return user->getAttribute<quint64>("votes") < 300;
});

// {{"name", "John"}, {"votes", 200}}

If no model passes a given truth test then the value of the second defaultModel argument will be returned, its default value is the nullptr.

using NullVariant = Orm::Utils::NullVariant;

User defaultUser {{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}};

User *user = users.last([](User *const user)
{
return user->getAttribute<quint64>("votes") < 100;
},
&defaultUser);

/*
{{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}}
*/

You can also call all last overloads provided by the QList::last.

load()

The load method eager loads the given relationships for all models in the collection:

users.load({"comments", "posts"});

users.load("comments.author");

users.load({{"comments"}, {"posts", [](auto &query)
{
query.whereEq("active", true);
}}});

The relations argument format is the same as for TinyBuilder's load method.

map()

The map method iterates through the collection and passes a copy of each model to the given lambda expression. The lambda expression is free to modify the model and return it, thus forming a new collection of modified models:

ModelsCollection<User> users {
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

auto usersAdded = users.map([](User &&userCopy)
{
if (userCopy.getAttribute<QString>("name") == "John")
userCopy["votes"] = userCopy.getAttribute<quint64>("votes") + 1;

return std::move(userCopy);
});

/*
{
{{"name", "John"}, {"price", 201}},
{{"name", "Jack"}, {"price", 400}},
}
*/

The second map overload allows to return the QList<T>:

QList<quint64> usersAdded = users.map<quint64>([](User &&userCopy)
{
const auto votesRef = userCopy["votes"];

if (userCopy.getAttribute<QString>("name") == "John")
votesRef = userCopy.getAttribute<quint64>("votes") + 1;

return votesRef->value<quint64>();
});

// {201, 400}

Both overloads allow to pass the lambda expression with two arguments, whereas the second argument can be an index of the std::size_t type.

caution

Like most other collection methods, map returns a new collection instance; it does not modify the collection it is called on. If you want to modify the original collection in place, use the each method.

info

The model copy is passed to the lambda expression even if the map iterates over a collection of model pointers ModelsCollection<Model *>. The models are dereferenced behind the scene.

mapWithKeys()

The mapWithKeys method iterates through the collection and passes each model to the given lambda expression. It returns the std::unordered_map<K, V> and the lambda expression should return the std::pair<K, V> containing a single column / value pair:

ModelsCollection<User> users {
{{"id", 1}, {"name", "John"}, {"email", "john@example.com"}},
{{"id", 2}, {"name", "Jill"}, {"email", "jill@example.com"}},
};

auto usersMap = users.mapWithKeys<quint64, QString>(
[](User *const user) -> std::pair<quint64, QString>
{
return {user->getKeyCasted(), user->getAttribute<QString>("name")};
});

// {{1, 'John'}, {2, 'Jill'}}

You can also map IDs to the model pointers:

auto usersMap = users.mapWithKeys<quint64, User *>(
[](User *const user) -> std::pair<quint64, User *>
{
return {user->getKeyCasted(), user};
});

mapWithModelKeys()

The mapWithModelKeys maps the primary keys to the Model *, it returns the std::unordered_map<Model::KeyType, Model *>:

auto usersMap = users.mapWithModelKeys();

modelKeys()

The modelKeys method returns the primary keys for all models in the collection:

ModelsCollection<User> users {
{{"id", 1}, {"name", "John"}},
{{"id", 2}, {"name", "Jill"}},
{{"id", 3}, {"name", "Kate"}},
{{"id", 5}, {"name", "Rose"}},
};

users.modelKeys(); // Returns QList<QVariant>
users.modelKeys<quint64>();

// {1, 2, 3, 5}

only()

The only method returns all of the models that have the given primary keys:

ModelsCollection<User *> usersResult = users.only({1, 2, 3});

An empty collection is returned if the ids argument is empty only({}).

The order of models in the collection is preserved.

For the inverse of only, see the except method.

pluck()

The pluck method retrieves all of the values for a given column, the following overload returns the QList<QVariant>:

ModelsCollection<Product> products {
{{"id", 1}, {"name", "Desk"}},
{{"id", 2}, {"name", "Chair"}},
};

auto plucked = products.pluck("name");

// {Desk, Chair}

The second overload allows returning the custom type QList<T>:

auto plucked = products.pluck<QString>("name");

You may also specify how you wish the resulting collection to be keyed, this overload returns the std::map<T, QVariant>:

auto plucked = products.pluck<quint64>("name", "id");

// {{1, "Desk"}, {2, "Chair"}}

If duplicate keys exist, the last matching attribute will be inserted into the plucked collection:

ModelsCollection<Product> collection {
{{"brand", "Tesla"}, {"color", "red"}},
{{"brand", "Pagani"}, {"color", "white"}},
{{"brand", "Tesla"}, {"color", "black"}},
{{"brand", "Pagani"}, {"color", "orange"}},
};

auto plucked = collection.pluck<QString>("color", "brand");

// {{'Tesla', 'black'}, {'Pagani', 'orange"}}

reject()

The reject method filters the collection using the given lambda expression. The lambda should return true if the model should be removed from the resulting collection:

auto usersWithNote = users.reject([](const User *const user)
{
return user->getAttribute("note").isNull();
});

You may also pass the lambda expression with two arguments, whereas the second argument can be an index of the std::size_t type.

For the inverse of the reject method, see the filter method.

sort()

The sort method sorts the models collection by primary keys:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto sorted = users.sort();

/*
{
{{"id", 1}, {"name", "Jack"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
}
*/

You may pass a predicate and projection callbacks to the sort method with your own algorithms. Refer to the CPP reference documentation on ranges::sort, which is what the sort method calls internally.

You can eg. sort by multiple columns, for an alternative method of multi-column sorting look at sortBy:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 350}},
{{"name", "John"}, {"votes", 200}},
{{"name", "John"}, {"votes", 150}},
{{"name", "Kate"}, {"votes", 200}},
};

auto sorted = users.sort([](const User *const left,
const User *const right)
{
const auto leftValue = left->getAttribute<QString>("name");
const auto rightValue = right->getAttribute<QString>("name");

if (leftValue == rightValue)
return left->getAttribute<quint64>("votes") <
right->getAttribute<quint64>("votes");

return leftValue < rightValue;
});

/*
{
{{"name", "John"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Kate"}, {"votes", 200}},
{{"name", "Kate"}, {"votes", 350}},
}
*/

The order of equal elements is not guaranteed to be preserved.

info

You can use the stable sort method variants to preserve the order of equal models.

sortBy()

The sortBy method sorts the collection by the given column, this overload needs the template argument so it can cast the attribute value before comparing:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

auto sorted = users.sortBy<QString>("name");

/*
{
{{"name", "Jack"}, {"votes", 400}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Kate"}, {"votes", 150}},
}
*/

You may pass the projection callback to determine how to sort the collection's models:

auto sorted = users.sortBy([](User *const user)
{
return user->getAttribute<quint64>("votes");
});

/*
{
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
}
*/

If you would like to sort your collection by multiple columns, you may pass a vector of comparison lambda expressions that define each sort operation to the sortBy method, in the following example is the name column sorted in ascending order and the second votes column is sorted in descending order:

using AttributeUtils = Orm::Tiny::Utils::Attribute;

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 350}},
{{"name", "John"}, {"votes", 200}},
{{"name", "John"}, {"votes", 150}},
{{"name", "Kate"}, {"votes", 200}},
};

auto sorted = users.sortBy({
[](const User *const left, const User *const right)
{
return AttributeUtils::compareForSortBy(
left->getAttribute<QString>("name"),
right->getAttribute<QString>("name"));
},
[](const User *const left, const User *const right)
{
return AttributeUtils::compareForSortByDesc(
left->getAttribute<quint64>("votes"),
right->getAttribute<quint64>("votes"));
},
});

/*
{
{{"name", "John"}, {"votes", 200}},
{{"name", "John"}, {"votes", 150}},
{{"name", "Kate"}, {"votes", 350}},
{{"name", "Kate"}, {"votes", 200}},
}
*/

The AttributeUtils::compareForSortBy and compareForSortByDesc methods are helper methods, they are needed because the Qt framework doesn't define <=> spaceship operator on its types, it doesn't support the three-way comparison.

The order of equal elements is not guaranteed to be preserved.

sortByDesc()

This method has the same signature as the sortBy method but will sort the collection in the opposite order.

The order of equal elements is not guaranteed to be preserved.

sortDesc()

This method will sort the collection in the opposite order as the sort method:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto sorted = users.sortDesc();

/*
{
{{"id", 3}, {"name", "John"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
}
*/

The order of equal elements is not guaranteed to be preserved.

stableSort()

This method has the same signature as the sort method but will preserve the order of equal elements (guaranteed to be preserved).

stableSortBy()

This method has the same signature as the sortBy method but will preserve the order of equal elements (guaranteed to be preserved).

stableSortByDesc()

This method has the same signature as the sortByDesc method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved).

stableSortDesc()

This method has the same signature as the sortDesc method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved).

tap()

The tap method passes a collection to the given lambda expression, allowing you to "tap" into the collection at a specific point and do something with the models while not affecting the collection itself:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

users.sort()
.tap([](/*const */ModelsCollection<User *> &usersRef)
{
qDebug() << "IDs after sorting:"
<< usersRef.template modelKeys<quint64>();
})
.value<quint64>("id");

// 1

The tap method returns an lvalue reference to the currently processed collection.

It can be also called on ModelsCollection rvalues, it returns an rvalue reference in this case.

toBase()

The toBase method returns a copy of the underlying vector represented by the collection:

QList<User> = users.toBase();
note

The toBase is an alias to the all method.

toJson()

The toJson method converts the collection of models with all nested relations into a JSON serialized QByteArray.

It returns an empty array for empty many type relations and null for empty one type relations.

info

The toJson method accepts the QJsonDocument::JsonFormat, possible values are QJsonDocument::Indented or QJsonDocument::Compact.

toJsonArray()

The toJsonArray method converts the collection of models with all nested relations into a QJsonArray.

toJsonDocument()

The toJsonDocument method converts the collection of models with all nested relations into a QJsonDocument.

toMap()

The toMap method converts the collection of models with all nested relations into an attributes map QList<QVariantMap>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

toMapVariantList()

The toMapVariantList method converts the collection of models with all nested relations into an attributes map, but it returns the QVariantList instead of the QList<QVariantMap>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

note

The toMapVariantList method is internally needed by the toJson related methods.

toQuery()

The toQuery method returns the TinyBuilder instance containing a whereIn constraint with the collection of models' primary keys:

using Models::User;

ModelsCollection<User> users = User::whereEq("status", "VIP")->get();

users.toQuery()->update({
{"status", "Administrator"},
});

toList()

The toList method converts the collection of models with all nested relations into an attributes vector QList<QList<AttributeItem>>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

toListVariantList()

The toListVariantList method converts the collection of models with all nested relations into an attributes vector, but it returns the QVariantList instead of the QList<QList<AttributeItem>>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

note

The toListVariantList method is internally needed by the toJson related methods.

unique()

The unique method returns all of the unique models in the sorted collection. Any models with the same primary key as another model in the collection are removed:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto unique = users.unique();

/*
{
{{"id", 1}, {"name", "Jack"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
}
*/

It sorts the collection internally because the ranges::unique can correctly operate only on the sorted container. You can disable it by passing false using the first sort parameter:

auto unique = users.sort().unique(false);

/*
{
{{"id", 1}, {"name", "Jack"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
}
*/

uniqueBy()

The uniqueBy method returns all of the unique models in the sorted collection by the given column. Any models with the same column value as another model in the collection are removed. It needs the template argument, so it can cast the attribute value before comparing:

ModelsCollection<User> users {
{{"name", "Kate"}},
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Jack"}},
};

auto unique = users.uniqueBy<QString>("name");

/*
{
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Kate"}},
}
*/

It sorts the collection internally because the ranges::unique can correctly operate only on the sorted container. You can disable it by passing false using the second sort parameter:

auto unique = users.sortBy<QString>("name")
.uniqueBy<QString>("name", false);

/*
{
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Kate"}},
}
*/

uniqueRelaxed()

The uniqueRelaxed method returns all of the unique models in the collection, it doesn't need a sorted collection. Any models with the same primary key as another model in the collection are removed:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto unique = users.uniqueRelaxed();

/*
{
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
{{"id", 3}, {"name", "John"}},
}
*/

uniqueRelaxedBy()

The uniqueRelaxedBy method returns all of the unique models in the collection by the given column, it doesn't need a sorted collection, but it needs the template argument, so it can cast the attribute value before comparing:

ModelsCollection<User> users {
{{"name", "Kate"}},
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Jack"}},
};

auto unique = users.uniqueRelaxedBy<QString>("name");

/*
{
{{"name", "Kate"}},
{{"name", "Jack"}},
{{"name", "John"}},
}
*/

value()

The value method retrieves a given value from the first model of the collection:

ModelsCollection<User> users {
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

QVariant votes = users.value("votes");

// 200

Alternatively, you can cast an obtained QVariant value to the given type by the second value overload:

quint64 votes = users.value<quint64>("votes");

The value method also accepts the second defaultValue argument, which will be returned if a collection is empty, the first model is nullptr, or a model doesn't contain the given column:

auto votes = ModelsCollection<User>().value("votes", 0);

// 0

You can also call all value overloads provided by the QList::value.

where()

The where method filters the collection by a given column / value pair:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 100}},
};

auto filtered = products.where("price", "=", 100);

/*
{
{{"product", "Chair"}, {"price", 100}},
{{"product", "Door"}, {"price", 100}},
}
*/

For convenience, if you want to verify that a column is = to a given value, you may call whereEq method. Similar XxxEq methods are also defined for other commands:

auto filtered = products.whereEq("price", 100);

Optionally, you may pass a comparison operator as the second argument.
Supported operators are =, !=, <, >, <=, and >=:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
};

auto filtered = products.where("price", ">", 150);

/*
{
{{"product", "Desk"}, {"price", 200}},
{{"product", "Door"}, {"price", 250}},
}
*/

whereBetween()

The whereBetween method filters the collection by determining if a specified models' attribute value is within a given range:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 80}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Pencil"}, {"price", 30}},
{{"product", "Door"}, {"price", 100}},
};

auto filtered = products.whereBetween<quint64>("price", {100, 200});

/*
{
{{"product", "Desk"}, {"price", 200}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 100}},
}
*/

whereIn()

The whereIn method filters models from the collection that have a specified attribute value that is contained within the given unordered set:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
};

auto filtered = products.whereIn<quint64>("price", {100, 200});

/*
{
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
}
*/

An empty collection is returned if the values argument is empty whereIn("price", {}).

The order of models in the collection is preserved.

whereNotBetween()

The whereNotBetween method filters the collection by determining if a specified models' attribute value is outside of a given range:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 80}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Pencil"}, {"price", 30}},
{{"product", "Door"}, {"price", 100}},
};

auto filtered = products.whereNotBetween<quint64>("price", {100, 200});

/*
{
{{"product", "Chair"}, {"price", 80}},
{{"product", "Pencil"}, {"price", 30}},
}
*/

whereNotIn()

The whereNotIn method removes models from the collection that have a specified attribute value that is contained within the given unordered set:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
};

auto filtered = products.whereNotIn<quint64>("price", {100, 200});

/*
{
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
}
*/

All of the models are returned if the values argument is empty whereNotIn("price", {}).

The order of models in the collection is preserved.

whereNotNull()

The whereNotNull method returns models from the collection where the given column is not null QVariant:

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

ModelsCollection<User> users {
{{"name", "John"}},
{{"name", NullVariant::QString()}},
{{"name", "Jack"}},
};

auto filtered = users.whereNotNull("name");

/*
{
{{"name", "John"}},
{{"name", "Jack"}},
}
*/
note

The NullVariant class returns the correct null QVariant for both Qt 5 QVariant(QVariant::String) and also Qt 6 QVariant(QMetaType(QMetaType::QString)).

whereNull()

The whereNull method returns models from the collection where the given column is null QVariant:

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

ModelsCollection<User> users {
{{"name", "John"}},
{{"name", NullVariant::QString()}},
{{"name", "Jack"}},
};

auto filtered = users.whereNotNull("name");

// {{"name", NullVariant::QString()}}
note

The NullVariant class returns the correct null QVariant for both Qt 5 QVariant(QVariant::String) and also Qt 6 QVariant(QMetaType(QMetaType::QString)).

+

all()

The all method returns a copy of the underlying vector represented by the collection:

QList<User> = users.all();
note

The toBase is an alias to the all method.

contains()

The contains method may be used to determine if a given model instance is contained by the collection. This method accepts a primary key or a model instance:

users.contains(1);

users.contains(User::find(1));

Alternatively, you may pass a lambda expression to the contains method to determine if a model exists in the collection matching a given truth test:

users.contains([](const User *const user)
{
return user->getKeyCasted() == 2;
});

For the inverse of contains, see the doesntContain method.

doesntContain()

The doesntContain method determines whether the collection does not contain a given item. This method accepts a primary key or a model instance:

users.doesntContain(1);

users.doesntContain(User::find(1));

Alternatively, you may pass a lambda expression to the doesntContain method to determine if a model does not exist in the collection matching a given truth test:

users.doesntContain([](const User *const user)
{
return user->getKeyCasted() == 2;
});

For the inverse of doesntContain, see the contains method.

each()

The each method iterates over the models in the collection and passes each model to the lambda expression:

ModelsCollection<User> users = Post::whereEq("user_id", 1)->get();

users.each([](User *const user)
{
// ...
});

If you would like to stop iterating through the models, you may return false from your lambda expression:

users.each([](User *const user)
{
if (/* condition */)
return false;

// Some logic

return true;
});

You may also pass the lambda expression with two parameters, whereas the second one is an index:

users.each([](User *const user, const std::size_t index)
{
// ...
});

The each method returns an lvalue reference to the currently processed collection.

It can be also called on ModelsCollection rvalues, it returns an rvalue reference in this case.

except()

The except method returns all of the models that do not have the given primary keys:

ModelsCollection<User *> usersResult = users.except({1, 2, 3});

All of the models are returned if the ids argument is empty except({}).

The order of models in the collection is preserved.

For the inverse of except, see the only method.

filter()

The filter method filters the collection using the lambda expression, keeping only those models that pass a given truth test:

auto usersBanned = users.filter([](const User *const user)
{
return user->getAttribute<bool>("is_banned");
});

You may also pass the lambda expression with two parameters, whereas the second one is an index:

auto usersBanned = users.filter([](const User *const user,
const std::size_t index)
{
return index < 10 && user->getAttribute<bool>("is_banned");
});

If no lambda expression is supplied, all models of the collection that are equivalent to the nullptr will be removed:

ModelsCollection<User> usersRaw = User::findMany({1, 2});
ModelsCollection<User *> users {&usersRaw[0], nullptr, &usersRaw[1]};

ModelsCollection<User *> filtered = users.filter();

// {1, 2}

For the inverse of filter, see the reject method.

find()

The find method returns the model that has a primary key matching the given key:

User *const user = users.find(1);

If you pass a model instance, find will attempt to return a model matching the primary key:

User *user = users.find(anotherUser);

The two overloads above also accept the second defaultModel model argument, which will be returned if a model was not found in the collection, its default value is the nullptr.

Alternatively, may pass more IDs and find will return all models which have a primary key within the given unordered set:

ModelsCollection<User *> usersMany = users.find({1, 2});

This overload internally calls the only method.

first()

The first method returns the first model in the collection that passes a given truth test:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

User *user = users.first([](User *const user)
{
return user->getAttribute<quint64>("votes") > 150;
});

// {{"name", "John"}, {"votes", 200}}

If no model passes a given truth test then the value of the second defaultModel argument will be returned, its default value is the nullptr.

using NullVariant = Orm::Utils::NullVariant;

User defaultUser {{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}};

User *user = users.first([](User *const user)
{
return user->getAttribute<quint64>("votes") > 500;
},
&defaultUser);

/*
{{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}}
*/

You can also call all first overloads provided by the QList::first.

firstWhere()

The firstWhere method returns the first model in the collection with the given column / value pair:

using NullVariant = Orm::Utils::NullVariant;

ModelsCollection<User> users {
{{"name", "Leon"}, {"age", NullVariant::UShort()}},
{{"name", "Jill"}, {"age", 14}},
{{"name", "Jack"}, {"age", 23}},
{{"name", "Jill"}, {"age", 84}},
};

auto user = users.firstWhereEq("name", "Linda");

// {{"name", "Jill"}, {"age", 14}}

You may also call the firstWhere method with a comparison operator:

users.firstWhere("age", ">=", 18);

// {{"name", "Jack"}, {"age", 23}}

fresh()

The fresh method retrieves a fresh instance of each model in the collection from the database. In addition, any specified relationships will be eager loaded:

auto usersFresh = users.fresh();

auto usersFresh = users.fresh("comments");

auto usersFresh = users.fresh("posts:id,name");

auto usersFresh = users.fresh({"comments", "posts:id,name"});

The relations argument format is the same as for TinyBuilder's load method.

implode()

The implode method joins attributes by the given column and the "glue" string you wish to place between the values:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
};

products.implode("product", ", ");

// {Desk, Chair}

The default "glue" value is an empty string "".

isEmpty()

The isEmpty method returns true if the collection is empty; otherwise, false is returned:

ModelsCollection<User>().isEmpty();

// true

isNotEmpty()

The isNotEmpty method returns true if the collection is not empty; otherwise, false is returned:

ModelsCollection<User>().isNotEmpty();

// false

last()

The last method returns the last model in the collection that passes a given truth test:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
{{"name", "Rose"}, {"votes", 350}},
};

User *user = users.last([](User *const user)
{
return user->getAttribute<quint64>("votes") < 300;
});

// {{"name", "John"}, {"votes", 200}}

If no model passes a given truth test then the value of the second defaultModel argument will be returned, its default value is the nullptr.

using NullVariant = Orm::Utils::NullVariant;

User defaultUser {{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}};

User *user = users.last([](User *const user)
{
return user->getAttribute<quint64>("votes") < 100;
},
&defaultUser);

/*
{{"name", NullVariant::QString()},
{"votes", NullVariant::ULongLong()}}
*/

You can also call all last overloads provided by the QList::last.

load()

The load method eager loads the given relationships for all models in the collection:

users.load({"comments", "posts"});

users.load("comments.author");

users.load({{"comments"}, {"posts", [](auto &query)
{
query.whereEq("active", true);
}}});

The relations argument format is the same as for TinyBuilder's load method.

map()

The map method iterates through the collection and passes a copy of each model to the given lambda expression. The lambda expression is free to modify the model and return it, thus forming a new collection of modified models:

ModelsCollection<User> users {
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

auto usersAdded = users.map([](User &&userCopy)
{
if (userCopy.getAttribute<QString>("name") == "John")
userCopy["votes"] = userCopy.getAttribute<quint64>("votes") + 1;

return std::move(userCopy);
});

/*
{
{{"name", "John"}, {"price", 201}},
{{"name", "Jack"}, {"price", 400}},
}
*/

The second map overload allows to return the QList<T>:

QList<quint64> usersAdded = users.map<quint64>([](User &&userCopy)
{
const auto votesRef = userCopy["votes"];

if (userCopy.getAttribute<QString>("name") == "John")
votesRef = userCopy.getAttribute<quint64>("votes") + 1;

return votesRef->value<quint64>();
});

// {201, 400}

Both overloads allow to pass the lambda expression with two arguments, whereas the second argument can be an index of the std::size_t type.

caution

Like most other collection methods, map returns a new collection instance; it does not modify the collection it is called on. If you want to modify the original collection in place, use the each method.

info

The model copy is passed to the lambda expression even if the map iterates over a collection of model pointers ModelsCollection<Model *>. The models are dereferenced behind the scene.

mapWithKeys()

The mapWithKeys method iterates through the collection and passes each model to the given lambda expression. It returns the std::unordered_map<K, V> and the lambda expression should return the std::pair<K, V> containing a single column / value pair:

ModelsCollection<User> users {
{{"id", 1}, {"name", "John"}, {"email", "john@example.com"}},
{{"id", 2}, {"name", "Jill"}, {"email", "jill@example.com"}},
};

auto usersMap = users.mapWithKeys<quint64, QString>(
[](User *const user) -> std::pair<quint64, QString>
{
return {user->getKeyCasted(), user->getAttribute<QString>("name")};
});

// {{1, 'John'}, {2, 'Jill'}}

You can also map IDs to the model pointers:

auto usersMap = users.mapWithKeys<quint64, User *>(
[](User *const user) -> std::pair<quint64, User *>
{
return {user->getKeyCasted(), user};
});

mapWithModelKeys()

The mapWithModelKeys maps the primary keys to the Model *, it returns the std::unordered_map<Model::KeyType, Model *>:

auto usersMap = users.mapWithModelKeys();

modelKeys()

The modelKeys method returns the primary keys for all models in the collection:

ModelsCollection<User> users {
{{"id", 1}, {"name", "John"}},
{{"id", 2}, {"name", "Jill"}},
{{"id", 3}, {"name", "Kate"}},
{{"id", 5}, {"name", "Rose"}},
};

users.modelKeys(); // Returns QList<QVariant>
users.modelKeys<quint64>();

// {1, 2, 3, 5}

only()

The only method returns all of the models that have the given primary keys:

ModelsCollection<User *> usersResult = users.only({1, 2, 3});

An empty collection is returned if the ids argument is empty only({}).

The order of models in the collection is preserved.

For the inverse of only, see the except method.

pluck()

The pluck method retrieves all of the values for a given column, the following overload returns the QList<QVariant>:

ModelsCollection<Product> products {
{{"id", 1}, {"name", "Desk"}},
{{"id", 2}, {"name", "Chair"}},
};

auto plucked = products.pluck("name");

// {Desk, Chair}

The second overload allows returning the custom type QList<T>:

auto plucked = products.pluck<QString>("name");

You may also specify how you wish the resulting collection to be keyed, this overload returns the std::map<T, QVariant>:

auto plucked = products.pluck<quint64>("name", "id");

// {{1, "Desk"}, {2, "Chair"}}

If duplicate keys exist, the last matching attribute will be inserted into the plucked collection:

ModelsCollection<Product> collection {
{{"brand", "Tesla"}, {"color", "red"}},
{{"brand", "Pagani"}, {"color", "white"}},
{{"brand", "Tesla"}, {"color", "black"}},
{{"brand", "Pagani"}, {"color", "orange"}},
};

auto plucked = collection.pluck<QString>("color", "brand");

// {{'Tesla', 'black'}, {'Pagani', 'orange"}}

reject()

The reject method filters the collection using the given lambda expression. The lambda should return true if the model should be removed from the resulting collection:

auto usersWithNote = users.reject([](const User *const user)
{
return user->getAttribute("note").isNull();
});

You may also pass the lambda expression with two arguments, whereas the second argument can be an index of the std::size_t type.

For the inverse of the reject method, see the filter method.

sort()

The sort method sorts the models collection by primary keys:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto sorted = users.sort();

/*
{
{{"id", 1}, {"name", "Jack"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
}
*/

You may pass a predicate and projection callbacks to the sort method with your own algorithms. Refer to the CPP reference documentation on ranges::sort, which is what the sort method calls internally.

You can eg. sort by multiple columns, for an alternative method of multi-column sorting look at sortBy:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 350}},
{{"name", "John"}, {"votes", 200}},
{{"name", "John"}, {"votes", 150}},
{{"name", "Kate"}, {"votes", 200}},
};

auto sorted = users.sort([](const User *const left,
const User *const right)
{
const auto leftValue = left->getAttribute<QString>("name");
const auto rightValue = right->getAttribute<QString>("name");

if (leftValue == rightValue)
return left->getAttribute<quint64>("votes") <
right->getAttribute<quint64>("votes");

return leftValue < rightValue;
});

/*
{
{{"name", "John"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Kate"}, {"votes", 200}},
{{"name", "Kate"}, {"votes", 350}},
}
*/

The order of equal elements is not guaranteed to be preserved.

info

You can use the stable sort method variants to preserve the order of equal models.

sortBy()

The sortBy method sorts the collection by the given column, this overload needs the template argument so it can cast the attribute value before comparing:

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

auto sorted = users.sortBy<QString>("name");

/*
{
{{"name", "Jack"}, {"votes", 400}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Kate"}, {"votes", 150}},
}
*/

You may pass the projection callback to determine how to sort the collection's models:

auto sorted = users.sortBy([](User *const user)
{
return user->getAttribute<quint64>("votes");
});

/*
{
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
}
*/

If you would like to sort your collection by multiple columns, you may pass a vector of comparison lambda expressions that define each sort operation to the sortBy method, in the following example is the name column sorted in ascending order and the second votes column is sorted in descending order:

using AttributeUtils = Orm::Tiny::Utils::Attribute;

ModelsCollection<User> users {
{{"name", "Kate"}, {"votes", 350}},
{{"name", "John"}, {"votes", 200}},
{{"name", "John"}, {"votes", 150}},
{{"name", "Kate"}, {"votes", 200}},
};

auto sorted = users.sortBy({
[](const User *const left, const User *const right)
{
return AttributeUtils::compareForSortBy(
left->getAttribute<QString>("name"),
right->getAttribute<QString>("name"));
},
[](const User *const left, const User *const right)
{
return AttributeUtils::compareForSortByDesc(
left->getAttribute<quint64>("votes"),
right->getAttribute<quint64>("votes"));
},
});

/*
{
{{"name", "John"}, {"votes", 200}},
{{"name", "John"}, {"votes", 150}},
{{"name", "Kate"}, {"votes", 350}},
{{"name", "Kate"}, {"votes", 200}},
}
*/

The AttributeUtils::compareForSortBy and compareForSortByDesc methods are helper methods, they are needed because the Qt framework doesn't define <=> spaceship operator on its types, it doesn't support the three-way comparison.

The order of equal elements is not guaranteed to be preserved.

sortByDesc()

This method has the same signature as the sortBy method but will sort the collection in the opposite order.

The order of equal elements is not guaranteed to be preserved.

sortDesc()

This method will sort the collection in the opposite order as the sort method:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto sorted = users.sortDesc();

/*
{
{{"id", 3}, {"name", "John"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
}
*/

The order of equal elements is not guaranteed to be preserved.

stableSort()

This method has the same signature as the sort method but will preserve the order of equal elements (guaranteed to be preserved).

stableSortBy()

This method has the same signature as the sortBy method but will preserve the order of equal elements (guaranteed to be preserved).

stableSortByDesc()

This method has the same signature as the sortByDesc method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved).

stableSortDesc()

This method has the same signature as the sortDesc method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved).

tap()

The tap method passes a collection to the given lambda expression, allowing you to "tap" into the collection at a specific point and do something with the models while not affecting the collection itself:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

users.sort()
.tap([](/*const */ModelsCollection<User *> &usersRef)
{
qDebug() << "IDs after sorting:"
<< usersRef.template modelKeys<quint64>();
})
.value<quint64>("id");

// 1

The tap method returns an lvalue reference to the currently processed collection.

It can be also called on ModelsCollection rvalues, it returns an rvalue reference in this case.

toBase()

The toBase method returns a copy of the underlying vector represented by the collection:

QList<User> = users.toBase();
note

The toBase is an alias to the all method.

toJson()

The toJson method converts the collection of models with all nested relations into a JSON serialized QByteArray.

It returns an empty array for empty many type relations and null for empty one type relations.

info

The toJson method accepts the QJsonDocument::JsonFormat, possible values are QJsonDocument::Indented or QJsonDocument::Compact.

toJsonArray()

The toJsonArray method converts the collection of models with all nested relations into a QJsonArray.

toJsonDocument()

The toJsonDocument method converts the collection of models with all nested relations into a QJsonDocument.

toMap()

The toMap method converts the collection of models with all nested relations into an attributes map QList<QVariantMap>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

toMapVariantList()

The toMapVariantList method converts the collection of models with all nested relations into an attributes map, but it returns the QVariantList instead of the QList<QVariantMap>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

note

The toMapVariantList method is internally needed by the toJson related methods.

toQuery()

The toQuery method returns the TinyBuilder instance containing a whereIn constraint with the collection of models' primary keys:

using Models::User;

ModelsCollection<User> users = User::whereEq("status", "VIP")->get();

users.toQuery()->update({
{"status", "Administrator"},
});

toList()

The toList method converts the collection of models with all nested relations into an attributes vector QList<QList<AttributeItem>>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

toListVariantList()

The toListVariantList method converts the collection of models with all nested relations into an attributes vector, but it returns the QVariantList instead of the QList<QList<AttributeItem>>.

It returns an empty QVariantList for empty many type relations and a null QVariant for empty one type relations.

note

The toListVariantList method is internally needed by the toJson related methods.

unique()

The unique method returns all of the unique models in the sorted collection. Any models with the same primary key as another model in the collection are removed:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto unique = users.unique();

/*
{
{{"id", 1}, {"name", "Jack"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
}
*/

It sorts the collection internally because the ranges::unique can correctly operate only on the sorted container. You can disable it by passing false using the first sort parameter:

auto unique = users.sort().unique(false);

/*
{
{{"id", 1}, {"name", "Jack"}},
{{"id", 2}, {"name", "Kate"}},
{{"id", 3}, {"name", "John"}},
}
*/

uniqueBy()

The uniqueBy method returns all of the unique models in the sorted collection by the given column. Any models with the same column value as another model in the collection are removed. It needs the template argument, so it can cast the attribute value before comparing:

ModelsCollection<User> users {
{{"name", "Kate"}},
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Jack"}},
};

auto unique = users.uniqueBy<QString>("name");

/*
{
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Kate"}},
}
*/

It sorts the collection internally because the ranges::unique can correctly operate only on the sorted container. You can disable it by passing false using the second sort parameter:

auto unique = users.sortBy<QString>("name")
.uniqueBy<QString>("name", false);

/*
{
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Kate"}},
}
*/

uniqueRelaxed()

The uniqueRelaxed method returns all of the unique models in the collection, it doesn't need a sorted collection. Any models with the same primary key as another model in the collection are removed:

ModelsCollection<User> users {
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
{{"id", 3}, {"name", "John"}},
{{"id", 1}, {"name", "Jack"}},
};

auto unique = users.uniqueRelaxed();

/*
{
{{"id", 2}, {"name", "Kate"}},
{{"id", 1}, {"name", "Jack"}},
{{"id", 3}, {"name", "John"}},
}
*/

uniqueRelaxedBy()

The uniqueRelaxedBy method returns all of the unique models in the collection by the given column, it doesn't need a sorted collection, but it needs the template argument, so it can cast the attribute value before comparing:

ModelsCollection<User> users {
{{"name", "Kate"}},
{{"name", "Jack"}},
{{"name", "John"}},
{{"name", "Jack"}},
};

auto unique = users.uniqueRelaxedBy<QString>("name");

/*
{
{{"name", "Kate"}},
{{"name", "Jack"}},
{{"name", "John"}},
}
*/

value()

The value method retrieves a given value from the first model of the collection:

ModelsCollection<User> users {
{{"name", "John"}, {"votes", 200}},
{{"name", "Jack"}, {"votes", 400}},
};

QVariant votes = users.value("votes");

// 200

Alternatively, you can cast an obtained QVariant value to the given type by the second value overload:

quint64 votes = users.value<quint64>("votes");

The value method also accepts the second defaultValue argument, which will be returned if a collection is empty, the first model is nullptr, or a model doesn't contain the given column:

auto votes = ModelsCollection<User>().value("votes", 0);

// 0

You can also call all value overloads provided by the QList::value.

where()

The where method filters the collection by a given column / value pair:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 100}},
};

auto filtered = products.where("price", "=", 100);

/*
{
{{"product", "Chair"}, {"price", 100}},
{{"product", "Door"}, {"price", 100}},
}
*/

For convenience, if you want to verify that a column is = to a given value, you may call whereEq method. Similar XxxEq methods are also defined for other commands:

auto filtered = products.whereEq("price", 100);

Optionally, you may pass a comparison operator as the second argument.
Supported operators are =, !=, <, >, <=, and >=:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
};

auto filtered = products.where("price", ">", 150);

/*
{
{{"product", "Desk"}, {"price", 200}},
{{"product", "Door"}, {"price", 250}},
}
*/

whereBetween()

The whereBetween method filters the collection by determining if a specified models' attribute value is within a given range:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 80}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Pencil"}, {"price", 30}},
{{"product", "Door"}, {"price", 100}},
};

auto filtered = products.whereBetween<quint64>("price", {100, 200});

/*
{
{{"product", "Desk"}, {"price", 200}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 100}},
}
*/

whereIn()

The whereIn method filters models from the collection that have a specified attribute value that is contained within the given unordered set:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
};

auto filtered = products.whereIn<quint64>("price", {100, 200});

/*
{
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
}
*/

An empty collection is returned if the values argument is empty whereIn("price", {}).

The order of models in the collection is preserved.

whereNotBetween()

The whereNotBetween method filters the collection by determining if a specified models' attribute value is outside of a given range:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 80}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Pencil"}, {"price", 30}},
{{"product", "Door"}, {"price", 100}},
};

auto filtered = products.whereNotBetween<quint64>("price", {100, 200});

/*
{
{{"product", "Chair"}, {"price", 80}},
{{"product", "Pencil"}, {"price", 30}},
}
*/

whereNotIn()

The whereNotIn method removes models from the collection that have a specified attribute value that is contained within the given unordered set:

ModelsCollection<Product> products {
{{"product", "Desk"}, {"price", 200}},
{{"product", "Chair"}, {"price", 100}},
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
};

auto filtered = products.whereNotIn<quint64>("price", {100, 200});

/*
{
{{"product", "Bookcase"}, {"price", 150}},
{{"product", "Door"}, {"price", 250}},
}
*/

All of the models are returned if the values argument is empty whereNotIn("price", {}).

The order of models in the collection is preserved.

whereNotNull()

The whereNotNull method returns models from the collection where the given column is not null QVariant:

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

ModelsCollection<User> users {
{{"name", "John"}},
{{"name", NullVariant::QString()}},
{{"name", "Jack"}},
};

auto filtered = users.whereNotNull("name");

/*
{
{{"name", "John"}},
{{"name", "Jack"}},
}
*/
note

The NullVariant class returns the correct null QVariant for both Qt 5 QVariant(QVariant::String) and also Qt 6 QVariant(QMetaType(QMetaType::QString)). The reason why this class still exists even after Qt v5.15 support was removed is the performance boost.

whereNull()

The whereNull method returns models from the collection where the given column is null QVariant:

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

ModelsCollection<User> users {
{{"name", "John"}},
{{"name", NullVariant::QString()}},
{{"name", "Jack"}},
};

auto filtered = users.whereNotNull("name");

// {{"name", NullVariant::QString()}}
note

The NullVariant class returns the correct null QVariant for both Qt 5 QVariant(QVariant::String) and also Qt 6 QVariant(QMetaType(QMetaType::QString)). The reason why this class still exists even after Qt v5.15 support was removed is the performance boost.

\ No newline at end of file diff --git a/tinyorm/getting-started.html b/tinyorm/getting-started.html index 04a923c7e..409e5c715 100644 --- a/tinyorm/getting-started.html +++ b/tinyorm/getting-started.html @@ -14,7 +14,7 @@ - + diff --git a/tinyorm/relationships.html b/tinyorm/relationships.html index 5f89400e6..408bd1504 100644 --- a/tinyorm/relationships.html +++ b/tinyorm/relationships.html @@ -14,7 +14,7 @@ - + diff --git a/tinyorm/serialization.html b/tinyorm/serialization.html index e13fd1baa..19bd94c2a 100644 --- a/tinyorm/serialization.html +++ b/tinyorm/serialization.html @@ -14,7 +14,7 @@ - +