diff --git a/404.html b/404.html index f74d7a742..40bb9dace 100644 --- a/404.html +++ b/404.html @@ -14,7 +14,7 @@ - + diff --git a/assets/js/0ab078a9.d34f93c5.js b/assets/js/0ab078a9.5134d01b.js similarity index 99% rename from assets/js/0ab078a9.d34f93c5.js rename to assets/js/0ab078a9.5134d01b.js index 096d309ca..68c21d35a 100644 --- a/assets/js/0ab078a9.d34f93c5.js +++ b/assets/js/0ab078a9.5134d01b.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[395],{1503:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>O,contentTitle:()=>_,default:()=>I,frontMatter:()=>T,metadata:()=>v,toc:()=>R});var s=i(4848),d=i(8453),r=i(8774),l=i(6684),c=i(2364),t=i(9365),o=i(1470),a=i(5556),h=i.n(a),x=i(6694);function j(e){let{groupId:n}=e;return(0,s.jsx)("span",{children:(0,x.OZ)(n)})}j.propTypes={groupId:h().string.isRequired};const u=j;var p=i(4164),m=i(6362);const b={rootFolderInput:"rootFolderInput_ottS",input:"input_OR7e",application:"application_fjej"};function f(e){let{groupId:n,label:i}=e;const{rootFolder:d,setRootFolder:r}=(0,m.A)(),l=(0,x.T3)(n),c=l?"application":"root",t=l?"\nThis folder name is common for all shells (eg. pwsh, bash, ...)":"";return(0,s.jsx)("form",{name:"tinyorm-root-folder-form",className:(0,p.A)(b.rootFolderInput,b[n],n),onSubmit:e=>{e.preventDefault(),e.stopPropagation()},children:(0,s.jsx)("input",{name:"tinyorm-root-folder-input",className:(0,p.A)(b.input,b[n],n),placeholder:`Enter ${c} folder...`,title:`This ${c} folder will be used in all ${i} examples at tinyorm.org${t}`,onChange:e=>{r(n,e.target.value)},value:d[n]??(0,x.bw)(n)})})}f.propTypes={groupId:h().string.isRequired,label:h().string.isRequired};const g=f;var y=i(7324);const T={sidebar_position:0,sidebar_label:"TinyORM",hide_table_of_contents:!0,description:"How to compile the TinyORM C++ library on Windows and Linux.",keywords:["c++ orm","building","tinyorm"]},_="Building: TinyORM",v={id:"building/tinyorm",title:"Building: TinyORM",description:"How to compile the TinyORM C++ library on Windows and Linux.",source:"@site/docs/building/tinyorm.mdx",sourceDirName:"building",slug:"/building/tinyorm",permalink:"/building/tinyorm",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"TinyORM",hide_table_of_contents:!0,description:"How to compile the TinyORM C++ library on Windows and Linux.",keywords:["c++ orm","building","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Getting Started",permalink:"/tinydrivers/getting-started"},next:{title:"Hello world",permalink:"/building/hello-world"}},O={},R=[{value:"Introduction",id:"introduction",level:2},{value:"Common Prerequisites",id:"common-prerequisites",level:4},{value:"Windows Prerequisites",id:"windows-prerequisites",level:4},{value:"Build environment scripts",id:"build-environment-scripts",level:5},{value:"Allow symbolic links unprivileged",id:"allow-symbolic-links-unprivileged",level:5},{value:"Folders structure",id:"folders-structure",level:2},{value:"Getting started",id:"getting-started",level:2},{value:"vcpkg",id:"vcpkg",level:2},{value:"Set up vcpkg environment",id:"set-up-vcpkg-environment",level:4},{value:"C preprocessor macros",id:"c-preprocessor-macros",level:2},{value:"Building with CMake",id:"building-with-cmake",level:2},{value:"Configure & Build (cmake)",id:"configure-and-build-cmake",level:3},{value:"CMake STRICT_MODE option",id:"cmake-strict_mode-option",level:5},{value:"Build TinyORM",id:"build-tinyorm",level:4},{value:"CMake build options",id:"cmake-build-options",level:3},{value:"Consume TinyOrm library (cmake)",id:"consume-tinyorm-library-cmake",level:3},{value:"Building with qmake",id:"building-with-qmake",level:2},{value:"Install dependencies",id:"install-dependencies",level:3},{value:"Configure & Build (qmake)",id:"configure-and-build-qmake",level:3},{value:"Open QtCreator IDE",id:"open-qtcreator-ide",level:4},{value:"Configure TinyORM",id:"configure-tinyorm",level:4},{value:"Auto-configuration and tiny_dotenv",id:"auto-configuration-and-tiny_dotenv",level:5},{value:"Manual configuration (conf.pri)",id:"manual-configuration-confpri",level:5},{value:"Opening TinyORM.pro (main project file)",id:"opening-tinyormpro-main-project-file",level:5},{value:"Build TinyORM",id:"build-tinyorm-1",level:4},{value:"qmake build options",id:"qmake-build-options",level:3},{value:"Consume TinyOrm library (qmake)",id:"consume-tinyorm-library-qmake",level:3},{value:"Requirements",id:"requirements",level:4},{value:"QMAKEFEATURES",id:"qmakefeatures",level:5},{value:"Variables affecting TinyOrm.pri",id:"variables-affecting-tinyormpri",level:5},{value:"Manual configuration examples",id:"manual-configuration-examples",level:5},{value:"Auto-configuration internals",id:"auto-configuration-internals",level:3},{value:"Environment files",id:"environment-files",level:4},{value:"Partial guessing of the TINYORM_BUILD_TREE",id:"partial-guessing-of-the-tinyorm_build_tree",level:4},{value:"Manual configuration internals",id:"manual-configuration-internals",level:3},{value:"Ccache support",id:"ccache-support",level:2}];function M(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"building-tinyorm",children:"Building: TinyORM"}),"\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:"#common-prerequisites",children:"Common Prerequisites"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#windows-prerequisites",children:"Windows Prerequisites"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#folders-structure",children:"Folders structure"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#getting-started",children:"Getting started"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#vcpkg",children:"vcpkg"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#c-preprocessor-macros",children:"C preprocessor macros"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#building-with-cmake",children:"Building with CMake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#configure-and-build-cmake",children:"Configure & Build"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#cmake-build-options",children:"CMake build options"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#consume-tinyorm-library-cmake",children:"Consume TinyOrm library"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#building-with-qmake",children:"Building with qmake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#install-dependencies",children:"Install dependencies"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#configure-and-build-qmake",children:"Configure & Build"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#qmake-build-options",children:"qmake build options"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#consume-tinyorm-library-qmake",children:"Consume TinyOrm library"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:"Auto-configuration internals"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#environment-files",children:"Environment files"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#manual-configuration-internals",children:"Manual configuration internals"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#ccache-support",children:"Ccache support"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsxs)(n.p,{children:["The build systems supported out of the box are ",(0,s.jsx)(n.code,{children:"CMake"})," and ",(0,s.jsx)(n.code,{children:"qmake"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["All examples below assume that ",(0,s.jsx)(n.code,{children:"pwsh"})," runs on ",(0,s.jsx)(n.code,{children:"Windows"})," and ",(0,s.jsx)(n.code,{children:"bash"})," runs on ",(0,s.jsx)(n.code,{children:"Linux"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"common-prerequisites",children:"Common Prerequisites"}),"\n",(0,s.jsxs)(n.p,{children:["Install the required ",(0,s.jsx)(n.a,{href:"/dependencies",children:"dependencies"})," before starting."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"QSqlDatabase"})," depends on ",(0,s.jsx)(n.code,{children:"QCoreApplication"})," from ",(0,s.jsx)(n.code,{children:"Qt v6.5.3"})," so you must create the ",(0,s.jsx)(n.code,{children:"QCoreApplication"})," instance before you will call anything from the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. \ud83e\udee4 The change was made ",(0,s.jsx)(n.a,{href:"https://github.com/qt/qtbase/commit/8d2bdc9cd5482eace12ba7e45304857bd24db0e6#diff-1d355c25c0b0eddec2be48253407780c4dc510d986739aec61e1ec892ccaf86e",children:"here"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"windows-prerequisites",children:"Windows Prerequisites"}),"\n",(0,s.jsx)(n.h5,{id:"build-environment-scripts",children:"Build environment scripts"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Visual Studio"})," does not provide ",(0,s.jsx)(n.code,{children:"vcvars"})," scripts for ",(0,s.jsx)(n.code,{children:"pwsh"}),", you can use ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/tools/vcvars64.ps1",children:(0,s.jsx)(n.code,{children:"vcvars64.ps1"})})," provided by ",(0,s.jsx)(n.code,{children:"TinyORM"})," in the ",(0,s.jsx)(n.code,{children:"tools/"})," folder. Place them on the ",(0,s.jsx)(n.code,{children:"$env:Path"})," user/system path and they will be available system-wide."]}),"\n",(0,s.jsxs)(n.p,{children:["The same is true for the ",(0,s.jsx)(n.code,{children:"Qt Framework"}),", it doesn't provide ",(0,s.jsx)(n.code,{children:"qtenv"})," scripts for ",(0,s.jsx)(n.code,{children:"pwsh"})," too. You can create your own script, place it on the ",(0,s.jsx)(n.code,{children:"$env:Path"})," user/system path and it will be available system-wide."]}),"\n",(0,s.jsxs)(n.p,{children:["Here is one simple example for ",(0,s.jsx)(n.code,{children:"pwsh"}),"."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:"qtenv6.ps1",label:"qtenv6.ps1",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:"#!/usr/bin/env pwsh\n\nSet-StrictMode -Version 3.0\n\nWrite-Host 'Setting up environment for Qt 6.7.2 usage...' -ForegroundColor Magenta\nWrite-Host\n\n$Script:QtRoot = $env:TINY_QT_ROOT ?? 'C:\\Qt'\n\n$env:Path = \"$Script:QtRoot\\6.7.2\\msvc2019_64\\bin;\" + $env:Path\n\n. vcvars64.ps1\n"})})}),(0,s.jsx)(t.A,{value:"qtenv5.ps1",label:"qtenv5.ps1",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:"#!/usr/bin/env pwsh\n\nSet-StrictMode -Version 3.0\n\nWrite-Host 'Setting up environment for Qt 5.15.2 usage...' -ForegroundColor Magenta\nWrite-Host\n\n$Script:QtRoot = $env:TINY_QT_ROOT ?? 'C:\\Qt'\n\n$env:Path = \"$Script:QtRoot\\5.15.2\\msvc2019_64\\bin;\" + $env:Path\n\n. vcvars64.ps1\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["And here for ",(0,s.jsx)(n.code,{children:"Linux"}),"."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:"qtenv6",label:"qtenv6",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'#!/usr/bin/env sh\n\necho \'Setting up environment for Qt 6.7.2 usage...\'\n\nQtRoot="${TINY_QT_ROOT:-/opt/Qt}"\n\nexport PATH="$QtRoot/6.7.2/gcc_64/bin"${PATH:+:}$PATH\nexport LD_LIBRARY_PATH="$QtRoot/6.7.2/gcc_64/lib"${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH\n'})})}),(0,s.jsx)(t.A,{value:"qtenv5",label:"qtenv5",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'#!/usr/bin/env sh\n\necho \'Setting up environment for Qt 5.15.2 usage...\'\n\nQtRoot="${TINY_QT_ROOT:-/opt/Qt}"\n\nexport PATH="$QtRoot/5.15.2/gcc_64/bin"${PATH:+:}$PATH\nexport LD_LIBRARY_PATH="$QtRoot/5.15.2/gcc_64/lib"${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH\n'})})})]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["These scripts consider the ",(0,s.jsx)(n.code,{children:"TINY_QT_ROOT"})," environment variable that should point to the ",(0,s.jsx)(n.code,{children:"Qt"})," installation folder, you can define this environment variable globally in your OS."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can't execute these ",(0,s.jsx)(n.code,{children:"qtenvX"})," scripts, they have to be sourced like ",(0,s.jsx)(n.code,{children:"source qtenvX"})," or ",(0,s.jsx)(n.code,{children:". qtenvX"}),"."]})}),"\n",(0,s.jsx)(n.h5,{id:"allow-symbolic-links-unprivileged",children:"Allow symbolic links unprivileged"}),"\n",(0,s.jsxs)(n.p,{children:["Open ",(0,s.jsx)(n.code,{children:"Local Security Policy"}),", go to ",(0,s.jsx)(n.code,{children:"Local Policies - User Rights Assignment"}),", open ",(0,s.jsx)(n.code,{children:"Create symbolic links"})," and add your user account or user group, restart when it doesn't apply immediately."]}),"\n",(0,s.jsx)(n.h2,{id:"folders-structure",children:"Folders structure"}),"\n",(0,s.jsxs)(n.p,{children:["All ",(0,s.jsx)(n.code,{children:"tinyorm.org"})," examples are based on the following folders structure. The ",(0,s.jsx)(n.code,{children:"tom"})," folder will contain a ",(0,s.jsx)(n.a,{href:"/building/migrations",children:"migrations console application"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can set the root and application folder paths in the form below and they will be used across the whole ",(0,s.jsx)(n.a,{href:"http://www.tinyorm.org",children:"www.tinyorm.org"})," website. \ud83e\udd73 The pwsh shell is supposed to use on Windows and the bash shell on Linux, but it is not a requirement."]})}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsxs)(t.A,{value:y.b,label:y.ux,className:"tiny-tree",children:[(0,s.jsx)("div",{className:"tiny-root-folder-info-wrapper",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)("span",{className:"tiny-root-folder-info-prefix",children:"Current pwsh path"}),"\xa0",(0,s.jsx)(u,{groupId:y.b})]})}),(0,s.jsx)(g,{groupId:y.b,label:y.ux}),(0,s.jsx)(g,{groupId:y.pW,label:y.kl}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"\n\n\n\u251c\u2500\u2500\n\u2502 \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld-builds-cmake/\n\u2502 | | \u2514\u2500\u2500 build-debug/\n\u2502 | \u2514\u2500\u2500 HelloWorld-builds-qmake/\n\u2502 | \u2514\u2500\u2500 build-debug/\n\u2502 \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM-builds-cmake/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-debug/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-release/\n\u2502 | \u2502 \u2514\u2500\u2500 build-clang-debug/\n\u2502 | \u2514\u2500\u2500 TinyORM-builds-qmake/\n\u2502 | \u251c\u2500\u2500 build-debug/\n\u2502 | \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/\n\u2502 | \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_MSYS2_UCRT64_64bit-Release/\n\u2502 \u2514\u2500\u2500 tom/\n\u2502 \u251c\u2500\u2500 tom/\n\u2502 \u2502 \u2514\u2500\u2500 database/\n\u2502 \u2502 \u251c\u2500\u2500 migrations/\n\u2502 \u2502 \u251c\u2500\u2500 seeders/\n\u2502 \u2502 \u251c\u2500\u2500 migrations.pri\n\u2502 \u2502 \u2514\u2500\u2500 seeders.pri\n\u2502 \u251c\u2500\u2500 tom-builds-cmake/\n\u2502 \u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/\n\u2502 \u2514\u2500\u2500 tom-builds-qmake/\n\u2502 \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_3_MSYS2_UCRT64_64bit-Release/\n\u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/\n\u251c\u2500\u2500 tmp/\n\u2514\u2500\u2500 vcpkg/\n"})})]}),(0,s.jsxs)(t.A,{value:y.xj,label:y.gg,className:"tiny-tree",children:[(0,s.jsx)("div",{className:"tiny-root-folder-info-wrapper",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)("span",{className:"tiny-root-folder-info-prefix",children:"Current bash path"}),"\xa0",(0,s.jsx)(u,{groupId:y.xj})]})}),(0,s.jsx)(g,{groupId:y.xj,label:y.gg}),(0,s.jsx)(g,{groupId:y.pW,label:y.pW}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"\n\n\n\u251c\u2500\u2500\n\u2502 \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld-builds-cmake/\n\u2502 | | \u2514\u2500\u2500 build-debug/\n\u2502 | \u2514\u2500\u2500 HelloWorld-builds-qmake/\n\u2502 | \u2514\u2500\u2500 build-debug/\n\u2502 \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM-builds-cmake/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-debug/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-release/\n\u2502 | \u2502 \u2514\u2500\u2500 build-clang-debug/\n\u2502 | \u2514\u2500\u2500 TinyORM-builds-qmake/\n\u2502 | \u251c\u2500\u2500 build-debug/\n\u2502 | \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_GCC_64bit-Debug/\n\u2502 | \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_clang13_64bit_ccache-Release/\n\u2502 \u2514\u2500\u2500 tom/\n\u2502 \u251c\u2500\u2500 tom/\n\u2502 \u2502 \u2514\u2500\u2500 database/\n\u2502 \u2502 \u251c\u2500\u2500 migrations/\n\u2502 \u2502 \u251c\u2500\u2500 seeders/\n\u2502 \u2502 \u251c\u2500\u2500 migrations.pri\n\u2502 \u2502 \u2514\u2500\u2500 seeders.pri\n\u2502 \u251c\u2500\u2500 tom-builds-cmake/\n\u2502 \u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_clang14_64bit_ccache-Debug/\n\u2502 \u2514\u2500\u2500 tom-builds-qmake/\n\u2502 \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_GCC_64bit-Debug/\n\u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_clang14_64bit_ccache-Release/\n\u251c\u2500\u2500 tmp/\n\u2514\u2500\u2500 vcpkg/\n"})})]})]}),"\n",(0,s.jsx)(n.admonition,{type:"danger",children:(0,s.jsxs)(n.p,{children:["Avoid paths with spaces with the ",(0,s.jsx)(n.code,{children:"qmake"})," build system, it will not compile."]})}),"\n",(0,s.jsx)(r.A,{id:"qtcreator-default-build-directory"}),"\n",(0,s.jsxs)(n.admonition,{type:"tip",children:[(0,s.jsxs)(n.p,{children:["You can force the ",(0,s.jsx)(n.code,{children:"QtCreator"})," to generate a build folders structure as is described above."]}),(0,s.jsxs)(n.p,{children:["To generate the required folders structure set the ",(0,s.jsx)(n.code,{children:"Settings"})," - ",(0,s.jsx)(n.code,{children:"Build & Run"})," - ",(0,s.jsx)(n.code,{children:"Default Build Properties"})," - ",(0,s.jsx)(n.code,{children:"Default build directory"})," to:",(0,s.jsx)("br",{}),"\n",(0,s.jsx)(n.code,{children:'../%{Project:Name}-builds-%{BuildSystem:Name}/%{JS: Util.asciify("build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}")}'})]})]}),"\n",(0,s.jsx)(n.h2,{id:"getting-started",children:"Getting started"}),"\n",(0,s.jsxs)(n.p,{children:["Prepare compilation environment, we need to put the Qt Framework and Visual Studio MSVC compiler on the path on Windows. The compiler is already on the path on Linux and you can export ",(0,s.jsx)(n.code,{children:"PATH"})," and ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," for Qt Framework, or use our ",(0,s.jsx)(n.code,{children:"qtenvX"})," scripts described above."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`mkdir ${(0,x.Sn)(y.b)}\ncd ${(0,x.Sn)(y.b)}\n$env:Path = 'C:\\Qt\\6.7.2\\msvc2019_64\\bin;' + $env:Path\nvcvars64.ps1`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`mkdir -p ${(0,x.Sn)(y.xj)}\ncd ${(0,x.Sn)(y.xj)}\nexport PATH=/opt/Qt/6.7.2/gcc_64/bin\${PATH:+:}$PATH\nexport LD_LIBRARY_PATH=/opt/Qt/6.7.2/gcc_64/lib\${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH`})})]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can also use the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tools/Add-FolderOnPath.ps1",children:(0,s.jsx)(n.code,{children:"tools/Add-FolderOnPath.ps1"})})," pwsh script to fastly prepend a path or ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"})," on the system ",(0,s.jsx)(n.code,{children:"PATH"}),"."]})}),"\n",(0,s.jsx)(n.h2,{id:"vcpkg",children:"vcpkg"}),"\n",(0,s.jsxs)(n.p,{children:["Installing the ",(0,s.jsx)(n.code,{children:"vcpkg"})," is highly recommended, it simplifies installation of the ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," dependencies."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:"git clone git@github.com:microsoft/vcpkg.git\ncd vcpkg\n.\\bootstrap-vcpkg.bat\n"})})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"git clone git@github.com:microsoft/vcpkg.git\ncd vcpkg\n./bootstrap-vcpkg.sh\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["Add ",(0,s.jsx)(n.code,{children:"vcpkg"})," on the system path, add the following to the ",(0,s.jsx)(n.code,{children:".bashrc"})," or ",(0,s.jsx)(n.code,{children:".zshrc"})," on Linux."]}),"\n",(0,s.jsx)(c.A,{className:"language-bash",children:`export PATH=${(0,x.Sn)(y.xj)}/vcpkg\${PATH:+:}$PATH`}),"\n",(0,s.jsxs)(n.p,{children:["On Windows, open the ",(0,s.jsx)(n.code,{children:"Environment variables"})," dialog and add ",(0,s.jsx)(n.code,{children:"vcpkg"})," on the user ",(0,s.jsx)(n.code,{children:"PATH"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Or you can export it for the current session only."}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`$env:Path = "${(0,x.Sn)(y.b,!1)}\\vcpkg;" + $env:Path`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`export PATH=${(0,x.Sn)(y.xj)}/vcpkg\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.h4,{id:"set-up-vcpkg-environment",children:["Set up ",(0,s.jsx)(n.code,{children:"vcpkg"})," environment"]}),"\n",(0,s.jsxs)(n.p,{children:["To export ",(0,s.jsx)(n.code,{children:"vcpkg"})," environment variables globally, add it to the ",(0,s.jsx)(n.code,{children:".bashrc"})," or ",(0,s.jsx)(n.code,{children:".zshrc"})," on Linux, and you can use the ",(0,s.jsx)(n.code,{children:"Environment variables"})," dialog on Windows."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",metastring:"title='Linux'",children:'export VCPKG_DEFAULT_TRIPLET=x64-linux\n#export VCPKG_DEFAULT_HOST_TRIPLET=x64-linux\nexport VCPKG_MAX_CONCURRENCY=11\nexport VCPKG_OVERLAY_PORTS="$HOME/.local/share/vcpkg/ports"\nexport VCPKG_OVERLAY_TRIPLETS="$HOME/.local/share/vcpkg/triplets"\nexport VCPKG_ROOT="$HOME/Code/c/vcpkg"\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["It is recommended to define these variables globally because the ",(0,s.jsx)(n.code,{children:"CMake"})," and ",(0,s.jsx)(n.code,{children:"qmake"})," build system are able to detect the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation from them so you don't have to configure them manually to detect the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["On Windows, it's always better to create these types of variables as user variables instead of system variables in the ",(0,s.jsx)(n.code,{children:"Environment variables"})," dialog."]})}),"\n",(0,s.jsx)(n.h2,{id:"c-preprocessor-macros",children:"C preprocessor macros"}),"\n",(0,s.jsxs)(n.p,{children:["The following table summarizes all the C preprocessor macros defined in the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. These C macros are configured by ",(0,s.jsx)(n.code,{children:"CMake"})," or ",(0,s.jsx)(n.code,{children:"qmake"})," build systems. They are not sorted alphabetically, but they are sorted by how significant they are."]}),"\n",(0,s.jsxs)(n.p,{children:["In the ",(0,s.jsx)(n.code,{children:"CMake"})," build system, all the C macros are auto-detected / auto-configured or controlled by ",(0,s.jsx)(n.a,{href:"#cmake-build-options",children:(0,s.jsx)(n.code,{children:"CMake build options"})}),", so you don't have to care too much about them."]}),"\n",(0,s.jsxs)(n.p,{children:["In the ",(0,s.jsx)(n.code,{children:"qmake"})," build is important whether you are building ",(0,s.jsx)(n.code,{children:"TinyORM"})," library or you are building your application and linking against ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. When you are building the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library, all the C macros are auto-detected / auto-configured or controlled by ",(0,s.jsx)(n.a,{href:"#qmake-build-options",children:(0,s.jsx)(n.code,{children:"qmake build options"})}),", so you don't have to care too much about them."]}),"\n",(0,s.jsxs)(n.p,{children:["But a special situation is when you are building your application / library and you are linking against ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. In this particular case, you must configure all these C macros manually! For this reason, the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/qmake/TinyOrm.pri",children:(0,s.jsx)(n.code,{children:"TinyOrm.pri"})})," has been created, so that's not a big deal either. Little more info ",(0,s.jsx)(n.a,{href:"#consume-tinyorm-library-qmake",children:"here"}),"."]}),"\n",(0,s.jsx)("div",{id:"apitable-c-macros",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"C Macro Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_LINKING_SHARED"})}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)("u",{children:(0,s.jsx)(n.strong,{children:"Must"})})," be defined when you are linking against ",(0,s.jsx)(n.code,{children:"TinyORM"})," shared build (",(0,s.jsx)(n.code,{children:"dll"})," library), exported classes and functions will be tagged with ",(0,s.jsx)(n.code,{children:"__declspec(dllimport)"})," on ",(0,s.jsx)(n.code,{children:"msvc"})," and ",(0,s.jsx)(n.code,{children:'visibility("default")'})," on ",(0,s.jsx)(n.code,{children:"GCC >= 4"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_BUILDING_SHARED"})}),(0,s.jsxs)(n.td,{children:["Defined when ",(0,s.jsx)(n.code,{children:"TinyORM"})," is built as a ",(0,s.jsx)(n.code,{children:"dll"})," library (shared build)."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DEBUG"})}),(0,s.jsx)(n.td,{children:"Defined in the debug build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_NO_DEBUG"})}),(0,s.jsx)(n.td,{children:"Defined in the release build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DEBUG_SQL"})}),(0,s.jsx)(n.td,{children:"Defined in the debug build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_NO_DEBUG_SQL"})}),(0,s.jsx)(n.td,{children:"Defined in the release build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_MYSQL_PING"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.code,{children:"Orm::MySqlConnection::pingDatabase()"})," method.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#mysql_ping",children:(0,s.jsx)(n.code,{children:"mysql_ping"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#MYSQL_PING",children:(0,s.jsx)(n.code,{children:"MYSQL_PING"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DISABLE_ORM"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"ORM-related"})," source code, when this macro is ",(0,s.jsx)(n.code,{children:"defined"}),", then only the ",(0,s.jsx)(n.code,{children:"query builder"})," without ",(0,s.jsx)(n.code,{children:"ORM"})," is compiled. Also excludes ",(0,s.jsx)(n.code,{children:"ORM-related"})," unit tests.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#disable_orm",children:(0,s.jsx)(n.code,{children:"disable_orm"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#ORM",children:(0,s.jsx)(n.code,{children:"ORM"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled ",(0,s.jsx)("small",{children:"(qmake)"})," / disabled ",(0,s.jsx)("small",{children:"(cmake)"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_EXTERN_CONSTANTS"})}),(0,s.jsxs)(n.td,{children:["Defined when extern constants are used. Extern constants are enabled by default for shared builds and disabled for static builds.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Described at ",(0,s.jsx)(n.a,{href:"#extern_constants",children:(0,s.jsx)(n.code,{children:"qmake"})})," / ",(0,s.jsx)(n.a,{href:"#INLINE_CONSTANTS",children:(0,s.jsx)(n.code,{children:"CMake"})})," how it works."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_INLINE_CONSTANTS"})}),(0,s.jsxs)(n.td,{children:["Defined when global inline constants are used.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#inline_constants",children:(0,s.jsx)(n.code,{children:"inline_constants"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#INLINE_CONSTANTS",children:(0,s.jsx)(n.code,{children:"INLINE_CONSTANTS"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_TESTS_CODE"})}),(0,s.jsxs)(n.td,{children:["Enable code needed by unit tests, eg. connection overriding in the ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Model"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#build_tests",children:(0,s.jsx)(n.code,{children:"build_tests"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#BUILD_TESTS",children:(0,s.jsx)(n.code,{children:"BUILD_TESTS"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DISABLE_THREAD_LOCAL"})}),(0,s.jsxs)(n.td,{children:["Remove all ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/c/language/storage_duration",children:(0,s.jsx)(n.code,{children:"thread_local"})})," storage duration specifiers, it disables multi-threading support.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#disable_thread_local",children:(0,s.jsx)(n.code,{children:"disable_thread_local"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#DISABLE_THREAD_LOCAL",children:(0,s.jsx)(n.code,{children:"DISABLE_THREAD_LOCAL"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYTOM_MIGRATIONS_DIR"})}),(0,s.jsxs)(n.td,{children:["Default migrations path for the ",(0,s.jsx)(n.code,{children:"make:migration"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/migrations"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined by ",(0,s.jsx)(n.a,{href:"#TOM_MIGRATIONS_DIR",children:(0,s.jsx)(n.code,{children:"TOM_MIGRATIONS_DIR"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration build option.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(qmake note) You can use ",(0,s.jsx)(n.code,{children:'DEFINES += TINYTOM_MIGRATIONS_DIR="\\"database/migrations\\""'})," on the command-line or set it in the ",(0,s.jsx)(n.strong,{children:"main"})," ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L65-L70",children:(0,s.jsx)(n.code,{children:"conf.pri"})})," file."]})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYTOM_MODELS_DIR"})}),(0,s.jsxs)(n.td,{children:["Default models path for the ",(0,s.jsx)(n.code,{children:"make:model"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/models"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined by ",(0,s.jsx)(n.a,{href:"#TOM_MODELS_DIR",children:(0,s.jsx)(n.code,{children:"TOM_MODELS_DIR"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration build option.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(qmake note) You can use ",(0,s.jsx)(n.code,{children:'DEFINES += TINYTOM_MODELS_DIR="\\"database/models\\""'})," on the command-line or set it in the ",(0,s.jsx)(n.strong,{children:"main"})," ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L72-L73",children:(0,s.jsx)(n.code,{children:"conf.pri"})})," file."]})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYTOM_SEEDERS_DIR"})}),(0,s.jsxs)(n.td,{children:["Default seeders path for the ",(0,s.jsx)(n.code,{children:"make:seeder"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/seeders"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined by ",(0,s.jsx)(n.a,{href:"#TOM_SEEDERS_DIR",children:(0,s.jsx)(n.code,{children:"TOM_SEEDERS_DIR"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration build option.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(qmake note) You can use ",(0,s.jsx)(n.code,{children:'DEFINES += TINYTOM_SEEDERS_DIR="\\"database/seeders\\""'})," on the command-line or set it in the ",(0,s.jsx)(n.strong,{children:"main"})," ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L75-L76",children:(0,s.jsx)(n.code,{children:"conf.pri"})})," file."]})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_USING_PCH"})}),(0,s.jsxs)(n.td,{children:["Defined if building with precompiled headers.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Controlled by ",(0,s.jsx)(n.a,{href:"#qmake-precompile_header",children:(0,s.jsx)(n.code,{children:"qmake"})})," / ",(0,s.jsx)(n.a,{href:"#CMAKE_DISABLE_PRECOMPILE_HEADERS",children:(0,s.jsx)(n.code,{children:"CMake"})}),"."]})]})]})]})]})})}),"\n",(0,s.jsx)(n.h2,{id:"building-with-cmake",children:"Building with CMake"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["If something is not clear, you can still look at GitHub Action ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/.github/workflows",children:(0,s.jsx)(n.code,{children:"workflows"})})," how a building is done."]})}),"\n",(0,s.jsxs)(n.p,{children:["First, create a basic folder structure and then clone the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.Sn)(y.b)}\nmkdir ${(0,x.np)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.Sn)(y.xj)}\nmkdir -p ${(0,x.np)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})})]}),"\n",(0,s.jsxs)(n.h3,{id:"configure-and-build-cmake",children:["Configure & Build ",(0,s.jsx)("small",{children:"(cmake)"})]}),"\n",(0,s.jsxs)(n.p,{children:["Now you are ready to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd TinyORM-builds-cmake/build-debug\n"})}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cmake.exe \`\n-S "${(0,x.OZ)(y.b)}/TinyORM/TinyORM" \`\n-B "${(0,x.OZ)(y.b)}/TinyORM/TinyORM-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,x.Sn)(y.b)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,x.Sn)(y.b)}/tmp/TinyORM" \`\n-D BUILD_TESTS:BOOL=OFF \`\n-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=ON \`\n-D MYSQL_PING:BOOL=OFF \`\n-D TOM:BOOL=ON \`\n-D TOM_EXAMPLE:BOOL=OFF \`\n-D VERBOSE_CONFIGURE:BOOL=ON`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cmake \\\n-S "${(0,x.OZ)(y.xj)}/TinyORM/TinyORM" \\\n-B "${(0,x.OZ)(y.xj)}/TinyORM/TinyORM-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,x.Sn)(y.xj)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,x.Sn)(y.xj)}/tmp/TinyORM" \\\n-D VERBOSE_CONFIGURE:BOOL=ON \\\n-D BUILD_TESTS:BOOL=OFF \\\n-D MYSQL_PING:BOOL=OFF \\\n-D TOM:BOOL=ON \\\n-D TOM_EXAMPLE:BOOL=OFF \\\n-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=ON`})})]}),"\n",(0,s.jsxs)(n.h5,{id:"cmake-strict_mode-option",children:["CMake ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," option"]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," ",(0,s.jsx)(n.code,{children:"CMake"})," configuration option was added in ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.37.3"}),". This option was added to avoid the propagation of aggressive strict warning compiler/linker options and Qt definitions from the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library to user code through the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/cmake/CommonModules/TinyCommon.cmake",children:(0,s.jsx)(n.code,{children:"TinyOrm::CommonConfig"})})," interface library."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"TinyORM"})," uses the strictest warning level options, virtually anything that can be enabled is enabled to produce a better code. I highly recommend enabling this option to produce better code and to follow good practices. It also helps to follow the ",(0,s.jsx)(n.code,{children:"ISOCPP"})," ",(0,s.jsx)(n.a,{href:"https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines",children:"C++ Core Guidelines"})," standards."]}),"\n",(0,s.jsxs)(n.p,{children:["If you want to enable these strict warning options in your code, you can enable the ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," ",(0,s.jsx)(n.code,{children:"CMake"})," configuration option and they will be propagated to your code. You can also enabled it globally using the ",(0,s.jsx)(n.code,{children:"TINYORM_STRICT_MODE"})," environment variable, and the value of this environment variable will be picked up during initial CMake configuration as the default value for the ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," ",(0,s.jsx)(n.code,{children:"CMake"})," configuration option."]}),"\n",(0,s.jsxs)(n.p,{children:["You can achieve the same result by manually linking against the ",(0,s.jsx)(n.code,{children:"TinyOrm::CommonConfig"})," interface library when the ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," is set to ",(0,s.jsx)(n.code,{children:"OFF"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cmake",children:"target_link_libraries( PRIVATE TinyOrm::CommonConfig)\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The recommended way is to set the ",(0,s.jsx)(n.code,{children:"TINYORM_STRICT_MODE"})," environment variable to ",(0,s.jsx)(n.code,{children:"1"})," or ",(0,s.jsx)(n.code,{children:"ON"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"build-tinyorm",children:"Build TinyORM"}),"\n",(0,s.jsx)(n.p,{children:"And build. You don't have to install it, you can use the build tree directly if you want."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cmake --build . --target all\ncmake --install .\n"})}),"\n",(0,s.jsx)(n.p,{children:"Or build and install in one step."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cmake --build . --target install\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["CMake multi-config generators like ",(0,s.jsx)(n.code,{children:"Ninja Multi-Config"})," or ",(0,s.jsx)(n.code,{children:"Visual Studio 16 2019"})," are also supported."]})}),"\n",(0,s.jsx)(n.h3,{id:"cmake-build-options",children:"CMake build options"}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_DRIVERS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started",children:"TinyDrivers"})," SQL database drivers (core/common code; replaces QtSql module)."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_MYSQL_DRIVER"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," MySQL database driver.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"BUILD_DRIVERS"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_SHARED_LIBS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsx)(n.td,{children:"Build as a shared/static library."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_TESTS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Build TinyORM unit tests."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_TREE_DEPLOY"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Copy ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," and ",(0,s.jsx)(n.code,{children:"TinyMySql"})," libraries to the root of the build tree."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"DRIVERS_TYPE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Shared"})}),(0,s.jsxs)(n.td,{children:["How to build and link against ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," SQL database drivers.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"Static"})," value will be select by default when the ",(0,s.jsx)(n.code,{children:"BUILD_SHARED_LIBS"})," is ",(0,s.jsx)(n.code,{children:"OFF"}),".",(0,s.jsx)("br",{}),"Supported values: ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-shared-library-build",children:(0,s.jsx)(n.code,{children:"Shared"})}),", ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-loadable-sql-drivers-build",children:(0,s.jsx)(n.code,{children:"Loadable"})}),", and ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-static-build",children:(0,s.jsx)(n.code,{children:"Static"})}),(0,s.jsx)("br",{}),"Available when: ",(0,s.jsx)(n.code,{children:"BUILD_DRIVERS AND BUILD_SHARED_LIBS"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"INLINE_CONSTANTS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Use inline constants instead of extern constants in the ",(0,s.jsx)(n.code,{children:"shared build"}),".",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"OFF"})," is highly recommended for the ",(0,s.jsx)(n.code,{children:"shared build"}),";",(0,s.jsx)("br",{}),"is always ",(0,s.jsx)(n.code,{children:"ON"})," for the ",(0,s.jsx)(n.code,{children:"static build"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"BUILD_SHARED_LIBS"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"MSVC_RUNTIME_DYNAMIC"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Use MSVC dynamic runtime library (",(0,s.jsx)(n.code,{children:"-MD"}),") instead of static (",(0,s.jsx)(n.code,{children:"-MT"}),"), also considers a Debug configuration (",(0,s.jsx)(n.code,{children:"-MTd"}),", ",(0,s.jsx)(n.code,{children:"-MDd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"MSVC AND NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"MYSQL_PING"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.code,{children:"Orm::MySqlConnection::pingDatabase()"})," method."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ORM"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"ORM-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"disabled"}),", then only the ",(0,s.jsx)(n.code,{children:"query builder"})," without ",(0,s.jsx)(n.code,{children:"ORM"})," is compiled. Also excludes ",(0,s.jsx)(n.code,{children:"ORM-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"STRICT_MODE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Controls propagation of strict compiler/linker options and Qt definitions using the ",(0,s.jsx)(n.code,{children:"TinyOrm::CommonConfig"})," interface library to the user code.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(highly recommended; can also be set with the ",(0,s.jsx)(n.code,{children:"TINYORM_STRICT_MODE"})," environment variable; described ",(0,s.jsx)(n.a,{href:"#cmake-strict_mode-option",children:"here"}),")"]}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"Tom-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"disabled"}),", then it also excludes ",(0,s.jsx)(n.code,{children:"Tom-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_EXAMPLE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build the ",(0,s.jsx)("abbr",{title:"TinyORM Migrations",children:(0,s.jsx)(n.code,{children:"tom"})})," console application example."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_MIGRATIONS_DIR"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default migrations path for the ",(0,s.jsx)(n.code,{children:"make:migration"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/migrations"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_MODELS_DIR"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default models path for the ",(0,s.jsx)(n.code,{children:"make:model"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/models"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_SEEDERS_DIR"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default seeders path for the ",(0,s.jsx)(n.code,{children:"make:seeder"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/seeders"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"VERBOSE_CONFIGURE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Show information about ",(0,s.jsx)(n.code,{children:"PACKAGES_FOUND"})," / ",(0,s.jsx)(n.code,{children:"PACKAGES_NOT_FOUND"})," in the CMake configure output."]})]})]})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Advanced ",(0,s.jsx)(n.code,{children:"TinyORM"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"DISABLE_THREAD_LOCAL"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Remove all ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/c/language/storage_duration",children:(0,s.jsx)(n.code,{children:"thread_local"})})," storage duration specifiers, it disables multi-threading support."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)("small",{children:(0,s.jsx)(n.code,{children:"MATCH_EQUAL_EXPORTED_BUILDTREE"})})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Exported package configuration from the build tree is considered to match only when ",(0,s.jsx)(n.code,{children:"the build type"})," of application/library that is linking against the TinyORM library ",(0,s.jsx)(n.strong,{children:"is equal"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when:",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"CMAKE_EXPORT_PACKAGE_REGISTRY AND NOT TINY_IS_MULTI_CONFIG"})]})]})]})]})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Important ",(0,s.jsx)(n.code,{children:"CMake"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_DISABLE_PRECOMPILE_HEADERS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Disable precompiled headers."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_CXX_COMPILER"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"auto"})}),(0,s.jsxs)(n.td,{children:["The full path to the ",(0,s.jsx)(n.code,{children:"C++"})," compiler."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_CXX_COMPILER_LAUNCHER"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default compiler launcher to use for the ",(0,s.jsx)(n.code,{children:"C++"})," compiler.",(0,s.jsx)("br",{}),"Can be used to enable ",(0,s.jsx)(n.code,{children:"ccache"}),", eg. ",(0,s.jsx)(n.code,{children:"ccache.exe"})," on ",(0,s.jsx)(n.code,{children:"MinGW"})," or ",(0,s.jsx)(n.code,{children:"/usr/bin/ccache"})," on ",(0,s.jsx)(n.code,{children:"Linux"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_EXPORT_PACKAGE_REGISTRY"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable the ",(0,s.jsx)(n.code,{children:"export(TinyOrm)"})," command.",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"TinyORM"})," doesn't set this variable by default. Its initial value is taken from the ",(0,s.jsx)(n.code,{children:"TINYORM_EXPORT_PACKAGE_REGISTRY"})," environment variable if not already defined."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)("small",{children:(0,s.jsx)(n.code,{children:"CMAKE_INTERPROCEDURAL_OPTIMIZATION"})})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Interprocedural_optimization",children:"Link time code optimization"})," (",(0,s.jsx)(n.a,{href:"https://wiki.gentoo.org/wiki/LTO",children:"LTO"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Works on all ",(0,s.jsx)(n.a,{href:"/supported-compilers",children:"Supported Compilers"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_VERBOSE_MAKEFILE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Enable verbose output from Makefile builds."})]})]})]})})}),"\n",(0,s.jsxs)(n.h3,{id:"consume-tinyorm-library-cmake",children:["Consume TinyOrm library ",(0,s.jsx)("small",{children:"(cmake)"})]}),"\n",(0,s.jsxs)(n.p,{children:["In your application or library ",(0,s.jsx)(n.code,{children:"CMakeLists.txt"})," file add following ",(0,s.jsx)(n.code,{children:"find_package()"})," call."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cmake",metastring:"title='CMakeLists.txt'",children:"find_package(TinyOrm 0.37.3 CONFIG REQUIRED)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build tree is not exported to the CMake's ",(0,s.jsx)(n.a,{href:"https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#user-package-registry",children:(0,s.jsx)(n.code,{children:"User Package Registry"})})," then also add the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build tree or ",(0,s.jsx)(n.code,{children:"CMAKE_INSTALL_PREFIX"})," folder to the ",(0,s.jsx)(n.code,{children:"CMAKE_PREFIX_PATH"}),", so CMake can find TinyORM's package configuration file during ",(0,s.jsx)(n.code,{children:"find_package(TinyOrm)"})," call."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:`cmake (${y.b})`,children:(0,s.jsx)(c.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.b,(0,x.OZ)(y.b))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.b,(0,x.Sn)(y.b))}/tmp/TinyORM")`})}),(0,s.jsx)(t.A,{value:y.xj,label:`cmake (${y.xj})`,children:(0,s.jsx)(c.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.xj,(0,x.OZ)(y.xj))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.xj,(0,x.Sn)(y.xj))}/tmp/TinyORM")`})})]}),"\n",(0,s.jsxs)(n.p,{children:["Or as an alternative, you can set ",(0,s.jsx)(n.code,{children:"CMAKE_PREFIX_PATH"})," environment variable."]}),"\n",(0,s.jsx)(r.A,{id:"tinyorm-on-path-cmake"}),"\n",(0,s.jsxs)(n.p,{children:["As the last thing, do not forget to add ",(0,s.jsx)(n.code,{children:"TinyOrm0d.dll"})," on the path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux, so your application can find it during execution."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`$env:Path = "${(0,x.OZ)(y.b,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,x.OZ)(y.xj)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.p,{children:["Now you can try the ",(0,s.jsx)(n.a,{href:"/building/hello-world#hello-world-with-cmake",children:(0,s.jsx)(n.code,{children:"HelloWorld CMake"})})," example."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can also try the ",(0,s.jsx)(n.a,{href:"/building/hello-world#fetchcontent",children:(0,s.jsx)(n.code,{children:"FetchContent"})})," method to fastly link against the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library."]})}),"\n",(0,s.jsx)(n.h2,{id:"building-with-qmake",children:"Building with qmake"}),"\n",(0,s.jsxs)(n.p,{children:["First, create a basic folder structure and then clone the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.Sn)(y.b)}\nmkdir ${(0,x.np)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.Sn)(y.xj)}\nmkdir -p ${(0,x.np)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})})]}),"\n",(0,s.jsx)(n.h3,{id:"install-dependencies",children:"Install dependencies"}),"\n",(0,s.jsxs)(n.p,{children:["With the ",(0,s.jsx)(n.code,{children:"qmake"})," build system, you have to install ",(0,s.jsx)(n.code,{children:"TinyORM"})," dependencies manually. We will use the ",(0,s.jsx)(n.code,{children:"vcpkg"})," package manager."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd ../../vcpkg\n\nvcpkg search range-v3\nvcpkg search tabulate\nvcpkg install range-v3 tabulate\nvcpkg list\n"})}),"\n",(0,s.jsxs)(n.p,{children:["On ",(0,s.jsx)(n.code,{children:"Linux"}),", you can install the ",(0,s.jsx)(n.code,{children:"range-v3"})," library and some other ",(0,s.jsx)(n.a,{href:"/dependencies#install-dependencies",children:"dependencies"})," with the package manager."]}),"\n",(0,s.jsxs)(n.h3,{id:"configure-and-build-qmake",children:["Configure & Build ",(0,s.jsx)("small",{children:"(qmake)"})]}),"\n",(0,s.jsx)(n.h4,{id:"open-qtcreator-ide",children:"Open QtCreator IDE"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["I recommend creating a new ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qtcreator/creator-project-managing-sessions.html",children:(0,s.jsx)(n.code,{children:"Session"})})," in the ",(0,s.jsx)(n.code,{children:"QtCreator"}),", this way you will have all the examples in one place and as a bonus, everything will be in the same place when you close and reopen ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),". You can name it ",(0,s.jsx)(n.code,{children:"tinyorm.org"})," or ",(0,s.jsx)(n.code,{children:"TinyORM examples"}),", it is up to you."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["If you are using sessions, you can use a single ",(0,s.jsx)(n.code,{children:"clangd"})," instance for all projects in this session in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),". One significant advantage of this method is that the ",(0,s.jsx)(n.code,{children:".qtc_clangd/"})," folder will not be created in the build folder, but will be stored globally in the Roaming profile. You can enable it in the ",(0,s.jsx)(n.code,{children:"Settings"})," - ",(0,s.jsx)(n.code,{children:"C++"})," - ",(0,s.jsx)(n.code,{children:"Clangd"})," - ",(0,s.jsx)(n.code,{children:"Sessions with a single clangd instance"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"configure-tinyorm",children:"Configure TinyORM"}),"\n",(0,s.jsxs)(n.p,{children:["Now you are ready to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. There are two ways how to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library and it's the new ",(0,s.jsx)(n.code,{children:"Auto-configure"})," feature added in ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"})," using the ",(0,s.jsx)(n.code,{children:".env"})," files and the old way using the ",(0,s.jsx)(n.code,{children:"conf.pri"})," files."]}),"\n",(0,s.jsx)(n.h5,{id:"auto-configuration-and-tiny_dotenv",children:"Auto-configuration and tiny_dotenv"}),"\n",(0,s.jsxs)(n.p,{children:["This is the new recommended method to auto-configure TinyORM's ",(0,s.jsx)(n.code,{children:"qmake"})," build system and also the dependencies, it was added in ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),". You need to copy the prepared ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw).example"})," file to the ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"}),". One ",(0,s.jsx)(n.code,{children:".env"})," example file is prepared for each supported platform."]}),"\n",(0,s.jsxs)(n.p,{children:["All prepared ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw).example"})," files are simple and clear. You can also create a common ",(0,s.jsx)(n.code,{children:".env"})," file that is included before the platform-specific ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"})," files."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.OZ)(y.b)}/TinyORM/TinyORM\n\ncp .env.win32.example .env.win32`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.OZ)(y.xj)}/TinyORM/TinyORM\n\ncp .env.unix.example .env.unix`})})]}),"\n",(0,s.jsxs)(n.p,{children:["And that is all, if you have correctly set all ",(0,s.jsx)(n.code,{children:"qmake"})," variables in this ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"})," file or you have correctly set environment variables, then the ",(0,s.jsx)(n.code,{children:"qmake"})," build system should be able to ",(0,s.jsx)(n.code,{children:"auto-detect"})," all dependencies . \ud83d\udd25"]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:(0,s.jsx)(n.code,{children:"Auto-configuration"})})," and ",(0,s.jsx)(n.a,{href:"#environment-files",children:(0,s.jsx)(n.code,{children:"Environment files"})})," internals are described at the end to make this section more clear."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_autoconf",children:(0,s.jsx)(n.code,{children:"disable_autoconf"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_autoconf"}),")."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_dotenv",children:(0,s.jsx)(n.code,{children:"disable_dotenv"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_dotenv"}),")."]})}),"\n",(0,s.jsx)(n.h5,{id:"manual-configuration-confpri",children:"Manual configuration (conf.pri)"}),"\n",(0,s.jsxs)(n.p,{children:["This is the old method used before ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),". You need to copy the ",(0,s.jsx)(n.code,{children:"conf.pri.example"})," files to ",(0,s.jsx)(n.code,{children:"conf.pri"})," (there are four, one for every project or sub-project) and manually update the ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," and ",(0,s.jsx)(n.code,{children:"LIBS"})," to configure TinyORM's ",(0,s.jsx)(n.code,{children:"qmake"})," build dependencies. This way you can override any ",(0,s.jsx)(n.code,{children:"qmake"})," build options or variables."]}),"\n",(0,s.jsxs)(n.p,{children:["To disable the ",(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:(0,s.jsx)(n.code,{children:"Auto-configuration"})})," feature you must define the ",(0,s.jsx)(n.a,{href:"#disable_autoconf",children:(0,s.jsx)(n.code,{children:"disable_autoconf"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_autoconf"}),") because from ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"})," is the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature enabled by default."]}),"\n",(0,s.jsxs)(n.p,{children:["You can also remove all ",(0,s.jsx)(n.code,{children:".env"})," files or turn off the ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature using ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_dotenv"}),". You can use them all at once if you want, ",(0,s.jsx)(n.code,{children:".env"})," and also ",(0,s.jsx)(n.code,{children:"conf.pri"})," files."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"conf.pri"})," files are nicely commented on, so you can see what needs to be modified."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.OZ)(y.b)}/TinyORM/TinyORM\n\ncp conf.pri.example conf.pri\ncp tests/conf.pri.example tests/conf.pri\ncp tests/testdata_tom/conf.pri.example tests/testdata_tom/conf.pri\ncp examples/tom/conf.pri.example examples/tom/conf.pri`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.OZ)(y.xj)}/TinyORM/TinyORM\n\ncp conf.pri.example conf.pri\ncp tests/conf.pri.example tests/conf.pri\ncp tests/testdata_tom/conf.pri.example tests/testdata_tom/conf.pri\ncp examples/tom/conf.pri.example examples/tom/conf.pri`})})]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#manual-configuration-internals",children:(0,s.jsx)(n.code,{children:"Manual configuration"})})," internals are described at the end to make this section more clear."]})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Manual configuration"})," is still relevant if you have any non-standard installation of the ",(0,s.jsx)(n.code,{children:"vcpkg"})," or ",(0,s.jsx)(n.code,{children:"MySQL"})," and the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature fails."]})}),"\n",(0,s.jsx)(n.h5,{id:"opening-tinyormpro-main-project-file",children:"Opening TinyORM.pro (main project file)"}),"\n",(0,s.jsxs)(n.p,{children:["Now you can open the ",(0,s.jsx)(n.code,{children:"TinyORM.pro"})," project in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["This will open the ",(0,s.jsx)(n.code,{children:"Configure Project"})," tab, select some kit and update build folder paths to meet our ",(0,s.jsx)(n.a,{href:"#folders-structure",children:"folders structure"})," or like you want."]}),"\n",(0,s.jsx)("img",{src:i(885).A,alt:"TinyORM - QtCreator - Configure Project",width:"760"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can force the ",(0,s.jsx)(n.code,{children:"QtCreator"})," to generate a build folders structure as is described ",(0,s.jsx)(n.a,{href:"#qtcreator-default-build-directory",children:"above"}),"."]})}),"\n",(0,s.jsxs)(n.p,{children:["You are ready to configure build options, hit ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"5"})," to open ",(0,s.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,s.jsx)(n.code,{children:"Build"})," in the left sidebar to open the ",(0,s.jsx)(n.code,{children:"Build Settings"}),", it should look similar to the following picture."]}),"\n",(0,s.jsxs)(n.p,{children:["Disable ",(0,s.jsx)(n.code,{children:"QML debugging and profiling"})," and ",(0,s.jsx)(n.code,{children:"Qt Quick Compiler"}),", they are not used."]}),"\n",(0,s.jsx)("img",{src:i(7619).A,alt:"TinyORM - QtCreator - Build Settings",width:"760"}),"\n",(0,s.jsxs)(n.p,{children:["If you want to change some ",(0,s.jsx)(n.code,{children:"TinyORM"})," build options, you can pass them to the ",(0,s.jsx)(n.code,{children:"Build Steps"})," - ",(0,s.jsx)(n.code,{children:"qmake TinyORM.pro"})," - ",(0,s.jsx)(n.code,{children:"Additional arguments"})," input field. It can look like this."]}),"\n",(0,s.jsx)("img",{src:i(2721).A,alt:"TinyORM - QtCreator - Build Settings - Additional arguments",width:"660"}),"\n",(0,s.jsx)(n.h4,{id:"build-tinyorm-1",children:"Build TinyORM"}),"\n",(0,s.jsxs)(n.p,{children:["Everything is ready for build, you can press ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"b"})," to build the project."]}),"\n",(0,s.jsx)(n.h3,{id:"qmake-build-options",children:"qmake build options"}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.th,{children:[(0,s.jsx)(n.code,{children:"CONFIG"})," ",(0,s.jsx)("small",{children:"Option Name"})]}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_loadable_drivers"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started",children:(0,s.jsx)(n.code,{children:"TinyDrivers"})})," as a shared library and SQL database drivers (eg. ",(0,s.jsx)(n.code,{children:"TinyMySql"}),") as shared libraries (",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-loadable-sql-drivers-build",children:(0,s.jsx)(n.code,{children:"Loadable"})})," modules) that are loaded at runtime using ",(0,s.jsx)(n.code,{children:"LoadLibrary()"})," on Windows or ",(0,s.jsx)(n.code,{children:"dlopen()"})," on Linux."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_mysql_driver"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," MySQL database driver.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It's enabled by default when ",(0,s.jsx)(n.code,{children:"build_shared_drivers"}),", ",(0,s.jsx)(n.code,{children:"build_loadable_drivers"}),", or ",(0,s.jsx)(n.code,{children:"build_static_drivers"})," is enabled.",(0,s.jsx)("br",{}),"Available when: ",(0,s.jsx)(n.code,{children:"build_shared_drivers"})," OR ",(0,s.jsx)(n.code,{children:"build_loadable_drivers"})," OR ",(0,s.jsx)(n.code,{children:"build_static_drivers"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_shared_drivers"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," as a ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-shared-library-build",children:(0,s.jsx)(n.code,{children:"Shared"})})," library."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_static_drivers"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," as a ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-static-build",children:(0,s.jsx)(n.code,{children:"Static"})})," library archive.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"build_static_drivers"})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option will be select by default when the ",(0,s.jsx)(n.a,{href:"#qmake-static",children:(0,s.jsx)(n.code,{children:"CONFIG*=static"})})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_tests"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Build TinyORM unit tests."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ccache"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Enable compiler cache. ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:"Homepage"}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It works on Windows and Unix systems. This option overrides qmake's ",(0,s.jsx)(n.code,{children:"ccache"})," option. It internally calls qmake's ",(0,s.jsx)(n.a,{href:"#qmake-ccache",children:(0,s.jsx)(n.code,{children:"ccache"})})," option on Unix and ",(0,s.jsx)(n.a,{href:"#tiny_ccache_win32",children:(0,s.jsx)(n.code,{children:"tiny_ccache_win32"})})," on Windows.",(0,s.jsx)("br",{}),"Reason: It allows using the same option on both OS-es.",(0,s.jsx)("br",{}),"See ",(0,s.jsx)(n.a,{href:"#ccache-support",children:"Ccache support"})," for more information."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_autoconf"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Disable the ",(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:(0,s.jsx)(n.code,{children:"Auto-configuration"})})," feature ",(0,s.jsxs)("small",{children:["(auto-configuration is enabled by default from ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),")"]}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_dotenv"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Disable the ",(0,s.jsx)(n.a,{href:"#environment-files",children:(0,s.jsx)(n.code,{children:"tiny_dotenv"})})," feature ",(0,s.jsxs)("small",{children:["(environment files are enabled by default from ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),")"]}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_thread_local"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Remove all ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/c/language/storage_duration",children:(0,s.jsx)(n.code,{children:"thread_local"})})," storage duration specifiers, it disables multi-threading support."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_orm"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"ORM-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"enabled"}),", then only the ",(0,s.jsx)(n.code,{children:"query builder"})," without ",(0,s.jsx)(n.code,{children:"ORM"})," is compiled. Also excludes ",(0,s.jsx)(n.code,{children:"ORM-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_tom"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"Tom-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"disabled"}),", then it also excludes ",(0,s.jsx)(n.code,{children:"Tom-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"extern_constants"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Use ",(0,s.jsx)(n.code,{children:"extern"})," constants instead of ",(0,s.jsx)(n.code,{children:"inline"})," constants in the ",(0,s.jsx)(n.code,{children:"shared build"}),".",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"ON"})," is highly recommended for the ",(0,s.jsx)(n.code,{children:"shared build"})," ",(0,s.jsx)("small",{children:"(by default)"}),";",(0,s.jsx)("br",{}),"is always ",(0,s.jsx)(n.code,{children:"OFF"})," for the ",(0,s.jsx)(n.code,{children:"static build"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)("code",{children:"CONFIG(shared|dll):!inline_constants"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"inline_constants"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Use ",(0,s.jsx)(n.code,{children:"inline"})," constants instead of ",(0,s.jsx)(n.code,{children:"extern"})," constants in the ",(0,s.jsx)(n.code,{children:"shared build"}),".",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"OFF"})," is highly recommended for the ",(0,s.jsx)(n.code,{children:"shared build"}),";",(0,s.jsx)("br",{}),"is always ",(0,s.jsx)(n.code,{children:"ON"})," for the ",(0,s.jsx)(n.code,{children:"static build"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"link_pkgconfig_off"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Link against ",(0,s.jsx)(n.code,{children:"mysqlclient"})," or ",(0,s.jsx)(n.code,{children:"libmariadb"})," with ",(0,s.jsx)(n.code,{children:"PKGCONFIG"}),".",(0,s.jsx)("br",{}),"Used only in the ",(0,s.jsx)(n.code,{children:"Unix"})," and ",(0,s.jsx)(n.code,{children:"MinGW"})," ",(0,s.jsx)(n.strong,{children:"shared"})," build ",(0,s.jsxs)("small",{children:["(exactly ",(0,s.jsx)("code",{children:"win32-g++|win32-clang-g++"}),")"]})," and when ",(0,s.jsx)(n.code,{children:"mysql_ping"})," is also defined to link against ",(0,s.jsx)(n.code,{children:"mysqlclient"})," or ",(0,s.jsx)(n.code,{children:"libmariadb"}),", ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L132",children:"source code"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"unix:mysql_ping"})," or ",(0,s.jsx)("code",{children:"(win32-g++|win32-clang-g++):mysql_ping:!static:!staticlib"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"mysql_ping"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.code,{children:"Orm::MySqlConnection::pingDatabase()"})," method."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"tiny_ccache_win32"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Enable compiler cache. ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:"Homepage"}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It works only on Windows systems. It works well with the MSYS2 ",(0,s.jsx)(n.code,{children:"g++"}),", ",(0,s.jsx)(n.code,{children:"clang++"}),", ",(0,s.jsx)(n.code,{children:"msvc"}),", and ",(0,s.jsx)(n.code,{children:"clang-cl"})," with ",(0,s.jsx)(n.code,{children:"msvc"}),". It replaces the ",(0,s.jsx)(n.code,{children:"-Zi"})," and ",(0,s.jsx)(n.code,{children:"-ZI"})," compiler options with the ",(0,s.jsx)(n.code,{children:"-Z7"})," for debug builds as the ",(0,s.jsx)(n.code,{children:"-Zi"})," and ",(0,s.jsx)(n.code,{children:"-ZI"})," compiler options are not supported (",(0,s.jsx)(n.a,{href:"https://github.com/ccache/ccache/issues/1040",children:"link"})," to the issue) and disables ",(0,s.jsx)(n.code,{children:"precompile_header"})," if ",(0,s.jsx)(n.code,{children:"ccache"})," ",(0,s.jsx)(n.code,{children:"<4.10"})," as they are not supported on Windows."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"tom_example"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build the ",(0,s.jsx)("abbr",{title:"TinyORM Migrations",children:(0,s.jsx)(n.code,{children:"tom"})})," console application example."]})]})]})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Advanced ",(0,s.jsx)(n.code,{children:"TinyORM"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ubsan"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Allows to enable ",(0,s.jsx)(n.a,{href:"https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html",children:"UBSan"})," sanitizer (Clang only)."]})]})})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Important ",(0,s.jsx)(n.code,{children:"qmake"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{name:"qmake",children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.th,{children:[(0,s.jsx)(n.code,{children:"CONFIG"})," ",(0,s.jsx)("small",{children:"Option Name"})]}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ccache"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable compiler cache. ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:"Homepage"}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It works only on the Unix systems. It works well with ",(0,s.jsx)(n.code,{children:"g++"})," and ",(0,s.jsx)(n.code,{children:"clang++"})," and also supports precompiled headers. TinyORM overrides this qmake option with the ",(0,s.jsx)(n.a,{href:"#ccache",children:(0,s.jsx)(n.code,{children:"ccache"})})," option.",(0,s.jsx)("br",{}),"See ",(0,s.jsx)(n.a,{href:"#ccache-support",children:"Ccache support"})," for more information."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ltcg"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Interprocedural_optimization",children:"Link time code optimization"})," (",(0,s.jsx)(n.a,{href:"https://wiki.gentoo.org/wiki/LTO",children:"LTO"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Works on all ",(0,s.jsx)(n.a,{href:"/supported-compilers",children:"Supported Compilers"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"precompile_header"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Enable precompiled headers, you can disable them with:",(0,s.jsx)("br",{})," ",(0,s.jsx)(n.code,{children:"CONFIG-=precompile_header"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"precompile_header"})," is enabled by default on ",(0,s.jsx)(n.code,{children:"msvc"}),", ",(0,s.jsx)(n.code,{children:"g++"}),", ",(0,s.jsx)(n.code,{children:"clang++"}),", ",(0,s.jsx)(n.code,{children:"clang-cl"})," on ",(0,s.jsx)(n.code,{children:"Windows"})," and disabled by default on ",(0,s.jsx)(n.code,{children:"linux"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"static"}),(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"staticlib"})]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build as a ",(0,s.jsx)(n.code,{children:"static"})," library (lib only).",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["If you want to build all libraries in the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project as static library archives and link against static libraries use the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qmake-variable-reference.html#config",children:(0,s.jsx)(n.code,{children:"CONFIG += static"})}),". Don't use the ",(0,s.jsx)(n.code,{children:"CONFIG += staticlib"}),".",(0,s.jsx)("br",{}),"See ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/NOTES.txt",children:"NOTES.txt"})," for more information (search ",(0,s.jsx)(n.code,{children:"static vs staticlib"}),")."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"static_runtime"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Link against the ",(0,s.jsx)(n.code,{children:"shared"})," (dynamic) or ",(0,s.jsx)(n.code,{children:"static"})," run-time library.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"-MD"})," becomes ",(0,s.jsx)(n.code,{children:"-MT"})," and ",(0,s.jsx)(n.code,{children:"-MDd"})," becomes ",(0,s.jsx)(n.code,{children:"-MTd"}),". It works only on ",(0,s.jsx)(n.code,{children:"MSVC"})," and ",(0,s.jsx)(n.code,{children:"MinGW"})," or ",(0,s.jsx)(n.code,{children:"MSYS2"}),".",(0,s.jsx)("br",{}),"Please ",(0,s.jsx)("u",{children:"don't use"})," this option.",(0,s.jsx)("br",{}),"Available when: ",(0,s.jsx)(n.code,{children:"msvc"})," or ",(0,s.jsx)(n.code,{children:"mingw"})]})]})]})]})]})})}),"\n",(0,s.jsxs)(n.h3,{id:"consume-tinyorm-library-qmake",children:["Consume TinyOrm library ",(0,s.jsx)("small",{children:"(qmake)"})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/qmake/TinyOrm.pri",children:(0,s.jsx)(n.code,{children:"TinyOrm.pri"})})," file is available to simplify the integration of the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library into your application. It sets up and configures the ",(0,s.jsx)(n.code,{children:"CONFIG"})," and ",(0,s.jsx)(n.code,{children:"DEFINES"})," qmake variables, adds the ",(0,s.jsx)(n.code,{children:"TinyORM"}),", ",(0,s.jsx)("abbr",{title:"TinyORM Migrations",children:(0,s.jsx)(n.code,{children:"tom"})}),", and ",(0,s.jsx)(n.code,{children:"vcpkg"})," header files on the system ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," (cross-platform using the ",(0,s.jsx)(n.code,{children:"-isystem"})," or ",(0,s.jsx)(n.code,{children:"-imsvc"}),"), links against the TinyORM ",(0,s.jsx)(n.code,{children:"shared"})," or ",(0,s.jsx)(n.code,{children:"static"})," library using the ",(0,s.jsx)(n.code,{children:"LIBS"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["You can use it to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library when you are linking against it. It does a very similar thing like the CMake's ",(0,s.jsx)(n.code,{children:"Find Modules"})," feature."]}),"\n",(0,s.jsx)(n.h4,{id:"requirements",children:"Requirements"}),"\n",(0,s.jsx)(n.p,{children:"It has a few requirements, you need to:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["specify path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," qmake features (",(0,s.jsx)(n.code,{children:".prf"})," files) using the ",(0,s.jsx)(n.code,{children:"QMAKEFEATURES"})," variable that can only be set in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file"]}),"\n",(0,s.jsxs)(n.li,{children:["specify ",(0,s.jsx)(n.code,{children:"qmake"})," or ",(0,s.jsx)(n.code,{children:"environment"})," variables to find the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation ",(0,s.jsxs)("small",{children:["(",(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})," and ",(0,s.jsx)(n.code,{children:"TINY_VCPKG_TRIPLET"}),")"]})]}),"\n",(0,s.jsxs)(n.li,{children:["specify path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder ",(0,s.jsxs)("small",{children:["(",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"}),")"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["you can specify it ",(0,s.jsx)(n.strong,{children:"manually"})]}),"\n",(0,s.jsxs)(n.li,{children:["or you can use ",(0,s.jsxs)(n.a,{href:"#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["build your application with the same ",(0,s.jsx)(n.code,{children:"CONFIG"})," ",(0,s.jsx)(n.code,{children:"qmake"})," variables that were used when building the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library"]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Let's explain one by one."}),"\n",(0,s.jsx)(n.h5,{id:"qmakefeatures",children:(0,s.jsx)(n.code,{children:"QMAKEFEATURES"})}),"\n",(0,s.jsxs)(n.p,{children:["Create the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file in your application root folder with the following content."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# Path to the PARENT folder of the TinyORM source folder\nTINY_MAIN_DIR = $$clean_path()\n# To find .env and .env.$$QMAKE_PLATFORM files in YOUR project\nTINY_DOTENV_ROOT = $$PWD\n\n# Path to the TinyORM build folder (specified manually)\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/)\n# vcpkg - range-v3 and tabulate\nTINY_VCPKG_ROOT = $$quote(/vcpkg/)\n#TINY_VCPKG_TRIPLET = x64-windows\n\n# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants\nQMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You can move all ",(0,s.jsx)(n.code,{children:"qmake"})," variables that are part of the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration process to the ",(0,s.jsx)(n.code,{children:".env"})," file if you want (recommended), this is possible because the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," enables the ",(0,s.jsx)(n.a,{href:"#environment-files",children:(0,s.jsx)(n.code,{children:"Environment files"})})," feature by default."]}),"\n",(0,s.jsxs)(n.p,{children:["You can look at the ",(0,s.jsx)(n.a,{href:"/building/hello-world#auto-configure-using-qmake_conf-and-env",children:"Auto-configure using .qmake.conf and .env"})," example for ",(0,s.jsx)(n.code,{children:"Hello world"})," project of what must stay in the ",(0,s.jsx)(n.code,{children:"qmake.conf"})," file and what can be moved to the ",(0,s.jsx)(n.code,{children:".env"})," files."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can use the ",(0,s.jsxs)(n.a,{href:"#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," if you don't like to specify it manually."]})}),"\n",(0,s.jsxs)(n.h5,{id:"variables-affecting-tinyormpri",children:["Variables affecting ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})]}),"\n",(0,s.jsxs)(n.p,{children:["You must define the following variables before the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," is included:"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation folder.",(0,s.jsx)("br",{}),"If not defined, then it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_TRIPLET"})}),(0,s.jsxs)(n.td,{children:["The ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," to use ",(0,s.jsx)("small",{children:"(vcpkg/installed/$$TINY_VCPKG_TRIPLET/)"}),".",(0,s.jsx)("br",{}),"If not defined, then it tries to guess the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," based on the current compiler and OS (based on the ",(0,s.jsx)(n.code,{children:"QMAKESPEC"}),"), and as the last thing, it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_DEFAULT_TRIPLET"})," environment variable."]})]})]})]}),"\n",(0,s.jsx)(n.p,{children:"These variables will be set after the configuration is done:"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_BUILD_SUBFOLDER"})}),(0,s.jsxs)(n.td,{children:["Folder by release type if ",(0,s.jsx)(n.code,{children:"CONFIG+=debug_and_release"})," is defined ",(0,s.jsx)("small",{children:"(/debug, /release, or an empty string)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_CCACHE_BUILD"})}),(0,s.jsxs)(n.td,{children:["To correctly link ",(0,s.jsx)(n.code,{children:"ccache"})," build against a ",(0,s.jsx)(n.code,{children:"ccache"})," build ",(0,s.jsx)("small",{children:"(_ccache or an empty string)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MSVC_VERSION"})}),(0,s.jsxs)(n.td,{children:["The ",(0,s.jsx)(n.code,{children:"msvc"})," compiler string ",(0,s.jsx)("small",{children:"(MSVC2022 or MSVC2019)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_QT_VERSION_UNDERSCORED"})}),(0,s.jsxs)(n.td,{children:["Underscored ",(0,s.jsx)(n.code,{children:"Qt"})," version ",(0,s.jsx)("small",{children:"(eg. 6_7_2)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_RELEASE_TYPE_CAMEL"})}),(0,s.jsxs)(n.td,{children:["Build type string ",(0,s.jsx)("small",{children:"(Debug, Profile, or Release)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_INCLUDE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"include"})," folder ",(0,s.jsx)("small",{children:"(vcpkg/installed//include/)"}),"."]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["Then you simply include the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," in your project file."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='AnyProject.pro'",children:"include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["And that is all, now you should be able to link against the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. \ud83d\udc4c"]}),"\n",(0,s.jsx)(n.h5,{id:"manual-configuration-examples",children:"Manual configuration examples"}),"\n",(0,s.jsxs)(n.p,{children:["Frankly, there is no reason to use the Manual configuration (define the variables described below before the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," inclusion), the only reason to use it is when you want more control over this process or want to define everything yourself. I'll leave this section here to show how things work."]}),"\n",(0,s.jsxs)(n.p,{children:["You will have to link against the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library manually if you don't set the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," ",(0,s.jsx)(n.code,{children:"qmake"})," variable before the inclusion of the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," file. The ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," is auto-detected every time."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"{9}",children:"# Link against TinyORM library\n# ---\nTINY_MAIN_DIR = $$clean_path()\n\n# Configure TinyORM library\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n\n# TinyORM library path\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake)\nLIBS += $$quote(-L$$TINYORM_BUILD_TREE/build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)\nLIBS += -lTinyOrm\n"})})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"{9}",children:"# Link against TinyORM library\n# ---\nTINY_MAIN_DIR = $$clean_path()\n\n# Configure TinyORM library\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n\n# TinyORM library path\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake)\nLIBS += $$quote(-L$$TINYORM_BUILD_TREE/build-TinyORM-Desktop_Qt_6_7_2_GCC_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)\nLIBS += -lTinyOrm\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["The same is true for the ",(0,s.jsx)(n.code,{children:"vcpkg"})," include path. If you don't set the ",(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})," or have not defined the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable, then you need to set up the ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," for the ",(0,s.jsx)(n.code,{children:"vcpkg"})," that provides the ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," header files."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# vcpkg - range-v3 and tabulate\n# ---\nINCLUDEPATH += $$quote(/vcpkg/installed/x64-windows/include/)\n"})})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# vcpkg - range-v3 and tabulate\n# ---\nQMAKE_CXXFLAGS += -isystem $$shell_quote(/vcpkg/installed/x64-linux/include/)\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["You can also use TinyORM's ",(0,s.jsx)(n.code,{children:"qmake"})," function ",(0,s.jsx)(n.code,{children:"tiny_add_system_includepath()"})," which handles ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," in a cross-platform way."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# vcpkg - range-v3 and tabulate\n# ---\nload(tiny_system_includepath)\ntiny_add_system_includepath(/vcpkg/installed/x64-linux/include/)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Do not forget to add ",(0,s.jsx)(n.code,{children:"TinyOrm0.dll"})," on the path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux, so your application can find it during execution."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`$env:Path = "${(0,x.OZ)(y.b,!1)}\\TinyORM\\TinyORM-builds-qmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,x.OZ)(y.xj)}/TinyORM/TinyORM-builds-qmake/build-debug\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.admonition,{type:"tip",children:[(0,s.jsxs)(n.p,{children:["On Linux ",(0,s.jsx)(n.code,{children:"-isystem"})," marks the directory as a system directory, it prevents warnings."]}),(0,s.jsxs)(n.p,{children:["On Windows you can use ",(0,s.jsx)(n.code,{children:"QMAKE_CXXFLAGS_WARN_ON = -external:anglebrackets -external:W0"}),", it applies a warning level 0 to the angel bracket includes; ",(0,s.jsx)(n.code,{children:"#include "}),"."]}),(0,s.jsxs)(n.p,{children:["With the ",(0,s.jsx)(n.code,{children:"clang-cl"})," with ",(0,s.jsx)(n.code,{children:"MSVC"})," you can use ",(0,s.jsx)(n.code,{children:"-imsvc"}),"."]})]}),"\n",(0,s.jsx)(n.h3,{id:"auto-configuration-internals",children:"Auto-configuration internals"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"qmake"})," build system does not support ",(0,s.jsx)(n.code,{children:"auto-configuration"})," of dependencies out of the box but ",(0,s.jsx)(n.code,{children:"TinyORM"})," from ",(0,s.jsx)(n.code,{children:"v0.34.0"})," added its own ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature along with the ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," qmake feature. These new features allow us to ",(0,s.jsx)(n.code,{children:"auto-configure"})," ",(0,s.jsx)(n.code,{children:"TinyORM"})," project, and with their help, the ",(0,s.jsx)(n.code,{children:"conf.pri"})," files can be ",(0,s.jsx)("u",{children:"skipped entirely"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["While it adds additional complexity to the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration process, the benefits are significant."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature is designed to find the ",(0,s.jsx)(n.code,{children:"vcpkg"})," and ",(0,s.jsx)(n.code,{children:"MySQL"})," installations, and ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," to include the ",(0,s.jsx)(n.code,{children:".env"})," and ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"})," files in the project's root folder. These new features can be configured using ",(0,s.jsx)(n.code,{children:"qmake"})," and ",(0,s.jsx)(n.code,{children:"environment"})," variables, and they also contain some guessing logic if these variables are not defined."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_autoconf",children:(0,s.jsx)(n.code,{children:"disable_autoconf"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_autoconf"}),")."]}),"\n",(0,s.jsxs)(n.p,{children:["These are ",(0,s.jsx)("u",{children:(0,s.jsx)(n.code,{children:"qmake"})})," and ",(0,s.jsx)("u",{children:(0,s.jsx)(n.code,{children:"environment"})})," variables that affect the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature:"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation folder.",(0,s.jsx)("br",{}),"If not defined, then it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_TRIPLET"})}),(0,s.jsxs)(n.td,{children:["The ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," to use ",(0,s.jsx)("small",{children:"(vcpkg/installed/$$TINY_VCPKG_TRIPLET/)"}),".",(0,s.jsx)("br",{}),"If not defined, then it tries to guess the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," based on the current compiler and OS (based on the ",(0,s.jsx)(n.code,{children:"QMAKESPEC"}),"), and as the last thing, it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_DEFAULT_TRIPLET"})," environment variable."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MYSQL_ROOT"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"MySQL"})," installation folder.",(0,s.jsx)("br",{}),"If not defined, then it tries to guess the ",(0,s.jsx)(n.code,{children:"MySQL"})," installation folder (",(0,s.jsx)(n.code,{children:"win32"})," only): ",(0,s.jsx)("code",{children:"$$(ProgramFiles)/MySQL/MySQL Server (8.4|8.3|8.2|8.1|8.0|5.7)/"})]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["You can set these variables in the ",(0,s.jsx)(n.code,{children:".env"})," (recommended) or ",(0,s.jsx)(n.code,{children:"conf.pri"})," files, in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file (or wherever you want), or as environment variables."]}),"\n",(0,s.jsxs)(n.p,{children:["These variables will be set after ",(0,s.jsx)(n.code,{children:"auto-configuration"})," is done:"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_INCLUDE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"include"})," folder ",(0,s.jsx)("small",{children:"(vcpkg/installed//include/)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MYSQL_INCLUDE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"MySQL"})," ",(0,s.jsx)(n.code,{children:"include"})," folder ",(0,s.jsx)("small",{children:"(MySQL Server 8.4/include/)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MYSQL_LIB"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"MySQL"})," ",(0,s.jsx)(n.code,{children:"lib"})," folder ",(0,s.jsx)("small",{children:"(MySQL Server 8.4/lib/)"}),"."]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TINY_MYSQL_INCLUDE"})," and ",(0,s.jsx)(n.code,{children:"TINY_MYSQL_LIB"})," are only set on ",(0,s.jsx)(n.code,{children:"win32"})," platform except ",(0,s.jsx)(n.code,{children:"mingw"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"environment-files",children:"Environment files"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature allows us to define the ",(0,s.jsx)(n.code,{children:".env"})," and ",(0,s.jsx)(n.code,{children:".env.$$TINY_DOTENV_PLATFORM"})," files in the project's root folder. These files are loaded as early as possible so you can affect the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration process. On the other hand, the ",(0,s.jsx)(n.code,{children:"conf.pri"})," files are loaded as late as possible, and they can be used to override the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:".env"})," file is included ",(0,s.jsx)("u",{children:"first"})," and is included on all platforms."]}),"\n",(0,s.jsxs)(n.p,{children:["There is only one requirement for this feature to work correctly, and that is to set the ",(0,s.jsx)(n.code,{children:"TINY_DOTENV_ROOT"})," ",(0,s.jsx)(n.code,{children:"qmake"})," variable to the project's root folder. This variable is ",(0,s.jsx)(n.strong,{children:"already"})," set in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file for the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project."]}),"\n",(0,s.jsx)(n.p,{children:"Then the following names are taken into account: .env, .env.win32, .env.unix, .env.mingw"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# To find .env and .env.$$QMAKE_PLATFORM files\nTINY_DOTENV_ROOT = $$PWD\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_dotenv",children:(0,s.jsx)(n.code,{children:"disable_dotenv"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_dotenv"}),")."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"Environment files"})," don't work in the ",(0,s.jsx)(n.code,{children:"CMake"})," builds."]})}),"\n",(0,s.jsxs)(n.h4,{id:"partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]}),"\n",(0,s.jsxs)(n.p,{children:["You don't have to manually define the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," in ",(0,s.jsx)(n.code,{children:".env"})," or ",(0,s.jsx)(n.code,{children:".qmake.conf"})," files. The ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," absolute path can be put together for you (this is happening inside the ",(0,s.jsx)(n.code,{children:"variables.pri"})," file) and ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder name can be guessed for you too."]}),"\n",(0,s.jsxs)(n.p,{children:["You must define the following variables before the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," will be included to make this real (set them in the ",(0,s.jsx)(n.code,{children:".qmake.conf"}),"):"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MAIN_DIR"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.strong,{children:"PARENT"})," folder of the ",(0,s.jsx)(n.code,{children:"TinyORM"})," source folder."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.strong,{children:"current"})," build tree - ",(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE = $$shadowed($$PWD)"}),"."]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TINY_MAIN_DIR"})," is required for another features anyway (so it should already be set) and all that's left is to set the ",(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# Path to the current build tree (used to guess the TinyORM build tree)\nTINY_BUILD_TREE = $$shadowed($$PWD)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If you will follow this pattern or logic then you can switch ",(0,s.jsx)(n.code,{children:"QtCreator Kits"})," and the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," will be ",(0,s.jsx)(n.strong,{children:"auto-generated"})," correctly and will always point to the correct ",(0,s.jsx)(n.code,{children:"TinyORM"})," build tree."]}),"\n",(0,s.jsxs)(n.p,{children:["It works this way, all is happening inside the ",(0,s.jsx)(n.code,{children:"variables.pri"}),", it takes a build folder name for the ",(0,s.jsx)(n.strong,{children:"current"})," project eg. ",(0,s.jsx)(n.code,{children:"build-HelloWorld-Desktop_Qt_6_7_2_MSVC2022_64bit-Debug"}),", replaces the ",(0,s.jsx)(n.code,{children:"HelloWorld"})," with the ",(0,s.jsx)(n.code,{children:"TinyORM"})," and as we already know the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder location we can simply concatenate these paths like ",(0,s.jsx)(n.code,{children:"$$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSVC2022_64bit-Debug"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["This will only work if you follow the recommended ",(0,s.jsx)(n.a,{href:"#folders-structure",children:(0,s.jsx)(n.code,{children:"Folders structure"})}),"."]})}),"\n",(0,s.jsx)(n.h3,{id:"manual-configuration-internals",children:"Manual configuration internals"}),"\n",(0,s.jsxs)(n.p,{children:["There is not much to say about the ",(0,s.jsx)(n.code,{children:"Manual configuration"})," feature. It uses ",(0,s.jsx)(n.code,{children:"conf.pri"})," files (there are four, one for every project or sub-project), and every project has prepared its own ",(0,s.jsx)(n.code,{children:"conf.pri.example"})," file for faster initial configuration."]}),"\n",(0,s.jsxs)(n.p,{children:["These ",(0,s.jsx)(n.code,{children:"conf.pri.example"})," files are nicely commented on, so you can see what needs to be modified. The ",(0,s.jsx)(n.code,{children:"conf.pri"})," files are loaded as late as possible, and they can be used to override the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration."]}),"\n",(0,s.jsxs)(n.p,{children:["If the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature is disabled and there are no ",(0,s.jsx)(n.code,{children:"conf.pri"})," files, then the ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration or build will fail at 100%."]}),"\n",(0,s.jsxs)(n.p,{children:["These ",(0,s.jsx)(n.code,{children:"conf.pri"})," files are intended for configuring qmake's ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," and ",(0,s.jsx)(n.code,{children:"LIBS"}),", ",(0,s.jsx)(n.code,{children:"CONFIG"})," or eg. ",(0,s.jsx)(n.code,{children:"QMAKE_LFLAGS"}),", or any other ",(0,s.jsx)(n.code,{children:"qmake"})," options or variables."]}),"\n",(0,s.jsx)(n.h2,{id:"ccache-support",children:"Ccache support"}),"\n",(0,s.jsxs)(n.p,{children:["The TinyORM supports the ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:(0,s.jsx)(n.code,{children:"ccache"})})," out of the box for all ",(0,s.jsx)(n.a,{href:"/supported-compilers",children:"supported compilers"}),". For ",(0,s.jsx)(n.code,{children:"qmake"})," you can enable it using the ",(0,s.jsx)(n.a,{href:"#ccache",children:(0,s.jsx)(n.code,{children:"CONFIG+=ccache"})})," and for ",(0,s.jsx)(n.code,{children:"CMake"})," you can set the ",(0,s.jsx)(n.a,{href:"#CMAKE_CXX_COMPILER_LAUNCHER",children:(0,s.jsx)(n.code,{children:"CMAKE_CXX_COMPILER_LAUNCHER=ccache"})}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["On ",(0,s.jsx)(n.code,{children:"Linux"})," it's clear, the ",(0,s.jsx)(n.code,{children:"ccache"})," is fully supported and works also with the ",(0,s.jsx)(n.code,{children:"precompiled headers"}),". But was necessary to add some workarounds to the ",(0,s.jsx)(n.code,{children:"qmake"}),"/",(0,s.jsx)(n.code,{children:"CMake"})," build systems to make out of the box support on ",(0,s.jsx)(n.code,{children:"Windows"}),". When you enable the ",(0,s.jsx)(n.code,{children:"ccache"})," on ",(0,s.jsx)(n.code,{children:"Windows"})," then the build system replaces the ",(0,s.jsx)(n.code,{children:"-Zi"})," and ",(0,s.jsx)(n.code,{children:"-ZI"})," compiler options with the ",(0,s.jsx)(n.code,{children:"-Z7"})," (link to the ",(0,s.jsx)(n.a,{href:"https://github.com/ccache/ccache/issues/1040",children:"issue"}),") and disables ",(0,s.jsx)(n.code,{children:"precompiled headers"})," if ",(0,s.jsx)(n.code,{children:"ccache <4.10"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can install the ",(0,s.jsx)(n.code,{children:"ccache"})," using the ",(0,s.jsx)(n.code,{children:"scoop install ccache"})," command on Windows. See the ",(0,s.jsx)(n.a,{href:"/dependencies#linux-installation-ccache",children:"Dependencies"})," page for how to install ",(0,s.jsx)(n.code,{children:"ccache"})," on Linux."]})})]})}function I(e={}){const{wrapper:n}={...(0,d.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(M,{...e})}):M(e)}},9365:(e,n,i)=>{i.d(n,{A:()=>l});i(6540);var s=i(4164);const d={tabItem:"tabItem_Ymn6"};var r=i(4848);function l(e){let{children:n,hidden:i,className:l}=e;return(0,r.jsx)("div",{role:"tabpanel",className:(0,s.A)(d.tabItem,l),hidden:i,children:n})}},1470:(e,n,i)=>{i.d(n,{A:()=>_});var s=i(6540),d=i(4164),r=i(3104),l=i(6347),c=i(205),t=i(7485),o=i(1682),a=i(679);function h(e){return s.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,s.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function x(e){const{values:n,children:i}=e;return(0,s.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:i,attributes:s,default:d}}=e;return{value:n,label:i,attributes:s,default:d}}))}(i);return function(e){const n=(0,o.X)(e,((e,n)=>e.value===n.value));if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[n,i])}function j(e){let{value:n,tabValues:i}=e;return i.some((e=>e.value===n))}function u(e){let{queryString:n=!1,groupId:i}=e;const d=(0,l.W6)(),r=function(e){let{queryString:n=!1,groupId:i}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!i)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return i??null}({queryString:n,groupId:i});return[(0,t.aZ)(r),(0,s.useCallback)((e=>{if(!r)return;const n=new URLSearchParams(d.location.search);n.set(r,e),d.replace({...d.location,search:n.toString()})}),[r,d])]}function p(e){const{defaultValue:n,queryString:i=!1,groupId:d}=e,r=x(e),[l,t]=(0,s.useState)((()=>function(e){let{defaultValue:n,tabValues:i}=e;if(0===i.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!j({value:n,tabValues:i}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${i.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const s=i.find((e=>e.default))??i[0];if(!s)throw new Error("Unexpected error: 0 tabValues");return s.value}({defaultValue:n,tabValues:r}))),[o,h]=u({queryString:i,groupId:d}),[p,m]=function(e){let{groupId:n}=e;const i=function(e){return e?`docusaurus.tab.${e}`:null}(n),[d,r]=(0,a.Dv)(i);return[d,(0,s.useCallback)((e=>{i&&r.set(e)}),[i,r])]}({groupId:d}),b=(()=>{const e=o??p;return j({value:e,tabValues:r})?e:null})();(0,c.A)((()=>{b&&t(b)}),[b]);return{selectedValue:l,selectValue:(0,s.useCallback)((e=>{if(!j({value:e,tabValues:r}))throw new Error(`Can't select invalid tab value=${e}`);t(e),h(e),m(e)}),[h,m,r]),tabValues:r}}var m=i(2303);const b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var f=i(4848);function g(e){let{className:n,block:i,selectedValue:s,selectValue:l,tabValues:c}=e;const t=[],{blockElementScrollPositionUntilNextRender:o}=(0,r.a_)(),a=e=>{const n=e.currentTarget,i=t.indexOf(n),d=c[i].value;d!==s&&(o(n),l(d))},h=e=>{let n=null;switch(e.key){case"Enter":a(e);break;case"ArrowRight":{const i=t.indexOf(e.currentTarget)+1;n=t[i]??t[0];break}case"ArrowLeft":{const i=t.indexOf(e.currentTarget)-1;n=t[i]??t[t.length-1];break}}n?.focus()};return(0,f.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,d.A)("tabs",{"tabs--block":i},n),children:c.map((e=>{let{value:n,label:i,attributes:r}=e;return(0,f.jsx)("li",{role:"tab",tabIndex:s===n?0:-1,"aria-selected":s===n,ref:e=>t.push(e),onKeyDown:h,onClick:a,...r,className:(0,d.A)("tabs__item",b.tabItem,r?.className,{"tabs__item--active":s===n}),children:i??n},n)}))})}function y(e){let{lazy:n,children:i,selectedValue:d}=e;const r=(Array.isArray(i)?i:[i]).filter(Boolean);if(n){const e=r.find((e=>e.props.value===d));return e?(0,s.cloneElement)(e,{className:"margin-top--md"}):null}return(0,f.jsx)("div",{className:"margin-top--md",children:r.map(((e,n)=>(0,s.cloneElement)(e,{key:n,hidden:e.props.value!==d})))})}function T(e){const n=p(e);return(0,f.jsxs)("div",{className:(0,d.A)("tabs-container",b.tabList),children:[(0,f.jsx)(g,{...n,...e}),(0,f.jsx)(y,{...n,...e})]})}function _(e){const n=(0,m.A)();return(0,f.jsx)(T,{...e,children:h(e.children)},String(n))}},6684:(e,n,i)=>{i.d(n,{A:()=>a});var s=i(6540),d=i(3427),r=i(6347);const l={apiTable:"apiTable_flxF"};var c=i(4848);function t(e,n){let{name:i,children:l}=e;const t=function(e){let n=e;for(;(0,s.isValidElement)(n);)[n]=s.Children.toArray(n.props.children);if("string"!=typeof n)throw new Error(`Could not extract APITable row name from JSX tree:\n${JSON.stringify(e,null,2)}`);return n}(l),o=i?`${i}-${t}`:t,a=`#${o}`,h=(0,r.W6)();return(0,d.A)().collectAnchor(o),(0,c.jsx)("tr",{id:o,tabIndex:0,ref:h.location.hash===a?n:void 0,onClick:e=>{const n=e.target;[n,n.parentElement].some((e=>"A"===e?.tagName.toUpperCase()))||h.push(a)},onKeyDown:e=>{"Enter"===e.key&&h.push(a)},children:l.props.children})}const o=s.forwardRef(t);function a(e){let{children:n,name:i}=e;if("table"!==n.type)throw new Error("Bad usage of APITable component.\nIt is probably that your Markdown table is malformed.\nMake sure to double-check you have the appropriate number of columns for each table row.");const[d,r]=s.Children.toArray(n.props.children),t=(0,s.useRef)(null);(0,s.useEffect)((()=>{t.current?.focus()}),[t]);const a=s.Children.map(r.props.children,(e=>(0,c.jsx)(o,{name:i,ref:t,children:e})));return(0,c.jsxs)("table",{className:l.apiTable,children:[d,(0,c.jsx)("tbody",{children:a})]})}},7324:(e,n,i)=>{i.d(n,{$E:()=>m,A3:()=>f,CW:()=>b,Dx:()=>a,F4:()=>x,Fi:()=>o,J_:()=>_,LQ:()=>g,Lf:()=>v,OO:()=>d,Q7:()=>y,b:()=>c,cy:()=>t,gg:()=>u,kl:()=>j,os:()=>h,pW:()=>r,ux:()=>p,vf:()=>s,xj:()=>l,xt:()=>T});const s="shell",d="database",r="application",l="bash",c="pwsh",t="zsh",o="maria",a="mysql",h="postgres",x="sqlite",j="application",u="bash",p="pwsh",m="zsh",b="MariaDB",f="MySQL",g="PostgreSQL",y="SQLite",T="tinyorm.org",_="$HOME/Code/c/",v="$env:USERPROFILE\\Code\\c\\"},6362:(e,n,i)=>{i.d(n,{A:()=>r});var s=i(6540),d=i(1838);function r(){const e=(0,s.useContext)(d.A);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6694:(e,n,i)=>{i.d(n,{OZ:()=>t,Sn:()=>l,T3:()=>a,bw:()=>o,nC:()=>h,np:()=>c});var s=i(6362),d=i(2303),r=i(7324);const l=function(e,n){return void 0===n&&(n=!0),x((0,s.A)().rootFolder[e]??o(e),e,n)},c=()=>(0,s.A)().rootFolder[r.pW]??o(r.pW),t=function(e,n){if(void 0===n&&(n=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const i=n||e!==r.b?"/":"\\";return x(l(e)+i+c(),e,n)};function o(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,d.A)())return"";switch(e){case r.b:return r.Lf;case r.xj:return r.J_;case r.pW:return r.xt;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function a(e){return e===r.pW}function h(e,n){if(null==n||""===n)return n;const i="$ENV{$1}$2";switch(e){case r.b:return u(n).replace(/\$env:(.+?)(\/.*)/,i);case r.xj:return n.replace(/\$(.+?)(\/.*)/,i);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function x(e,n,i){if(void 0===i&&(i=!0),null==e||""===e)return e;if(n!==r.b)return j(e);const s=j(e);return i?u(s):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(s)}function j(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function u(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},2721:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-additional_arguments-14d3b6b82ad6d28db5b999a462500a6a.png"},7619:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-build_settings-7caa6d7c86232484b82acb24b5a3a6a7.png"},885:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-configure_project-0b6821ea0523567dab9f21b3215055a3.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[395],{1503:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>O,contentTitle:()=>_,default:()=>I,frontMatter:()=>T,metadata:()=>v,toc:()=>R});var s=i(4848),d=i(8453),r=i(8774),l=i(6684),c=i(2364),t=i(9365),o=i(1470),a=i(5556),h=i.n(a),x=i(6694);function j(e){let{groupId:n}=e;return(0,s.jsx)("span",{children:(0,x.OZ)(n)})}j.propTypes={groupId:h().string.isRequired};const u=j;var p=i(4164),m=i(6362);const b={rootFolderInput:"rootFolderInput_ottS",input:"input_OR7e",application:"application_fjej"};function f(e){let{groupId:n,label:i}=e;const{rootFolder:d,setRootFolder:r}=(0,m.A)(),l=(0,x.T3)(n),c=l?"application":"root",t=l?"\nThis folder name is common for all shells (eg. pwsh, bash, ...)":"";return(0,s.jsx)("form",{name:"tinyorm-root-folder-form",className:(0,p.A)(b.rootFolderInput,b[n],n),onSubmit:e=>{e.preventDefault(),e.stopPropagation()},children:(0,s.jsx)("input",{name:"tinyorm-root-folder-input",className:(0,p.A)(b.input,b[n],n),placeholder:`Enter ${c} folder...`,title:`This ${c} folder will be used in all ${i} examples at tinyorm.org${t}`,onChange:e=>{r(n,e.target.value)},value:d[n]??(0,x.bw)(n)})})}f.propTypes={groupId:h().string.isRequired,label:h().string.isRequired};const g=f;var y=i(7324);const T={sidebar_position:0,sidebar_label:"TinyORM",hide_table_of_contents:!0,description:"How to compile the TinyORM C++ library on Windows and Linux.",keywords:["c++ orm","building","tinyorm"]},_="Building: TinyORM",v={id:"building/tinyorm",title:"Building: TinyORM",description:"How to compile the TinyORM C++ library on Windows and Linux.",source:"@site/docs/building/tinyorm.mdx",sourceDirName:"building",slug:"/building/tinyorm",permalink:"/building/tinyorm",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"TinyORM",hide_table_of_contents:!0,description:"How to compile the TinyORM C++ library on Windows and Linux.",keywords:["c++ orm","building","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Getting Started",permalink:"/tinydrivers/getting-started"},next:{title:"Hello world",permalink:"/building/hello-world"}},O={},R=[{value:"Introduction",id:"introduction",level:2},{value:"Common Prerequisites",id:"common-prerequisites",level:4},{value:"Windows Prerequisites",id:"windows-prerequisites",level:4},{value:"Build environment scripts",id:"build-environment-scripts",level:5},{value:"Allow symbolic links unprivileged",id:"allow-symbolic-links-unprivileged",level:5},{value:"Folders structure",id:"folders-structure",level:2},{value:"Getting started",id:"getting-started",level:2},{value:"vcpkg",id:"vcpkg",level:2},{value:"Set up vcpkg environment",id:"set-up-vcpkg-environment",level:4},{value:"C preprocessor macros",id:"c-preprocessor-macros",level:2},{value:"Building with CMake",id:"building-with-cmake",level:2},{value:"Configure & Build (cmake)",id:"configure-and-build-cmake",level:3},{value:"CMake STRICT_MODE option",id:"cmake-strict_mode-option",level:5},{value:"Build TinyORM",id:"build-tinyorm",level:4},{value:"CMake build options",id:"cmake-build-options",level:3},{value:"Consume TinyOrm library (cmake)",id:"consume-tinyorm-library-cmake",level:3},{value:"Building with qmake",id:"building-with-qmake",level:2},{value:"Install dependencies",id:"install-dependencies",level:3},{value:"Configure & Build (qmake)",id:"configure-and-build-qmake",level:3},{value:"Open QtCreator IDE",id:"open-qtcreator-ide",level:4},{value:"Configure TinyORM",id:"configure-tinyorm",level:4},{value:"Auto-configuration and tiny_dotenv",id:"auto-configuration-and-tiny_dotenv",level:5},{value:"Manual configuration (conf.pri)",id:"manual-configuration-confpri",level:5},{value:"Opening TinyORM.pro (main project file)",id:"opening-tinyormpro-main-project-file",level:5},{value:"Build TinyORM",id:"build-tinyorm-1",level:4},{value:"qmake build options",id:"qmake-build-options",level:3},{value:"Consume TinyOrm library (qmake)",id:"consume-tinyorm-library-qmake",level:3},{value:"Requirements",id:"requirements",level:4},{value:"QMAKEFEATURES",id:"qmakefeatures",level:5},{value:"Variables affecting TinyOrm.pri",id:"variables-affecting-tinyormpri",level:5},{value:"Manual configuration examples",id:"manual-configuration-examples",level:5},{value:"Auto-configuration internals",id:"auto-configuration-internals",level:3},{value:"Environment files",id:"environment-files",level:4},{value:"Partial guessing of the TINYORM_BUILD_TREE",id:"partial-guessing-of-the-tinyorm_build_tree",level:4},{value:"Manual configuration internals",id:"manual-configuration-internals",level:3},{value:"Ccache support",id:"ccache-support",level:2}];function M(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,d.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"building-tinyorm",children:"Building: TinyORM"}),"\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:"#common-prerequisites",children:"Common Prerequisites"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#windows-prerequisites",children:"Windows Prerequisites"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#folders-structure",children:"Folders structure"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#getting-started",children:"Getting started"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#vcpkg",children:"vcpkg"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#c-preprocessor-macros",children:"C preprocessor macros"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#building-with-cmake",children:"Building with CMake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#configure-and-build-cmake",children:"Configure & Build"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#cmake-build-options",children:"CMake build options"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#consume-tinyorm-library-cmake",children:"Consume TinyOrm library"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#building-with-qmake",children:"Building with qmake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#install-dependencies",children:"Install dependencies"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#configure-and-build-qmake",children:"Configure & Build"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#qmake-build-options",children:"qmake build options"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#consume-tinyorm-library-qmake",children:"Consume TinyOrm library"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:"Auto-configuration internals"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#environment-files",children:"Environment files"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#manual-configuration-internals",children:"Manual configuration internals"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#ccache-support",children:"Ccache support"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsxs)(n.p,{children:["The build systems supported out of the box are ",(0,s.jsx)(n.code,{children:"CMake"})," and ",(0,s.jsx)(n.code,{children:"qmake"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["All examples below assume that ",(0,s.jsx)(n.code,{children:"pwsh"})," runs on ",(0,s.jsx)(n.code,{children:"Windows"})," and ",(0,s.jsx)(n.code,{children:"bash"})," runs on ",(0,s.jsx)(n.code,{children:"Linux"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"common-prerequisites",children:"Common Prerequisites"}),"\n",(0,s.jsxs)(n.p,{children:["Install the required ",(0,s.jsx)(n.a,{href:"/dependencies",children:"dependencies"})," before starting."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"QSqlDatabase"})," depends on ",(0,s.jsx)(n.code,{children:"QCoreApplication"})," from ",(0,s.jsx)(n.code,{children:"Qt v6.5.3"})," so you must create the ",(0,s.jsx)(n.code,{children:"QCoreApplication"})," instance before you will call anything from the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. \ud83e\udee4 The change was made ",(0,s.jsx)(n.a,{href:"https://github.com/qt/qtbase/commit/8d2bdc9cd5482eace12ba7e45304857bd24db0e6#diff-1d355c25c0b0eddec2be48253407780c4dc510d986739aec61e1ec892ccaf86e",children:"here"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"windows-prerequisites",children:"Windows Prerequisites"}),"\n",(0,s.jsx)(n.h5,{id:"build-environment-scripts",children:"Build environment scripts"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Visual Studio"})," does not provide ",(0,s.jsx)(n.code,{children:"vcvars"})," scripts for ",(0,s.jsx)(n.code,{children:"pwsh"}),", you can use ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/tools/vcvars64.ps1",children:(0,s.jsx)(n.code,{children:"vcvars64.ps1"})})," provided by ",(0,s.jsx)(n.code,{children:"TinyORM"})," in the ",(0,s.jsx)(n.code,{children:"tools/"})," folder. Place them on the ",(0,s.jsx)(n.code,{children:"$env:Path"})," user/system path and they will be available system-wide."]}),"\n",(0,s.jsxs)(n.p,{children:["The same is true for the ",(0,s.jsx)(n.code,{children:"Qt Framework"}),", it doesn't provide ",(0,s.jsx)(n.code,{children:"qtenv"})," scripts for ",(0,s.jsx)(n.code,{children:"pwsh"})," too. You can create your own script, place it on the ",(0,s.jsx)(n.code,{children:"$env:Path"})," user/system path and it will be available system-wide."]}),"\n",(0,s.jsxs)(n.p,{children:["Here is one simple example for ",(0,s.jsx)(n.code,{children:"pwsh"}),"."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:"qtenv6.ps1",label:"qtenv6.ps1",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:"#!/usr/bin/env pwsh\n\nSet-StrictMode -Version 3.0\n\nWrite-Host 'Setting up environment for Qt 6.7.2 usage...' -ForegroundColor Magenta\nWrite-Host\n\n$Script:QtRoot = $env:TINY_QT_ROOT ?? 'C:\\Qt'\n\n$env:Path = \"$Script:QtRoot\\6.7.2\\msvc2019_64\\bin;\" + $env:Path\n\n. vcvars64.ps1\n"})})}),(0,s.jsx)(t.A,{value:"qtenv5.ps1",label:"qtenv5.ps1",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:"#!/usr/bin/env pwsh\n\nSet-StrictMode -Version 3.0\n\nWrite-Host 'Setting up environment for Qt 5.15.2 usage...' -ForegroundColor Magenta\nWrite-Host\n\n$Script:QtRoot = $env:TINY_QT_ROOT ?? 'C:\\Qt'\n\n$env:Path = \"$Script:QtRoot\\5.15.2\\msvc2019_64\\bin;\" + $env:Path\n\n. vcvars64.ps1\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["And here for ",(0,s.jsx)(n.code,{children:"Linux"}),"."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:"qtenv6",label:"qtenv6",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'#!/usr/bin/env sh\n\necho \'Setting up environment for Qt 6.7.2 usage...\'\n\nQtRoot="${TINY_QT_ROOT:-/opt/Qt}"\n\nexport PATH="$QtRoot/6.7.2/gcc_64/bin"${PATH:+:}$PATH\nexport LD_LIBRARY_PATH="$QtRoot/6.7.2/gcc_64/lib"${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH\n'})})}),(0,s.jsx)(t.A,{value:"qtenv5",label:"qtenv5",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'#!/usr/bin/env sh\n\necho \'Setting up environment for Qt 5.15.2 usage...\'\n\nQtRoot="${TINY_QT_ROOT:-/opt/Qt}"\n\nexport PATH="$QtRoot/5.15.2/gcc_64/bin"${PATH:+:}$PATH\nexport LD_LIBRARY_PATH="$QtRoot/5.15.2/gcc_64/lib"${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH\n'})})})]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["These scripts consider the ",(0,s.jsx)(n.code,{children:"TINY_QT_ROOT"})," environment variable that should point to the ",(0,s.jsx)(n.code,{children:"Qt"})," installation folder, you can define this environment variable globally in your OS."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can't execute these ",(0,s.jsx)(n.code,{children:"qtenvX"})," scripts, they have to be sourced like ",(0,s.jsx)(n.code,{children:"source qtenvX"})," or ",(0,s.jsx)(n.code,{children:". qtenvX"}),"."]})}),"\n",(0,s.jsx)(n.h5,{id:"allow-symbolic-links-unprivileged",children:"Allow symbolic links unprivileged"}),"\n",(0,s.jsxs)(n.p,{children:["Open ",(0,s.jsx)(n.code,{children:"Local Security Policy"}),", go to ",(0,s.jsx)(n.code,{children:"Local Policies - User Rights Assignment"}),", open ",(0,s.jsx)(n.code,{children:"Create symbolic links"})," and add your user account or user group, restart when it doesn't apply immediately."]}),"\n",(0,s.jsx)(n.h2,{id:"folders-structure",children:"Folders structure"}),"\n",(0,s.jsxs)(n.p,{children:["All ",(0,s.jsx)(n.code,{children:"tinyorm.org"})," examples are based on the following folders structure. The ",(0,s.jsx)(n.code,{children:"tom"})," folder will contain a ",(0,s.jsx)(n.a,{href:"/building/migrations",children:"migrations console application"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can set the root and application folder paths in the form below and they will be used across the whole ",(0,s.jsx)(n.a,{href:"http://www.tinyorm.org",children:"www.tinyorm.org"})," website. \ud83e\udd73 The pwsh shell is supposed to use on Windows and the bash shell on Linux, but it is not a requirement."]})}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsxs)(t.A,{value:y.b,label:y.ux,className:"tiny-tree",children:[(0,s.jsx)("div",{className:"tiny-root-folder-info-wrapper",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)("span",{className:"tiny-root-folder-info-prefix",children:"Current pwsh path"}),"\xa0",(0,s.jsx)(u,{groupId:y.b})]})}),(0,s.jsx)(g,{groupId:y.b,label:y.ux}),(0,s.jsx)(g,{groupId:y.pW,label:y.kl}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"\n\n\n\u251c\u2500\u2500\n\u2502 \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld-builds-cmake/\n\u2502 | | \u2514\u2500\u2500 build-debug/\n\u2502 | \u2514\u2500\u2500 HelloWorld-builds-qmake/\n\u2502 | \u2514\u2500\u2500 build-debug/\n\u2502 \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM-builds-cmake/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-debug/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-release/\n\u2502 | \u2502 \u2514\u2500\u2500 build-clang-debug/\n\u2502 | \u2514\u2500\u2500 TinyORM-builds-qmake/\n\u2502 | \u251c\u2500\u2500 build-debug/\n\u2502 | \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/\n\u2502 | \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_MSYS2_UCRT64_64bit-Release/\n\u2502 \u2514\u2500\u2500 tom/\n\u2502 \u251c\u2500\u2500 tom/\n\u2502 \u2502 \u2514\u2500\u2500 database/\n\u2502 \u2502 \u251c\u2500\u2500 migrations/\n\u2502 \u2502 \u251c\u2500\u2500 seeders/\n\u2502 \u2502 \u251c\u2500\u2500 migrations.pri\n\u2502 \u2502 \u2514\u2500\u2500 seeders.pri\n\u2502 \u251c\u2500\u2500 tom-builds-cmake/\n\u2502 \u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/\n\u2502 \u2514\u2500\u2500 tom-builds-qmake/\n\u2502 \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_3_MSYS2_UCRT64_64bit-Release/\n\u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/\n\u251c\u2500\u2500 tmp/\n\u2514\u2500\u2500 vcpkg/\n"})})]}),(0,s.jsxs)(t.A,{value:y.xj,label:y.gg,className:"tiny-tree",children:[(0,s.jsx)("div",{className:"tiny-root-folder-info-wrapper",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)("span",{className:"tiny-root-folder-info-prefix",children:"Current bash path"}),"\xa0",(0,s.jsx)(u,{groupId:y.xj})]})}),(0,s.jsx)(g,{groupId:y.xj,label:y.gg}),(0,s.jsx)(g,{groupId:y.pW,label:y.pW}),(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"\n\n\n\u251c\u2500\u2500\n\u2502 \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld/\n\u2502 | \u251c\u2500\u2500 HelloWorld-builds-cmake/\n\u2502 | | \u2514\u2500\u2500 build-debug/\n\u2502 | \u2514\u2500\u2500 HelloWorld-builds-qmake/\n\u2502 | \u2514\u2500\u2500 build-debug/\n\u2502 \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM/\n\u2502 | \u251c\u2500\u2500 TinyORM-builds-cmake/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-debug/\n\u2502 | \u2502 \u251c\u2500\u2500 build-gcc-release/\n\u2502 | \u2502 \u2514\u2500\u2500 build-clang-debug/\n\u2502 | \u2514\u2500\u2500 TinyORM-builds-qmake/\n\u2502 | \u251c\u2500\u2500 build-debug/\n\u2502 | \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_GCC_64bit-Debug/\n\u2502 | \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_5_15_2_clang13_64bit_ccache-Release/\n\u2502 \u2514\u2500\u2500 tom/\n\u2502 \u251c\u2500\u2500 tom/\n\u2502 \u2502 \u2514\u2500\u2500 database/\n\u2502 \u2502 \u251c\u2500\u2500 migrations/\n\u2502 \u2502 \u251c\u2500\u2500 seeders/\n\u2502 \u2502 \u251c\u2500\u2500 migrations.pri\n\u2502 \u2502 \u2514\u2500\u2500 seeders.pri\n\u2502 \u251c\u2500\u2500 tom-builds-cmake/\n\u2502 \u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_clang14_64bit_ccache-Debug/\n\u2502 \u2514\u2500\u2500 tom-builds-qmake/\n\u2502 \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_GCC_64bit-Debug/\n\u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_2_clang14_64bit_ccache-Release/\n\u251c\u2500\u2500 tmp/\n\u2514\u2500\u2500 vcpkg/\n"})})]})]}),"\n",(0,s.jsx)(n.admonition,{type:"danger",children:(0,s.jsxs)(n.p,{children:["Avoid paths with spaces with the ",(0,s.jsx)(n.code,{children:"qmake"})," build system, it will not compile."]})}),"\n",(0,s.jsx)(r.A,{id:"qtcreator-default-build-directory"}),"\n",(0,s.jsxs)(n.admonition,{type:"tip",children:[(0,s.jsxs)(n.p,{children:["You can force the ",(0,s.jsx)(n.code,{children:"QtCreator"})," to generate a build folders structure as is described above."]}),(0,s.jsxs)(n.p,{children:["To generate the required folders structure set the ",(0,s.jsx)(n.code,{children:"Settings"})," - ",(0,s.jsx)(n.code,{children:"Build & Run"})," - ",(0,s.jsx)(n.code,{children:"Default Build Properties"})," - ",(0,s.jsx)(n.code,{children:"Default build directory"})," to:",(0,s.jsx)("br",{}),"\n",(0,s.jsx)(n.code,{children:'../%{Project:Name}-builds-%{BuildSystem:Name}/%{JS: Util.asciify("build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}")}'})]})]}),"\n",(0,s.jsx)(n.h2,{id:"getting-started",children:"Getting started"}),"\n",(0,s.jsxs)(n.p,{children:["Prepare compilation environment, we need to put the Qt Framework and Visual Studio MSVC compiler on the path on Windows. The compiler is already on the path on Linux and you can export ",(0,s.jsx)(n.code,{children:"PATH"})," and ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," for Qt Framework, or use our ",(0,s.jsx)(n.code,{children:"qtenvX"})," scripts described above."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`mkdir ${(0,x.Sn)(y.b)}\ncd ${(0,x.Sn)(y.b)}\n$env:Path = 'C:\\Qt\\6.7.2\\msvc2019_64\\bin;' + $env:Path\nvcvars64.ps1`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`mkdir -p ${(0,x.Sn)(y.xj)}\ncd ${(0,x.Sn)(y.xj)}\nexport PATH=/opt/Qt/6.7.2/gcc_64/bin\${PATH:+:}$PATH\nexport LD_LIBRARY_PATH=/opt/Qt/6.7.2/gcc_64/lib\${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH`})})]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can also use the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tools/Add-FolderOnPath.ps1",children:(0,s.jsx)(n.code,{children:"tools/Add-FolderOnPath.ps1"})})," pwsh script to fastly prepend a path or ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"})," on the system ",(0,s.jsx)(n.code,{children:"PATH"}),"."]})}),"\n",(0,s.jsx)(n.h2,{id:"vcpkg",children:"vcpkg"}),"\n",(0,s.jsxs)(n.p,{children:["Installing the ",(0,s.jsx)(n.code,{children:"vcpkg"})," is highly recommended, it simplifies installation of the ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," dependencies."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:"git clone git@github.com:microsoft/vcpkg.git\ncd vcpkg\n.\\bootstrap-vcpkg.bat\n"})})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"git clone git@github.com:microsoft/vcpkg.git\ncd vcpkg\n./bootstrap-vcpkg.sh\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["Add ",(0,s.jsx)(n.code,{children:"vcpkg"})," on the system path, add the following to the ",(0,s.jsx)(n.code,{children:".bashrc"})," or ",(0,s.jsx)(n.code,{children:".zshrc"})," on Linux."]}),"\n",(0,s.jsx)(c.A,{className:"language-bash",children:`export PATH=${(0,x.Sn)(y.xj)}/vcpkg\${PATH:+:}$PATH`}),"\n",(0,s.jsxs)(n.p,{children:["On Windows, open the ",(0,s.jsx)(n.code,{children:"Environment variables"})," dialog and add ",(0,s.jsx)(n.code,{children:"vcpkg"})," on the user ",(0,s.jsx)(n.code,{children:"PATH"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Or you can export it for the current session only."}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`$env:Path = "${(0,x.Sn)(y.b,!1)}\\vcpkg;" + $env:Path`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`export PATH=${(0,x.Sn)(y.xj)}/vcpkg\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.h4,{id:"set-up-vcpkg-environment",children:["Set up ",(0,s.jsx)(n.code,{children:"vcpkg"})," environment"]}),"\n",(0,s.jsxs)(n.p,{children:["To export ",(0,s.jsx)(n.code,{children:"vcpkg"})," environment variables globally, add it to the ",(0,s.jsx)(n.code,{children:".bashrc"})," or ",(0,s.jsx)(n.code,{children:".zshrc"})," on Linux, and you can use the ",(0,s.jsx)(n.code,{children:"Environment variables"})," dialog on Windows."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",metastring:"title='Linux'",children:'export VCPKG_DEFAULT_TRIPLET=x64-linux\n#export VCPKG_DEFAULT_HOST_TRIPLET=x64-linux\nexport VCPKG_MAX_CONCURRENCY=11\nexport VCPKG_OVERLAY_PORTS="$HOME/.local/share/vcpkg/ports"\nexport VCPKG_OVERLAY_TRIPLETS="$HOME/.local/share/vcpkg/triplets"\nexport VCPKG_ROOT="$HOME/Code/c/vcpkg"\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["It is recommended to define these variables globally because the ",(0,s.jsx)(n.code,{children:"CMake"})," and ",(0,s.jsx)(n.code,{children:"qmake"})," build system are able to detect the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation from them so you don't have to configure them manually to detect the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["On Windows, it's always better to create these types of variables as user variables instead of system variables in the ",(0,s.jsx)(n.code,{children:"Environment variables"})," dialog."]})}),"\n",(0,s.jsx)(n.h2,{id:"c-preprocessor-macros",children:"C preprocessor macros"}),"\n",(0,s.jsxs)(n.p,{children:["The following table summarizes all the C preprocessor macros defined in the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. These C macros are configured by ",(0,s.jsx)(n.code,{children:"CMake"})," or ",(0,s.jsx)(n.code,{children:"qmake"})," build systems. They are not sorted alphabetically, but they are sorted by how significant they are."]}),"\n",(0,s.jsxs)(n.p,{children:["In the ",(0,s.jsx)(n.code,{children:"CMake"})," build system, all the C macros are auto-detected / auto-configured or controlled by ",(0,s.jsx)(n.a,{href:"#cmake-build-options",children:(0,s.jsx)(n.code,{children:"CMake build options"})}),", so you don't have to care too much about them."]}),"\n",(0,s.jsxs)(n.p,{children:["In the ",(0,s.jsx)(n.code,{children:"qmake"})," build is important whether you are building ",(0,s.jsx)(n.code,{children:"TinyORM"})," library or you are building your application and linking against ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. When you are building the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library, all the C macros are auto-detected / auto-configured or controlled by ",(0,s.jsx)(n.a,{href:"#qmake-build-options",children:(0,s.jsx)(n.code,{children:"qmake build options"})}),", so you don't have to care too much about them."]}),"\n",(0,s.jsxs)(n.p,{children:["But a special situation is when you are building your application / library and you are linking against ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. In this particular case, you must configure all these C macros manually! For this reason, the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/qmake/TinyOrm.pri",children:(0,s.jsx)(n.code,{children:"TinyOrm.pri"})})," has been created, so that's not a big deal either. Little more info ",(0,s.jsx)(n.a,{href:"#consume-tinyorm-library-qmake",children:"here"}),"."]}),"\n",(0,s.jsx)("div",{id:"apitable-c-macros",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"C Macro Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_LINKING_SHARED"})}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)("u",{children:(0,s.jsx)(n.strong,{children:"Must"})})," be defined when you are linking against ",(0,s.jsx)(n.code,{children:"TinyORM"})," shared build (",(0,s.jsx)(n.code,{children:"dll"})," library), exported classes and functions will be tagged with ",(0,s.jsx)(n.code,{children:"__declspec(dllimport)"})," on ",(0,s.jsx)(n.code,{children:"msvc"})," and ",(0,s.jsx)(n.code,{children:'visibility("default")'})," on ",(0,s.jsx)(n.code,{children:"GCC >= 4"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_BUILDING_SHARED"})}),(0,s.jsxs)(n.td,{children:["Defined when ",(0,s.jsx)(n.code,{children:"TinyORM"})," is built as a ",(0,s.jsx)(n.code,{children:"dll"})," library (shared build)."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DEBUG"})}),(0,s.jsx)(n.td,{children:"Defined in the debug build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_NO_DEBUG"})}),(0,s.jsx)(n.td,{children:"Defined in the release build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DEBUG_SQL"})}),(0,s.jsx)(n.td,{children:"Defined in the debug build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_NO_DEBUG_SQL"})}),(0,s.jsx)(n.td,{children:"Defined in the release build."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_MYSQL_PING"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.code,{children:"Orm::MySqlConnection::pingDatabase()"})," method.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#mysql_ping",children:(0,s.jsx)(n.code,{children:"mysql_ping"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#MYSQL_PING",children:(0,s.jsx)(n.code,{children:"MYSQL_PING"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DISABLE_ORM"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"ORM-related"})," source code, when this macro is ",(0,s.jsx)(n.code,{children:"defined"}),", then only the ",(0,s.jsx)(n.code,{children:"query builder"})," without ",(0,s.jsx)(n.code,{children:"ORM"})," is compiled. Also excludes ",(0,s.jsx)(n.code,{children:"ORM-related"})," unit tests.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#disable_orm",children:(0,s.jsx)(n.code,{children:"disable_orm"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#ORM",children:(0,s.jsx)(n.code,{children:"ORM"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled ",(0,s.jsx)("small",{children:"(qmake)"})," / disabled ",(0,s.jsx)("small",{children:"(cmake)"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_EXTERN_CONSTANTS"})}),(0,s.jsxs)(n.td,{children:["Defined when extern constants are used. Extern constants are enabled by default for shared builds and disabled for static builds.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Described at ",(0,s.jsx)(n.a,{href:"#extern_constants",children:(0,s.jsx)(n.code,{children:"qmake"})})," / ",(0,s.jsx)(n.a,{href:"#INLINE_CONSTANTS",children:(0,s.jsx)(n.code,{children:"CMake"})})," how it works."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_INLINE_CONSTANTS"})}),(0,s.jsxs)(n.td,{children:["Defined when global inline constants are used.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#inline_constants",children:(0,s.jsx)(n.code,{children:"inline_constants"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#INLINE_CONSTANTS",children:(0,s.jsx)(n.code,{children:"INLINE_CONSTANTS"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_TESTS_CODE"})}),(0,s.jsxs)(n.td,{children:["Enable code needed by unit tests, eg. connection overriding in the ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Model"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#build_tests",children:(0,s.jsx)(n.code,{children:"build_tests"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#BUILD_TESTS",children:(0,s.jsx)(n.code,{children:"BUILD_TESTS"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_DISABLE_THREAD_LOCAL"})}),(0,s.jsxs)(n.td,{children:["Remove all ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/c/language/storage_duration",children:(0,s.jsx)(n.code,{children:"thread_local"})})," storage duration specifiers, it disables multi-threading support.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined when ",(0,s.jsx)(n.a,{href:"#disable_thread_local",children:(0,s.jsx)(n.code,{children:"disable_thread_local"})})," ",(0,s.jsx)("small",{children:"(qmake)"})," / ",(0,s.jsx)(n.a,{href:"#DISABLE_THREAD_LOCAL",children:(0,s.jsx)(n.code,{children:"DISABLE_THREAD_LOCAL"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration ",(0,s.jsx)(n.code,{children:"build option"})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYTOM_MIGRATIONS_DIR"})}),(0,s.jsxs)(n.td,{children:["Default migrations path for the ",(0,s.jsx)(n.code,{children:"make:migration"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/migrations"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined by ",(0,s.jsx)(n.a,{href:"#TOM_MIGRATIONS_DIR",children:(0,s.jsx)(n.code,{children:"TOM_MIGRATIONS_DIR"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration build option.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(qmake note) You can use ",(0,s.jsx)(n.code,{children:'DEFINES += TINYTOM_MIGRATIONS_DIR="\\"database/migrations\\""'})," on the command-line or set it in the ",(0,s.jsx)(n.strong,{children:"main"})," ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L65-L70",children:(0,s.jsx)(n.code,{children:"conf.pri"})})," file."]})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYTOM_MODELS_DIR"})}),(0,s.jsxs)(n.td,{children:["Default models path for the ",(0,s.jsx)(n.code,{children:"make:model"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/models"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined by ",(0,s.jsx)(n.a,{href:"#TOM_MODELS_DIR",children:(0,s.jsx)(n.code,{children:"TOM_MODELS_DIR"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration build option.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(qmake note) You can use ",(0,s.jsx)(n.code,{children:'DEFINES += TINYTOM_MODELS_DIR="\\"database/models\\""'})," on the command-line or set it in the ",(0,s.jsx)(n.strong,{children:"main"})," ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L72-L73",children:(0,s.jsx)(n.code,{children:"conf.pri"})})," file."]})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYTOM_SEEDERS_DIR"})}),(0,s.jsxs)(n.td,{children:["Default seeders path for the ",(0,s.jsx)(n.code,{children:"make:seeder"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/seeders"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Defined by ",(0,s.jsx)(n.a,{href:"#TOM_SEEDERS_DIR",children:(0,s.jsx)(n.code,{children:"TOM_SEEDERS_DIR"})})," ",(0,s.jsx)("small",{children:"(cmake)"})," configuration build option.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(qmake note) You can use ",(0,s.jsx)(n.code,{children:'DEFINES += TINYTOM_SEEDERS_DIR="\\"database/seeders\\""'})," on the command-line or set it in the ",(0,s.jsx)(n.strong,{children:"main"})," ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L75-L76",children:(0,s.jsx)(n.code,{children:"conf.pri"})})," file."]})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_USING_PCH"})}),(0,s.jsxs)(n.td,{children:["Defined if building with precompiled headers.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Controlled by ",(0,s.jsx)(n.a,{href:"#qmake-precompile_header",children:(0,s.jsx)(n.code,{children:"qmake"})})," / ",(0,s.jsx)(n.a,{href:"#CMAKE_DISABLE_PRECOMPILE_HEADERS",children:(0,s.jsx)(n.code,{children:"CMake"})}),"."]})]})]})]})]})})}),"\n",(0,s.jsx)(n.h2,{id:"building-with-cmake",children:"Building with CMake"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["If something is not clear, you can still look at GitHub Action ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/.github/workflows",children:(0,s.jsx)(n.code,{children:"workflows"})})," how a building is done."]})}),"\n",(0,s.jsxs)(n.p,{children:["First, create a basic folder structure and then clone the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.Sn)(y.b)}\nmkdir ${(0,x.np)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.Sn)(y.xj)}\nmkdir -p ${(0,x.np)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})})]}),"\n",(0,s.jsxs)(n.h3,{id:"configure-and-build-cmake",children:["Configure & Build ",(0,s.jsx)("small",{children:"(cmake)"})]}),"\n",(0,s.jsxs)(n.p,{children:["Now you are ready to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd TinyORM-builds-cmake/build-debug\n"})}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cmake.exe \`\n-S "${(0,x.OZ)(y.b)}/TinyORM/TinyORM" \`\n-B "${(0,x.OZ)(y.b)}/TinyORM/TinyORM-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,x.Sn)(y.b)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,x.Sn)(y.b)}/tmp/TinyORM" \`\n-D BUILD_TESTS:BOOL=OFF \`\n-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=ON \`\n-D MYSQL_PING:BOOL=OFF \`\n-D TOM:BOOL=ON \`\n-D TOM_EXAMPLE:BOOL=OFF \`\n-D VERBOSE_CONFIGURE:BOOL=ON`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cmake \\\n-S "${(0,x.OZ)(y.xj)}/TinyORM/TinyORM" \\\n-B "${(0,x.OZ)(y.xj)}/TinyORM/TinyORM-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,x.Sn)(y.xj)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,x.Sn)(y.xj)}/tmp/TinyORM" \\\n-D VERBOSE_CONFIGURE:BOOL=ON \\\n-D BUILD_TESTS:BOOL=OFF \\\n-D MYSQL_PING:BOOL=OFF \\\n-D TOM:BOOL=ON \\\n-D TOM_EXAMPLE:BOOL=OFF \\\n-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=ON`})})]}),"\n",(0,s.jsxs)(n.h5,{id:"cmake-strict_mode-option",children:["CMake ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," option"]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," ",(0,s.jsx)(n.code,{children:"CMake"})," configuration option was added in ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.37.3"}),". This option was added to avoid the propagation of aggressive strict warning compiler/linker options and Qt definitions from the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library to user code through the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/cmake/CommonModules/TinyCommon.cmake",children:(0,s.jsx)(n.code,{children:"TinyOrm::CommonConfig"})})," interface library."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"TinyORM"})," uses the strictest warning level options, virtually anything that can be enabled is enabled to produce a better code. I highly recommend enabling this option to produce better code and to follow good practices. It also helps to follow the ",(0,s.jsx)(n.code,{children:"ISOCPP"})," ",(0,s.jsx)(n.a,{href:"https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines",children:"C++ Core Guidelines"})," standards."]}),"\n",(0,s.jsxs)(n.p,{children:["If you want to enable these strict warning options in your code, you can enable the ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," ",(0,s.jsx)(n.code,{children:"CMake"})," configuration option and they will be propagated to your code. You can also enabled it globally using the ",(0,s.jsx)(n.code,{children:"TINYORM_STRICT_MODE"})," environment variable, and the value of this environment variable will be picked up during initial CMake configuration as the default value for the ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," ",(0,s.jsx)(n.code,{children:"CMake"})," configuration option."]}),"\n",(0,s.jsxs)(n.p,{children:["You can achieve the same result by manually linking against the ",(0,s.jsx)(n.code,{children:"TinyOrm::CommonConfig"})," interface library when the ",(0,s.jsx)(n.code,{children:"STRICT_MODE"})," is set to ",(0,s.jsx)(n.code,{children:"OFF"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cmake",children:"target_link_libraries( PRIVATE TinyOrm::CommonConfig)\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The recommended way is to set the ",(0,s.jsx)(n.code,{children:"TINYORM_STRICT_MODE"})," environment variable to ",(0,s.jsx)(n.code,{children:"1"})," or ",(0,s.jsx)(n.code,{children:"ON"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"build-tinyorm",children:"Build TinyORM"}),"\n",(0,s.jsx)(n.p,{children:"And build. You don't have to install it, you can use the build tree directly if you want."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cmake --build . --target all\ncmake --install .\n"})}),"\n",(0,s.jsx)(n.p,{children:"Or build and install in one step."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cmake --build . --target install\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["CMake multi-config generators like ",(0,s.jsx)(n.code,{children:"Ninja Multi-Config"})," or ",(0,s.jsx)(n.code,{children:"Visual Studio 16 2019"})," are also supported."]})}),"\n",(0,s.jsx)(n.h3,{id:"cmake-build-options",children:"CMake build options"}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_DRIVERS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started",children:"TinyDrivers"})," SQL database drivers (core/common code; replaces QtSql module)."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_MYSQL_DRIVER"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," MySQL database driver.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"BUILD_DRIVERS"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_SHARED_LIBS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsx)(n.td,{children:"Build as a shared/static library."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_TESTS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Build TinyORM unit tests."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"BUILD_TREE_DEPLOY"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Copy ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," and ",(0,s.jsx)(n.code,{children:"TinyMySql"})," libraries to the root of the build tree."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"DRIVERS_TYPE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"Shared"})}),(0,s.jsxs)(n.td,{children:["How to build and link against ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," SQL database drivers.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"Static"})," value will be select by default when the ",(0,s.jsx)(n.code,{children:"BUILD_SHARED_LIBS"})," is ",(0,s.jsx)(n.code,{children:"OFF"}),".",(0,s.jsx)("br",{}),"Supported values: ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-shared-library-build",children:(0,s.jsx)(n.code,{children:"Shared"})}),", ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-loadable-sql-drivers-build",children:(0,s.jsx)(n.code,{children:"Loadable"})}),", and ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-static-build",children:(0,s.jsx)(n.code,{children:"Static"})}),(0,s.jsx)("br",{}),"Available when: ",(0,s.jsx)(n.code,{children:"BUILD_DRIVERS AND BUILD_SHARED_LIBS"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"INLINE_CONSTANTS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Use inline constants instead of extern constants in the ",(0,s.jsx)(n.code,{children:"shared build"}),".",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"OFF"})," is highly recommended for the ",(0,s.jsx)(n.code,{children:"shared build"}),";",(0,s.jsx)("br",{}),"is always ",(0,s.jsx)(n.code,{children:"ON"})," for the ",(0,s.jsx)(n.code,{children:"static build"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"BUILD_SHARED_LIBS"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"MSVC_RUNTIME_DYNAMIC"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Use MSVC dynamic runtime library (",(0,s.jsx)(n.code,{children:"-MD"}),") instead of static (",(0,s.jsx)(n.code,{children:"-MT"}),"), also considers a Debug configuration (",(0,s.jsx)(n.code,{children:"-MTd"}),", ",(0,s.jsx)(n.code,{children:"-MDd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"MSVC AND NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"MYSQL_PING"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.code,{children:"Orm::MySqlConnection::pingDatabase()"})," method."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ORM"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"ORM-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"disabled"}),", then only the ",(0,s.jsx)(n.code,{children:"query builder"})," without ",(0,s.jsx)(n.code,{children:"ORM"})," is compiled. Also excludes ",(0,s.jsx)(n.code,{children:"ORM-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"STRICT_MODE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Controls propagation of strict compiler/linker options and Qt definitions using the ",(0,s.jsx)(n.code,{children:"TinyOrm::CommonConfig"})," interface library to the user code.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["(highly recommended; can also be set with the ",(0,s.jsx)(n.code,{children:"TINYORM_STRICT_MODE"})," environment variable; described ",(0,s.jsx)(n.a,{href:"#cmake-strict_mode-option",children:"here"}),")"]}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"Tom-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"disabled"}),", then it also excludes ",(0,s.jsx)(n.code,{children:"Tom-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_EXAMPLE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build the ",(0,s.jsx)("abbr",{title:"TinyORM Migrations",children:(0,s.jsx)(n.code,{children:"tom"})})," console application example."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_MIGRATIONS_DIR"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default migrations path for the ",(0,s.jsx)(n.code,{children:"make:migration"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/migrations"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_MODELS_DIR"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default models path for the ",(0,s.jsx)(n.code,{children:"make:model"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/models"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TOM_SEEDERS_DIR"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default seeders path for the ",(0,s.jsx)(n.code,{children:"make:seeder"})," command, can be an absolute or relative path (to the ",(0,s.jsx)("abbr",{title:"Current working directory",children:"pwd"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Default value: ",(0,s.jsx)(n.code,{children:"database/seeders"})," ",(0,s.jsx)("small",{children:"(relative to the pwd)"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"VERBOSE_CONFIGURE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Show information about ",(0,s.jsx)(n.code,{children:"PACKAGES_FOUND"})," / ",(0,s.jsx)(n.code,{children:"PACKAGES_NOT_FOUND"})," in the CMake configure output."]})]})]})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Advanced ",(0,s.jsx)(n.code,{children:"TinyORM"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"DISABLE_THREAD_LOCAL"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Remove all ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/c/language/storage_duration",children:(0,s.jsx)(n.code,{children:"thread_local"})})," storage duration specifiers, it disables multi-threading support."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)("small",{children:(0,s.jsx)(n.code,{children:"MATCH_EQUAL_EXPORTED_BUILDTREE"})})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Exported package configuration from the build tree is considered to match only when ",(0,s.jsx)(n.code,{children:"the build type"})," of application/library that is linking against the TinyORM library ",(0,s.jsx)(n.strong,{children:"is equal"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when:",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"CMAKE_EXPORT_PACKAGE_REGISTRY AND NOT TINY_IS_MULTI_CONFIG"})]})]})]})]})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Important ",(0,s.jsx)(n.code,{children:"CMake"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_DISABLE_PRECOMPILE_HEADERS"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Disable precompiled headers."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_CXX_COMPILER"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"auto"})}),(0,s.jsxs)(n.td,{children:["The full path to the ",(0,s.jsx)(n.code,{children:"C++"})," compiler."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_CXX_COMPILER_LAUNCHER"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Default compiler launcher to use for the ",(0,s.jsx)(n.code,{children:"C++"})," compiler.",(0,s.jsx)("br",{}),"Can be used to enable ",(0,s.jsx)(n.code,{children:"ccache"}),", eg. ",(0,s.jsx)(n.code,{children:"ccache.exe"})," on ",(0,s.jsx)(n.code,{children:"MinGW"})," or ",(0,s.jsx)(n.code,{children:"/usr/bin/ccache"})," on ",(0,s.jsx)(n.code,{children:"Linux"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_EXPORT_PACKAGE_REGISTRY"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable the ",(0,s.jsx)(n.code,{children:"export(TinyOrm)"})," command.",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"TinyORM"})," doesn't set this variable by default. Its initial value is taken from the ",(0,s.jsx)(n.code,{children:"TINYORM_EXPORT_PACKAGE_REGISTRY"})," environment variable if not already defined."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)("small",{children:(0,s.jsx)(n.code,{children:"CMAKE_INTERPROCEDURAL_OPTIMIZATION"})})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Interprocedural_optimization",children:"Link time code optimization"})," (",(0,s.jsx)(n.a,{href:"https://wiki.gentoo.org/wiki/LTO",children:"LTO"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Works on all ",(0,s.jsx)(n.a,{href:"/supported-compilers",children:"Supported Compilers"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"CMAKE_VERBOSE_MAKEFILE"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Enable verbose output from Makefile builds."})]})]})]})})}),"\n",(0,s.jsxs)(n.h3,{id:"consume-tinyorm-library-cmake",children:["Consume TinyOrm library ",(0,s.jsx)("small",{children:"(cmake)"})]}),"\n",(0,s.jsxs)(n.p,{children:["In your application or library ",(0,s.jsx)(n.code,{children:"CMakeLists.txt"})," file add following ",(0,s.jsx)(n.code,{children:"find_package()"})," call."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cmake",metastring:"title='CMakeLists.txt'",children:"find_package(TinyOrm 0.37.3 CONFIG REQUIRED)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build tree is not exported to the CMake's ",(0,s.jsx)(n.a,{href:"https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#user-package-registry",children:(0,s.jsx)(n.code,{children:"User Package Registry"})})," then also add the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build tree or ",(0,s.jsx)(n.code,{children:"CMAKE_INSTALL_PREFIX"})," folder to the ",(0,s.jsx)(n.code,{children:"CMAKE_PREFIX_PATH"}),", so CMake can find TinyORM's package configuration file during ",(0,s.jsx)(n.code,{children:"find_package(TinyOrm)"})," call."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:`cmake (${y.b})`,children:(0,s.jsx)(c.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.b,(0,x.OZ)(y.b))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.b,(0,x.Sn)(y.b))}/tmp/TinyORM")`})}),(0,s.jsx)(t.A,{value:y.xj,label:`cmake (${y.xj})`,children:(0,s.jsx)(c.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.xj,(0,x.OZ)(y.xj))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,x.nC)(y.xj,(0,x.Sn)(y.xj))}/tmp/TinyORM")`})})]}),"\n",(0,s.jsxs)(n.p,{children:["Or as an alternative, you can set ",(0,s.jsx)(n.code,{children:"CMAKE_PREFIX_PATH"})," environment variable."]}),"\n",(0,s.jsx)(r.A,{id:"tinyorm-on-path-cmake"}),"\n",(0,s.jsxs)(n.p,{children:["As the last thing, do not forget to add ",(0,s.jsx)(n.code,{children:"TinyOrm0d.dll"})," on the path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux, so your application can find it during execution."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`$env:Path = "${(0,x.OZ)(y.b,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,x.OZ)(y.xj)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.p,{children:["Now you can try the ",(0,s.jsx)(n.a,{href:"/building/hello-world#hello-world-with-cmake",children:(0,s.jsx)(n.code,{children:"HelloWorld CMake"})})," example."]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can also try the ",(0,s.jsx)(n.a,{href:"/building/hello-world#fetchcontent",children:(0,s.jsx)(n.code,{children:"FetchContent"})})," method to fastly link against the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library."]})}),"\n",(0,s.jsx)(n.h2,{id:"building-with-qmake",children:"Building with qmake"}),"\n",(0,s.jsxs)(n.p,{children:["First, create a basic folder structure and then clone the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.Sn)(y.b)}\nmkdir ${(0,x.np)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.Sn)(y.xj)}\nmkdir -p ${(0,x.np)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,x.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})})]}),"\n",(0,s.jsx)(n.h3,{id:"install-dependencies",children:"Install dependencies"}),"\n",(0,s.jsxs)(n.p,{children:["With the ",(0,s.jsx)(n.code,{children:"qmake"})," build system, you have to install ",(0,s.jsx)(n.code,{children:"TinyORM"})," dependencies manually. We will use the ",(0,s.jsx)(n.code,{children:"vcpkg"})," package manager."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd ../../vcpkg\n\nvcpkg search range-v3\nvcpkg search tabulate\nvcpkg install range-v3 tabulate\nvcpkg list\n"})}),"\n",(0,s.jsxs)(n.p,{children:["On ",(0,s.jsx)(n.code,{children:"Linux"}),", you can install the ",(0,s.jsx)(n.code,{children:"range-v3"})," library and some other ",(0,s.jsx)(n.a,{href:"/dependencies#install-dependencies",children:"dependencies"})," with the package manager."]}),"\n",(0,s.jsxs)(n.h3,{id:"configure-and-build-qmake",children:["Configure & Build ",(0,s.jsx)("small",{children:"(qmake)"})]}),"\n",(0,s.jsx)(n.h4,{id:"open-qtcreator-ide",children:"Open QtCreator IDE"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["I recommend creating a new ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qtcreator/creator-project-managing-sessions.html",children:(0,s.jsx)(n.code,{children:"Session"})})," in the ",(0,s.jsx)(n.code,{children:"QtCreator"}),", this way you will have all the examples in one place and as a bonus, everything will be in the same place when you close and reopen ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),". You can name it ",(0,s.jsx)(n.code,{children:"tinyorm.org"})," or ",(0,s.jsx)(n.code,{children:"TinyORM examples"}),", it is up to you."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["If you are using sessions, you can use a single ",(0,s.jsx)(n.code,{children:"clangd"})," instance for all projects in this session in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),". One significant advantage of this method is that the ",(0,s.jsx)(n.code,{children:".qtc_clangd/"})," folder will not be created in the build folder, but will be stored globally in the Roaming profile. You can enable it in the ",(0,s.jsx)(n.code,{children:"Settings"})," - ",(0,s.jsx)(n.code,{children:"C++"})," - ",(0,s.jsx)(n.code,{children:"Clangd"})," - ",(0,s.jsx)(n.code,{children:"Sessions with a single clangd instance"}),"."]})}),"\n",(0,s.jsx)(n.h4,{id:"configure-tinyorm",children:"Configure TinyORM"}),"\n",(0,s.jsxs)(n.p,{children:["Now you are ready to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. There are two ways how to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library and it's the new ",(0,s.jsx)(n.code,{children:"Auto-configure"})," feature added in ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"})," using the ",(0,s.jsx)(n.code,{children:".env"})," files and the old way using the ",(0,s.jsx)(n.code,{children:"conf.pri"})," files."]}),"\n",(0,s.jsx)(n.h5,{id:"auto-configuration-and-tiny_dotenv",children:"Auto-configuration and tiny_dotenv"}),"\n",(0,s.jsxs)(n.p,{children:["This is the new recommended method to auto-configure TinyORM's ",(0,s.jsx)(n.code,{children:"qmake"})," build system and also the dependencies, it was added in ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),". You need to copy the prepared ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw).example"})," file to the ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"}),". One ",(0,s.jsx)(n.code,{children:".env"})," example file is prepared for each supported platform."]}),"\n",(0,s.jsxs)(n.p,{children:["All prepared ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw).example"})," files are simple and clear. You can also create a common ",(0,s.jsx)(n.code,{children:".env"})," file that is included before the platform-specific ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"})," files."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.OZ)(y.b)}/TinyORM/TinyORM\n\ncp .env.win32.example .env.win32`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.OZ)(y.xj)}/TinyORM/TinyORM\n\ncp .env.unix.example .env.unix`})})]}),"\n",(0,s.jsxs)(n.p,{children:["And that is all, if you have correctly set all ",(0,s.jsx)(n.code,{children:"qmake"})," variables in this ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"})," file or you have correctly set environment variables, then the ",(0,s.jsx)(n.code,{children:"qmake"})," build system should be able to ",(0,s.jsx)(n.code,{children:"auto-detect"})," all dependencies . \ud83d\udd25"]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:(0,s.jsx)(n.code,{children:"Auto-configuration"})})," and ",(0,s.jsx)(n.a,{href:"#environment-files",children:(0,s.jsx)(n.code,{children:"Environment files"})})," internals are described at the end to make this section more clear."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_autoconf",children:(0,s.jsx)(n.code,{children:"disable_autoconf"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_autoconf"}),")."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_dotenv",children:(0,s.jsx)(n.code,{children:"disable_dotenv"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_dotenv"}),")."]})}),"\n",(0,s.jsx)(n.h5,{id:"manual-configuration-confpri",children:"Manual configuration (conf.pri)"}),"\n",(0,s.jsxs)(n.p,{children:["This is the old method used before ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),". You need to copy the ",(0,s.jsx)(n.code,{children:"conf.pri.example"})," files to ",(0,s.jsx)(n.code,{children:"conf.pri"})," (there are four, one for every project or sub-project) and manually update the ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," and ",(0,s.jsx)(n.code,{children:"LIBS"})," to configure TinyORM's ",(0,s.jsx)(n.code,{children:"qmake"})," build dependencies. This way you can override any ",(0,s.jsx)(n.code,{children:"qmake"})," build options or variables."]}),"\n",(0,s.jsxs)(n.p,{children:["To disable the ",(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:(0,s.jsx)(n.code,{children:"Auto-configuration"})})," feature you must define the ",(0,s.jsx)(n.a,{href:"#disable_autoconf",children:(0,s.jsx)(n.code,{children:"disable_autoconf"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_autoconf"}),") because from ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"})," is the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature enabled by default."]}),"\n",(0,s.jsxs)(n.p,{children:["You can also remove all ",(0,s.jsx)(n.code,{children:".env"})," files or turn off the ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature using ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_dotenv"}),". You can use them all at once if you want, ",(0,s.jsx)(n.code,{children:".env"})," and also ",(0,s.jsx)(n.code,{children:"conf.pri"})," files."]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"conf.pri"})," files are nicely commented on, so you can see what needs to be modified."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`cd ${(0,x.OZ)(y.b)}/TinyORM/TinyORM\n\ncp conf.pri.example conf.pri\ncp tests/conf.pri.example tests/conf.pri\ncp tests/testdata_tom/conf.pri.example tests/testdata_tom/conf.pri\ncp examples/tom/conf.pri.example examples/tom/conf.pri`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`cd ${(0,x.OZ)(y.xj)}/TinyORM/TinyORM\n\ncp conf.pri.example conf.pri\ncp tests/conf.pri.example tests/conf.pri\ncp tests/testdata_tom/conf.pri.example tests/testdata_tom/conf.pri\ncp examples/tom/conf.pri.example examples/tom/conf.pri`})})]}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#manual-configuration-internals",children:(0,s.jsx)(n.code,{children:"Manual configuration"})})," internals are described at the end to make this section more clear."]})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Manual configuration"})," is still relevant if you have any non-standard installation of the ",(0,s.jsx)(n.code,{children:"vcpkg"})," or ",(0,s.jsx)(n.code,{children:"MySQL"})," and the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature fails."]})}),"\n",(0,s.jsx)(n.h5,{id:"opening-tinyormpro-main-project-file",children:"Opening TinyORM.pro (main project file)"}),"\n",(0,s.jsxs)(n.p,{children:["Now you can open the ",(0,s.jsx)(n.code,{children:"TinyORM.pro"})," project in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["This will open the ",(0,s.jsx)(n.code,{children:"Configure Project"})," tab, select some kit and update build folder paths to meet our ",(0,s.jsx)(n.a,{href:"#folders-structure",children:"folders structure"})," or like you want."]}),"\n",(0,s.jsx)("img",{src:i(885).A,alt:"TinyORM - QtCreator - Configure Project",width:"760"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can force the ",(0,s.jsx)(n.code,{children:"QtCreator"})," to generate a build folders structure as is described ",(0,s.jsx)(n.a,{href:"#qtcreator-default-build-directory",children:"above"}),"."]})}),"\n",(0,s.jsxs)(n.p,{children:["You are ready to configure build options, hit ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"5"})," to open ",(0,s.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,s.jsx)(n.code,{children:"Build"})," in the left sidebar to open the ",(0,s.jsx)(n.code,{children:"Build Settings"}),", it should look similar to the following picture."]}),"\n",(0,s.jsxs)(n.p,{children:["Disable ",(0,s.jsx)(n.code,{children:"QML debugging and profiling"})," and ",(0,s.jsx)(n.code,{children:"Qt Quick Compiler"}),", they are not used."]}),"\n",(0,s.jsx)("img",{src:i(7619).A,alt:"TinyORM - QtCreator - Build Settings",width:"760"}),"\n",(0,s.jsxs)(n.p,{children:["If you want to change some ",(0,s.jsx)(n.code,{children:"TinyORM"})," build options, you can pass them to the ",(0,s.jsx)(n.code,{children:"Build Steps"})," - ",(0,s.jsx)(n.code,{children:"qmake TinyORM.pro"})," - ",(0,s.jsx)(n.code,{children:"Additional arguments"})," input field. It can look like this."]}),"\n",(0,s.jsx)("img",{src:i(2721).A,alt:"TinyORM - QtCreator - Build Settings - Additional arguments",width:"660"}),"\n",(0,s.jsx)(n.h4,{id:"build-tinyorm-1",children:"Build TinyORM"}),"\n",(0,s.jsxs)(n.p,{children:["Everything is ready for build, you can press ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"b"})," to build the project."]}),"\n",(0,s.jsx)(n.h3,{id:"qmake-build-options",children:"qmake build options"}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.th,{children:[(0,s.jsx)(n.code,{children:"CONFIG"})," ",(0,s.jsx)("small",{children:"Option Name"})]}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_loadable_drivers"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started",children:(0,s.jsx)(n.code,{children:"TinyDrivers"})})," as a shared library and SQL database drivers (eg. ",(0,s.jsx)(n.code,{children:"TinyMySql"}),") as shared libraries (",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-loadable-sql-drivers-build",children:(0,s.jsx)(n.code,{children:"Loadable"})})," modules) that are loaded at runtime using ",(0,s.jsx)(n.code,{children:"LoadLibrary()"})," on Windows or ",(0,s.jsx)(n.code,{children:"dlopen()"})," on Linux."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_mysql_driver"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," MySQL database driver.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It's enabled by default when ",(0,s.jsx)(n.code,{children:"build_shared_drivers"}),", ",(0,s.jsx)(n.code,{children:"build_loadable_drivers"}),", or ",(0,s.jsx)(n.code,{children:"build_static_drivers"})," is enabled.",(0,s.jsx)("br",{}),"Available when: ",(0,s.jsx)(n.code,{children:"build_shared_drivers"})," OR ",(0,s.jsx)(n.code,{children:"build_loadable_drivers"})," OR ",(0,s.jsx)(n.code,{children:"build_static_drivers"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_shared_drivers"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," as a ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-shared-library-build",children:(0,s.jsx)(n.code,{children:"Shared"})})," library."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_static_drivers"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build ",(0,s.jsx)(n.code,{children:"TinyDrivers"})," as a ",(0,s.jsx)(n.a,{href:"/tinydrivers/getting-started#the-static-build",children:(0,s.jsx)(n.code,{children:"Static"})})," library archive.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"build_static_drivers"})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option will be select by default when the ",(0,s.jsx)(n.a,{href:"#qmake-static",children:(0,s.jsx)(n.code,{children:"CONFIG*=static"})})," is enabled."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"build_tests"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsx)(n.td,{children:"Build TinyORM unit tests."})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ccache"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Enable compiler cache. ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:"Homepage"}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It works on Windows and Unix systems. This option overrides qmake's ",(0,s.jsx)(n.code,{children:"ccache"})," option. It internally calls qmake's ",(0,s.jsx)(n.a,{href:"#qmake-ccache",children:(0,s.jsx)(n.code,{children:"ccache"})})," option on Unix and ",(0,s.jsx)(n.a,{href:"#tiny_ccache_win32",children:(0,s.jsx)(n.code,{children:"tiny_ccache_win32"})})," on Windows.",(0,s.jsx)("br",{}),"Reason: It allows using the same option on both OS-es.",(0,s.jsx)("br",{}),"See ",(0,s.jsx)(n.a,{href:"#ccache-support",children:"Ccache support"})," for more information."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_autoconf"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Disable the ",(0,s.jsx)(n.a,{href:"#auto-configuration-internals",children:(0,s.jsx)(n.code,{children:"Auto-configuration"})})," feature ",(0,s.jsxs)("small",{children:["(auto-configuration is enabled by default from ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),")"]}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_dotenv"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Disable the ",(0,s.jsx)(n.a,{href:"#environment-files",children:(0,s.jsx)(n.code,{children:"tiny_dotenv"})})," feature ",(0,s.jsxs)("small",{children:["(environment files are enabled by default from ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"v0.34.0"}),")"]}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_thread_local"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Remove all ",(0,s.jsx)(n.a,{href:"https://en.cppreference.com/w/c/language/storage_duration",children:(0,s.jsx)(n.code,{children:"thread_local"})})," storage duration specifiers, it disables multi-threading support."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_orm"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"ORM-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"enabled"}),", then only the ",(0,s.jsx)(n.code,{children:"query builder"})," without ",(0,s.jsx)(n.code,{children:"ORM"})," is compiled. Also excludes ",(0,s.jsx)(n.code,{children:"ORM-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"disable_tom"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Controls the compilation of all ",(0,s.jsx)(n.code,{children:"Tom-related"})," source code, when this option is ",(0,s.jsx)(n.code,{children:"disabled"}),", then it also excludes ",(0,s.jsx)(n.code,{children:"Tom-related"})," unit tests."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"extern_constants"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Use ",(0,s.jsx)(n.code,{children:"extern"})," constants instead of ",(0,s.jsx)(n.code,{children:"inline"})," constants in the ",(0,s.jsx)(n.code,{children:"shared build"}),".",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"ON"})," is highly recommended for the ",(0,s.jsx)(n.code,{children:"shared build"})," ",(0,s.jsx)("small",{children:"(by default)"}),";",(0,s.jsx)("br",{}),"is always ",(0,s.jsx)(n.code,{children:"OFF"})," for the ",(0,s.jsx)(n.code,{children:"static build"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)("code",{children:"CONFIG(shared|dll):!inline_constants"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"inline_constants"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Use ",(0,s.jsx)(n.code,{children:"inline"})," constants instead of ",(0,s.jsx)(n.code,{children:"extern"})," constants in the ",(0,s.jsx)(n.code,{children:"shared build"}),".",(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"OFF"})," is highly recommended for the ",(0,s.jsx)(n.code,{children:"shared build"}),";",(0,s.jsx)("br",{}),"is always ",(0,s.jsx)(n.code,{children:"ON"})," for the ",(0,s.jsx)(n.code,{children:"static build"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"link_pkgconfig_off"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Link against ",(0,s.jsx)(n.code,{children:"mysqlclient"})," or ",(0,s.jsx)(n.code,{children:"libmariadb"})," with ",(0,s.jsx)(n.code,{children:"PKGCONFIG"}),".",(0,s.jsx)("br",{}),"Used only in the ",(0,s.jsx)(n.code,{children:"Unix"})," and ",(0,s.jsx)(n.code,{children:"MinGW"})," ",(0,s.jsx)(n.strong,{children:"shared"})," build ",(0,s.jsxs)("small",{children:["(exactly ",(0,s.jsx)("code",{children:"win32-g++|win32-clang-g++"}),")"]})," and when ",(0,s.jsx)(n.code,{children:"mysql_ping"})," is also defined to link against ",(0,s.jsx)(n.code,{children:"mysqlclient"})," or ",(0,s.jsx)(n.code,{children:"libmariadb"}),", ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L132",children:"source code"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Available when: ",(0,s.jsx)(n.code,{children:"unix:mysql_ping"})," or ",(0,s.jsx)("code",{children:"(win32-g++|win32-clang-g++):mysql_ping:!static:!staticlib"})]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"mysql_ping"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.code,{children:"Orm::MySqlConnection::pingDatabase()"})," method."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"tiny_ccache_win32"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ON"})}),(0,s.jsxs)(n.td,{children:["Enable compiler cache. ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:"Homepage"}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It works only on Windows systems. It works well with the MSYS2 ",(0,s.jsx)(n.code,{children:"g++"}),", ",(0,s.jsx)(n.code,{children:"clang++"}),", ",(0,s.jsx)(n.code,{children:"msvc"}),", and ",(0,s.jsx)(n.code,{children:"clang-cl"})," with ",(0,s.jsx)(n.code,{children:"msvc"}),". It replaces the ",(0,s.jsx)(n.code,{children:"-Zi"})," and ",(0,s.jsx)(n.code,{children:"-ZI"})," compiler options with the ",(0,s.jsx)(n.code,{children:"-Z7"})," for debug builds as the ",(0,s.jsx)(n.code,{children:"-Zi"})," and ",(0,s.jsx)(n.code,{children:"-ZI"})," compiler options are not supported (",(0,s.jsx)(n.a,{href:"https://github.com/ccache/ccache/issues/1040",children:"link"})," to the issue) and disables ",(0,s.jsx)(n.code,{children:"precompile_header"})," if ",(0,s.jsx)(n.code,{children:"ccache"})," ",(0,s.jsx)(n.code,{children:"<4.10"})," as they are not supported on Windows."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"tom_example"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build the ",(0,s.jsx)("abbr",{title:"TinyORM Migrations",children:(0,s.jsx)(n.code,{children:"tom"})})," console application example."]})]})]})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Advanced ",(0,s.jsx)(n.code,{children:"TinyORM"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Option Name"}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsx)(n.tbody,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ubsan"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Allows to enable ",(0,s.jsx)(n.a,{href:"https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html",children:"UBSan"})," sanitizer (Clang only)."]})]})})]})})}),"\n",(0,s.jsxs)(n.p,{children:["Important ",(0,s.jsx)(n.code,{children:"qmake"})," options."]}),"\n",(0,s.jsx)("div",{className:"apitable-build-options",children:(0,s.jsx)(l.A,{name:"qmake",children:(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.th,{children:[(0,s.jsx)(n.code,{children:"CONFIG"})," ",(0,s.jsx)("small",{children:"Option Name"})]}),(0,s.jsx)(n.th,{children:"Default"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ccache"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable compiler cache. ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:"Homepage"}),(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["It works only on the Unix systems. It works well with ",(0,s.jsx)(n.code,{children:"g++"})," and ",(0,s.jsx)(n.code,{children:"clang++"})," and also supports precompiled headers. TinyORM overrides this qmake option with the ",(0,s.jsx)(n.a,{href:"#ccache",children:(0,s.jsx)(n.code,{children:"ccache"})})," option.",(0,s.jsx)("br",{}),"See ",(0,s.jsx)(n.a,{href:"#ccache-support",children:"Ccache support"})," for more information."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"ltcg"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Enable ",(0,s.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Interprocedural_optimization",children:"Link time code optimization"})," (",(0,s.jsx)(n.a,{href:"https://wiki.gentoo.org/wiki/LTO",children:"LTO"}),").",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["Works on all ",(0,s.jsx)(n.a,{href:"/supported-compilers",children:"Supported Compilers"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"precompile_header"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"-"})}),(0,s.jsxs)(n.td,{children:["Enable precompiled headers, you can disable them with:",(0,s.jsx)("br",{})," ",(0,s.jsx)(n.code,{children:"CONFIG-=precompile_header"}),".",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"precompile_header"})," is enabled by default on ",(0,s.jsx)(n.code,{children:"msvc"}),", ",(0,s.jsx)(n.code,{children:"g++"}),", ",(0,s.jsx)(n.code,{children:"clang++"}),", ",(0,s.jsx)(n.code,{children:"clang-cl"})," on ",(0,s.jsx)(n.code,{children:"Windows"})," and disabled by default on ",(0,s.jsx)(n.code,{children:"linux"}),"."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"static"}),(0,s.jsx)("br",{}),(0,s.jsx)(n.code,{children:"staticlib"})]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Build as a ",(0,s.jsx)(n.code,{children:"static"})," library (lib only).",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["If you want to build all libraries in the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project as static library archives and link against static libraries use the ",(0,s.jsx)(n.a,{href:"https://doc.qt.io/qt/qmake-variable-reference.html#config",children:(0,s.jsx)(n.code,{children:"CONFIG += static"})}),". Don't use the ",(0,s.jsx)(n.code,{children:"CONFIG += staticlib"}),".",(0,s.jsx)("br",{}),"See ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/NOTES.txt",children:"NOTES.txt"})," for more information (search ",(0,s.jsx)(n.code,{children:"static vs staticlib"}),")."]})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"static_runtime"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"OFF"})}),(0,s.jsxs)(n.td,{children:["Link against the ",(0,s.jsx)(n.code,{children:"shared"})," (dynamic) or ",(0,s.jsx)(n.code,{children:"static"})," run-time library.",(0,s.jsx)("br",{}),(0,s.jsxs)("small",{children:["The ",(0,s.jsx)(n.code,{children:"-MD"})," becomes ",(0,s.jsx)(n.code,{children:"-MT"})," and ",(0,s.jsx)(n.code,{children:"-MDd"})," becomes ",(0,s.jsx)(n.code,{children:"-MTd"}),". It works only on ",(0,s.jsx)(n.code,{children:"MSVC"})," and ",(0,s.jsx)(n.code,{children:"MinGW"})," or ",(0,s.jsx)(n.code,{children:"MSYS2"}),".",(0,s.jsx)("br",{}),"Please ",(0,s.jsx)("u",{children:"don't use"})," this option.",(0,s.jsx)("br",{}),"Available when: ",(0,s.jsx)(n.code,{children:"msvc"})," or ",(0,s.jsx)(n.code,{children:"mingw"})]})]})]})]})]})})}),"\n",(0,s.jsxs)(n.h3,{id:"consume-tinyorm-library-qmake",children:["Consume TinyOrm library ",(0,s.jsx)("small",{children:"(qmake)"})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/qmake/TinyOrm.pri",children:(0,s.jsx)(n.code,{children:"TinyOrm.pri"})})," file is available to simplify the integration of the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library into your application. It sets up and configures the ",(0,s.jsx)(n.code,{children:"CONFIG"})," and ",(0,s.jsx)(n.code,{children:"DEFINES"})," qmake variables, adds the ",(0,s.jsx)(n.code,{children:"TinyORM"}),", ",(0,s.jsx)("abbr",{title:"TinyORM Migrations",children:(0,s.jsx)(n.code,{children:"tom"})}),", and ",(0,s.jsx)(n.code,{children:"vcpkg"})," header files on the system ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," (cross-platform using the ",(0,s.jsx)(n.code,{children:"-isystem"})," or ",(0,s.jsx)(n.code,{children:"-imsvc"}),"), links against the TinyORM ",(0,s.jsx)(n.code,{children:"shared"})," or ",(0,s.jsx)(n.code,{children:"static"})," library using the ",(0,s.jsx)(n.code,{children:"LIBS"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["You can use it to configure the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library when you are linking against it. It does a very similar thing like the CMake's ",(0,s.jsx)(n.code,{children:"Find Modules"})," feature."]}),"\n",(0,s.jsx)(n.h4,{id:"requirements",children:"Requirements"}),"\n",(0,s.jsx)(n.p,{children:"It has a few requirements, you need to:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["specify path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," qmake features (",(0,s.jsx)(n.code,{children:".prf"})," files) using the ",(0,s.jsx)(n.code,{children:"QMAKEFEATURES"})," variable that can only be set in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file"]}),"\n",(0,s.jsxs)(n.li,{children:["specify ",(0,s.jsx)(n.code,{children:"qmake"})," or ",(0,s.jsx)(n.code,{children:"environment"})," variables to find the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation ",(0,s.jsxs)("small",{children:["(",(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})," and ",(0,s.jsx)(n.code,{children:"TINY_VCPKG_TRIPLET"}),")"]})]}),"\n",(0,s.jsxs)(n.li,{children:["specify path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder ",(0,s.jsxs)("small",{children:["(",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"}),")"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["you can specify it ",(0,s.jsx)(n.strong,{children:"manually"})]}),"\n",(0,s.jsxs)(n.li,{children:["or you can use ",(0,s.jsxs)(n.a,{href:"#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})]}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["build your application with the same ",(0,s.jsx)(n.code,{children:"CONFIG"})," ",(0,s.jsx)(n.code,{children:"qmake"})," variables that were used when building the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library"]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Let's explain one by one."}),"\n",(0,s.jsx)(n.h5,{id:"qmakefeatures",children:(0,s.jsx)(n.code,{children:"QMAKEFEATURES"})}),"\n",(0,s.jsxs)(n.p,{children:["Create the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file in your application root folder with the following content."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# Path to the PARENT folder of the TinyORM source folder\nTINY_MAIN_DIR = $$clean_path()\n# To find .env and .env.$$QMAKE_PLATFORM files in YOUR project\nTINY_DOTENV_ROOT = $$PWD\n\n# Path to the TinyORM build folder (specified manually)\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/)\n# vcpkg - range-v3 and tabulate\nTINY_VCPKG_ROOT = $$quote(/vcpkg/)\n#TINY_VCPKG_TRIPLET = x64-windows\n\n# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants\nQMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You can move all ",(0,s.jsx)(n.code,{children:"qmake"})," variables that are part of the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration process to the ",(0,s.jsx)(n.code,{children:".env"})," file if you want (recommended), this is possible because the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," enables the ",(0,s.jsx)(n.a,{href:"#environment-files",children:(0,s.jsx)(n.code,{children:"Environment files"})})," feature by default."]}),"\n",(0,s.jsxs)(n.p,{children:["You can look at the ",(0,s.jsx)(n.a,{href:"/building/hello-world#auto-configure-using-qmake_conf-and-env",children:"Auto-configure using .qmake.conf and .env"})," example for ",(0,s.jsx)(n.code,{children:"Hello world"})," project of what must stay in the ",(0,s.jsx)(n.code,{children:"qmake.conf"})," file and what can be moved to the ",(0,s.jsx)(n.code,{children:".env"})," files."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can use the ",(0,s.jsxs)(n.a,{href:"#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," if you don't like to specify it manually."]})}),"\n",(0,s.jsxs)(n.h5,{id:"variables-affecting-tinyormpri",children:["Variables affecting ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})]}),"\n",(0,s.jsxs)(n.p,{children:["You must define the following variables before the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," is included:"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation folder.",(0,s.jsx)("br",{}),"If not defined, then it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_TRIPLET"})}),(0,s.jsxs)(n.td,{children:["The ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," to use ",(0,s.jsx)("small",{children:"(vcpkg/installed/$$TINY_VCPKG_TRIPLET/)"}),".",(0,s.jsx)("br",{}),"If not defined, then it tries to guess the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," based on the current compiler and OS (based on the ",(0,s.jsx)(n.code,{children:"QMAKESPEC"}),"), and as the last thing, it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_DEFAULT_TRIPLET"})," environment variable."]})]})]})]}),"\n",(0,s.jsx)(n.p,{children:"These variables will be set after the configuration is done:"}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_BUILD_SUBFOLDER"})}),(0,s.jsxs)(n.td,{children:["Folder by release type if ",(0,s.jsx)(n.code,{children:"CONFIG+=debug_and_release"})," is defined ",(0,s.jsx)("small",{children:"(/debug, /release, or an empty string)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_CCACHE_BUILD"})}),(0,s.jsxs)(n.td,{children:["To correctly link ",(0,s.jsx)(n.code,{children:"ccache"})," build against a ",(0,s.jsx)(n.code,{children:"ccache"})," build ",(0,s.jsx)("small",{children:"(_ccache or an empty string)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MSVC_VERSION"})}),(0,s.jsxs)(n.td,{children:["The ",(0,s.jsx)(n.code,{children:"MSVC"})," compiler string ",(0,s.jsx)("small",{children:"(MSVC2022 or MSVC2019)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_QT_VERSION_UNDERSCORED"})}),(0,s.jsxs)(n.td,{children:["Underscored ",(0,s.jsx)(n.code,{children:"Qt"})," version ",(0,s.jsx)("small",{children:"(eg. 6_7_2)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_RELEASE_TYPE_CAMEL"})}),(0,s.jsxs)(n.td,{children:["Build type string ",(0,s.jsx)("small",{children:"(Debug, Profile, or Release)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_INCLUDE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"include"})," folder ",(0,s.jsx)("small",{children:"(vcpkg/installed//include/)"}),"."]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["Then you simply include the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," in your project file."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='AnyProject.pro'",children:"include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["And that is all, now you should be able to link against the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library. \ud83d\udc4c"]}),"\n",(0,s.jsx)(n.h5,{id:"manual-configuration-examples",children:"Manual configuration examples"}),"\n",(0,s.jsxs)(n.p,{children:["Frankly, there is no reason to use the Manual configuration (define the variables described below before the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," inclusion), the only reason to use it is when you want more control over this process or want to define everything yourself. I'll leave this section here to show how things work."]}),"\n",(0,s.jsxs)(n.p,{children:["You will have to link against the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library manually if you don't set the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," ",(0,s.jsx)(n.code,{children:"qmake"})," variable before the inclusion of the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," file. The ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," is auto-detected every time."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"{9}",children:"# Link against TinyORM library\n# ---\nTINY_MAIN_DIR = $$clean_path()\n\n# Configure TinyORM library\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n\n# TinyORM library path\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake)\nLIBS += $$quote(-L$$TINYORM_BUILD_TREE/build-TinyORM-Desktop_Qt_6_7_2_MSVC2019_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)\nLIBS += -lTinyOrm\n"})})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"{9}",children:"# Link against TinyORM library\n# ---\nTINY_MAIN_DIR = $$clean_path()\n\n# Configure TinyORM library\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n\n# TinyORM library path\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake)\nLIBS += $$quote(-L$$TINYORM_BUILD_TREE/build-TinyORM-Desktop_Qt_6_7_2_GCC_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)\nLIBS += -lTinyOrm\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["The same is true for the ",(0,s.jsx)(n.code,{children:"vcpkg"})," include path. If you don't set the ",(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})," or have not defined the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable, then you need to set up the ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," for the ",(0,s.jsx)(n.code,{children:"vcpkg"})," that provides the ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," header files."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# vcpkg - range-v3 and tabulate\n# ---\nINCLUDEPATH += $$quote(/vcpkg/installed/x64-windows/include/)\n"})})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# vcpkg - range-v3 and tabulate\n# ---\nQMAKE_CXXFLAGS += -isystem $$shell_quote(/vcpkg/installed/x64-linux/include/)\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["You can also use TinyORM's ",(0,s.jsx)(n.code,{children:"qmake"})," function ",(0,s.jsx)(n.code,{children:"tiny_add_system_includepath()"})," which handles ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," in a cross-platform way."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# vcpkg - range-v3 and tabulate\n# ---\nload(tiny_system_includepath)\ntiny_add_system_includepath(/vcpkg/installed/x64-linux/include/)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Do not forget to add ",(0,s.jsx)(n.code,{children:"TinyOrm0.dll"})," on the path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux, so your application can find it during execution."]}),"\n",(0,s.jsxs)(o.A,{groupId:y.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(t.A,{value:y.b,label:y.ux,children:(0,s.jsx)(c.A,{className:"language-powershell",children:`$env:Path = "${(0,x.OZ)(y.b,!1)}\\TinyORM\\TinyORM-builds-qmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(t.A,{value:y.xj,label:y.gg,children:(0,s.jsx)(c.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,x.OZ)(y.xj)}/TinyORM/TinyORM-builds-qmake/build-debug\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.admonition,{type:"tip",children:[(0,s.jsxs)(n.p,{children:["On Linux ",(0,s.jsx)(n.code,{children:"-isystem"})," marks the directory as a system directory, it prevents warnings."]}),(0,s.jsxs)(n.p,{children:["On Windows you can use ",(0,s.jsx)(n.code,{children:"QMAKE_CXXFLAGS_WARN_ON = -external:anglebrackets -external:W0"}),", it applies a warning level 0 to the angel bracket includes; ",(0,s.jsx)(n.code,{children:"#include "}),"."]}),(0,s.jsxs)(n.p,{children:["With the ",(0,s.jsx)(n.code,{children:"Clang-cl"})," with ",(0,s.jsx)(n.code,{children:"MSVC"})," you can use ",(0,s.jsx)(n.code,{children:"-imsvc"}),"."]})]}),"\n",(0,s.jsx)(n.h3,{id:"auto-configuration-internals",children:"Auto-configuration internals"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"qmake"})," build system does not support ",(0,s.jsx)(n.code,{children:"auto-configuration"})," of dependencies out of the box but ",(0,s.jsx)(n.code,{children:"TinyORM"})," from ",(0,s.jsx)(n.code,{children:"v0.34.0"})," added its own ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature along with the ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," qmake feature. These new features allow us to ",(0,s.jsx)(n.code,{children:"auto-configure"})," ",(0,s.jsx)(n.code,{children:"TinyORM"})," project, and with their help, the ",(0,s.jsx)(n.code,{children:"conf.pri"})," files can be ",(0,s.jsx)("u",{children:"skipped entirely"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["While it adds additional complexity to the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration process, the benefits are significant."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature is designed to find the ",(0,s.jsx)(n.code,{children:"vcpkg"})," and ",(0,s.jsx)(n.code,{children:"MySQL"})," installations, and ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," to include the ",(0,s.jsx)(n.code,{children:".env"})," and ",(0,s.jsx)(n.code,{children:".env.(win32|unix|mingw)"})," files in the project's root folder. These new features can be configured using ",(0,s.jsx)(n.code,{children:"qmake"})," and ",(0,s.jsx)(n.code,{children:"environment"})," variables, and they also contain some guessing logic if these variables are not defined."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_autoconf",children:(0,s.jsx)(n.code,{children:"disable_autoconf"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_autoconf"}),")."]}),"\n",(0,s.jsxs)(n.p,{children:["These are ",(0,s.jsx)("u",{children:(0,s.jsx)(n.code,{children:"qmake"})})," and ",(0,s.jsx)("u",{children:(0,s.jsx)(n.code,{children:"environment"})})," variables that affect the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature:"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," installation folder.",(0,s.jsx)("br",{}),"If not defined, then it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_TRIPLET"})}),(0,s.jsxs)(n.td,{children:["The ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," to use ",(0,s.jsx)("small",{children:"(vcpkg/installed/$$TINY_VCPKG_TRIPLET/)"}),".",(0,s.jsx)("br",{}),"If not defined, then it tries to guess the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"triplet"})," based on the current compiler and OS (based on the ",(0,s.jsx)(n.code,{children:"QMAKESPEC"}),"), and as the last thing, it tries to use the ",(0,s.jsx)(n.code,{children:"VCPKG_DEFAULT_TRIPLET"})," environment variable."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MYSQL_ROOT"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"MySQL"})," installation folder.",(0,s.jsx)("br",{}),"If not defined, then it tries to guess the ",(0,s.jsx)(n.code,{children:"MySQL"})," installation folder (",(0,s.jsx)(n.code,{children:"win32"})," only): ",(0,s.jsx)("code",{children:"$$(ProgramFiles)/MySQL/MySQL Server (8.4|8.3|8.2|8.1|8.0|5.7)/"})]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["You can set these variables in the ",(0,s.jsx)(n.code,{children:".env"})," (recommended) or ",(0,s.jsx)(n.code,{children:"conf.pri"})," files, in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file (or wherever you want), or as environment variables."]}),"\n",(0,s.jsxs)(n.p,{children:["These variables will be set after ",(0,s.jsx)(n.code,{children:"auto-configuration"})," is done:"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_VCPKG_INCLUDE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"vcpkg"})," ",(0,s.jsx)(n.code,{children:"include"})," folder ",(0,s.jsx)("small",{children:"(vcpkg/installed//include/)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MYSQL_INCLUDE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"MySQL"})," ",(0,s.jsx)(n.code,{children:"include"})," folder ",(0,s.jsx)("small",{children:"(MySQL Server 8.4/include/)"}),"."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MYSQL_LIB"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.code,{children:"MySQL"})," ",(0,s.jsx)(n.code,{children:"lib"})," folder ",(0,s.jsx)("small",{children:"(MySQL Server 8.4/lib/)"}),"."]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TINY_MYSQL_INCLUDE"})," and ",(0,s.jsx)(n.code,{children:"TINY_MYSQL_LIB"})," are only set on ",(0,s.jsx)(n.code,{children:"win32"})," platform except ",(0,s.jsx)(n.code,{children:"mingw"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"environment-files",children:"Environment files"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature allows us to define the ",(0,s.jsx)(n.code,{children:".env"})," and ",(0,s.jsx)(n.code,{children:".env.$$TINY_DOTENV_PLATFORM"})," files in the project's root folder. These files are loaded as early as possible so you can affect the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration process. On the other hand, the ",(0,s.jsx)(n.code,{children:"conf.pri"})," files are loaded as late as possible, and they can be used to override the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:".env"})," file is included ",(0,s.jsx)("u",{children:"first"})," and is included on all platforms."]}),"\n",(0,s.jsxs)(n.p,{children:["There is only one requirement for this feature to work correctly, and that is to set the ",(0,s.jsx)(n.code,{children:"TINY_DOTENV_ROOT"})," ",(0,s.jsx)(n.code,{children:"qmake"})," variable to the project's root folder. This variable is ",(0,s.jsx)(n.strong,{children:"already"})," set in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file for the ",(0,s.jsx)(n.code,{children:"TinyORM"})," project."]}),"\n",(0,s.jsx)(n.p,{children:"Then the following names are taken into account: .env, .env.win32, .env.unix, .env.mingw"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# To find .env and .env.$$QMAKE_PLATFORM files\nTINY_DOTENV_ROOT = $$PWD\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tiny_dotenv"})," feature can be turned off using the ",(0,s.jsx)(n.a,{href:"#disable_dotenv",children:(0,s.jsx)(n.code,{children:"disable_dotenv"})})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration option (eg. ",(0,s.jsx)(n.code,{children:"CONFIG*=disable_dotenv"}),")."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"Environment files"})," don't work in the ",(0,s.jsx)(n.code,{children:"CMake"})," builds."]})}),"\n",(0,s.jsxs)(n.h4,{id:"partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]}),"\n",(0,s.jsxs)(n.p,{children:["You don't have to manually define the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," in ",(0,s.jsx)(n.code,{children:".env"})," or ",(0,s.jsx)(n.code,{children:".qmake.conf"})," files. The ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," absolute path can be put together for you (this is happening inside the ",(0,s.jsx)(n.code,{children:"variables.pri"})," file) and ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder name can be guessed for you too."]}),"\n",(0,s.jsxs)(n.p,{children:["You must define the following variables before the ",(0,s.jsx)(n.code,{children:"TinyOrm.pri"})," will be included to make this real (set them in the ",(0,s.jsx)(n.code,{children:".qmake.conf"}),"):"]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Variable Name"}),(0,s.jsx)(n.th,{children:"Description"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_MAIN_DIR"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.strong,{children:"PARENT"})," folder of the ",(0,s.jsx)(n.code,{children:"TinyORM"})," source folder."]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE"})}),(0,s.jsxs)(n.td,{children:["Path to the ",(0,s.jsx)(n.strong,{children:"current"})," build tree - ",(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE = $$shadowed($$PWD)"}),"."]})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TINY_MAIN_DIR"})," is required for another features anyway (so it should already be set) and all that's left is to set the ",(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# Path to the current build tree (used to guess the TinyORM build tree)\nTINY_BUILD_TREE = $$shadowed($$PWD)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If you will follow this pattern or logic then you can switch ",(0,s.jsx)(n.code,{children:"QtCreator Kits"})," and the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," will be ",(0,s.jsx)(n.strong,{children:"auto-generated"})," correctly and will always point to the correct ",(0,s.jsx)(n.code,{children:"TinyORM"})," build tree."]}),"\n",(0,s.jsxs)(n.p,{children:["It works this way, all is happening inside the ",(0,s.jsx)(n.code,{children:"variables.pri"}),", it takes a build folder name for the ",(0,s.jsx)(n.strong,{children:"current"})," project eg. ",(0,s.jsx)(n.code,{children:"build-HelloWorld-Desktop_Qt_6_7_2_MSVC2022_64bit-Debug"}),", replaces the ",(0,s.jsx)(n.code,{children:"HelloWorld"})," with the ",(0,s.jsx)(n.code,{children:"TinyORM"})," and as we already know the ",(0,s.jsx)(n.code,{children:"TinyORM"})," build folder location we can simply concatenate these paths like ",(0,s.jsx)(n.code,{children:"$$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSVC2022_64bit-Debug"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["This will only work if you follow the recommended ",(0,s.jsx)(n.a,{href:"#folders-structure",children:(0,s.jsx)(n.code,{children:"Folders structure"})}),"."]})}),"\n",(0,s.jsx)(n.h3,{id:"manual-configuration-internals",children:"Manual configuration internals"}),"\n",(0,s.jsxs)(n.p,{children:["There is not much to say about the ",(0,s.jsx)(n.code,{children:"Manual configuration"})," feature. It uses ",(0,s.jsx)(n.code,{children:"conf.pri"})," files (there are four, one for every project or sub-project), and every project has prepared its own ",(0,s.jsx)(n.code,{children:"conf.pri.example"})," file for faster initial configuration."]}),"\n",(0,s.jsxs)(n.p,{children:["These ",(0,s.jsx)(n.code,{children:"conf.pri.example"})," files are nicely commented on, so you can see what needs to be modified. The ",(0,s.jsx)(n.code,{children:"conf.pri"})," files are loaded as late as possible, and they can be used to override the ",(0,s.jsx)(n.code,{children:"qmake"})," configuration."]}),"\n",(0,s.jsxs)(n.p,{children:["If the ",(0,s.jsx)(n.code,{children:"Auto-configuration"})," feature is disabled and there are no ",(0,s.jsx)(n.code,{children:"conf.pri"})," files, then the ",(0,s.jsx)(n.code,{children:"TinyORM"})," ",(0,s.jsx)(n.code,{children:"qmake"})," configuration or build will fail at 100%."]}),"\n",(0,s.jsxs)(n.p,{children:["These ",(0,s.jsx)(n.code,{children:"conf.pri"})," files are intended for configuring qmake's ",(0,s.jsx)(n.code,{children:"INCLUDEPATH"})," and ",(0,s.jsx)(n.code,{children:"LIBS"}),", ",(0,s.jsx)(n.code,{children:"CONFIG"})," or eg. ",(0,s.jsx)(n.code,{children:"QMAKE_LFLAGS"}),", or any other ",(0,s.jsx)(n.code,{children:"qmake"})," options or variables."]}),"\n",(0,s.jsx)(n.h2,{id:"ccache-support",children:"Ccache support"}),"\n",(0,s.jsxs)(n.p,{children:["The TinyORM supports the ",(0,s.jsx)(n.a,{href:"https://ccache.dev/",children:(0,s.jsx)(n.code,{children:"ccache"})})," out of the box for all ",(0,s.jsx)(n.a,{href:"/supported-compilers",children:"supported compilers"}),". For ",(0,s.jsx)(n.code,{children:"qmake"})," you can enable it using the ",(0,s.jsx)(n.a,{href:"#ccache",children:(0,s.jsx)(n.code,{children:"CONFIG+=ccache"})})," and for ",(0,s.jsx)(n.code,{children:"CMake"})," you can set the ",(0,s.jsx)(n.a,{href:"#CMAKE_CXX_COMPILER_LAUNCHER",children:(0,s.jsx)(n.code,{children:"CMAKE_CXX_COMPILER_LAUNCHER=ccache"})}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["On ",(0,s.jsx)(n.code,{children:"Linux"})," it's clear, the ",(0,s.jsx)(n.code,{children:"ccache"})," is fully supported and works also with the ",(0,s.jsx)(n.code,{children:"precompiled headers"}),". But was necessary to add some workarounds to the ",(0,s.jsx)(n.code,{children:"qmake"}),"/",(0,s.jsx)(n.code,{children:"CMake"})," build systems to make out of the box support on ",(0,s.jsx)(n.code,{children:"Windows"}),". When you enable the ",(0,s.jsx)(n.code,{children:"ccache"})," on ",(0,s.jsx)(n.code,{children:"Windows"})," then the build system replaces the ",(0,s.jsx)(n.code,{children:"-Zi"})," and ",(0,s.jsx)(n.code,{children:"-ZI"})," compiler options with the ",(0,s.jsx)(n.code,{children:"-Z7"})," (link to the ",(0,s.jsx)(n.a,{href:"https://github.com/ccache/ccache/issues/1040",children:"issue"}),") and disables ",(0,s.jsx)(n.code,{children:"precompiled headers"})," if ",(0,s.jsx)(n.code,{children:"ccache <4.10"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can install the ",(0,s.jsx)(n.code,{children:"ccache"})," using the ",(0,s.jsx)(n.code,{children:"scoop install ccache"})," command on Windows. See the ",(0,s.jsx)(n.a,{href:"/dependencies#linux-installation-ccache",children:"Dependencies"})," page for how to install ",(0,s.jsx)(n.code,{children:"ccache"})," on Linux."]})})]})}function I(e={}){const{wrapper:n}={...(0,d.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(M,{...e})}):M(e)}},9365:(e,n,i)=>{i.d(n,{A:()=>l});i(6540);var s=i(4164);const d={tabItem:"tabItem_Ymn6"};var r=i(4848);function l(e){let{children:n,hidden:i,className:l}=e;return(0,r.jsx)("div",{role:"tabpanel",className:(0,s.A)(d.tabItem,l),hidden:i,children:n})}},1470:(e,n,i)=>{i.d(n,{A:()=>_});var s=i(6540),d=i(4164),r=i(3104),l=i(6347),c=i(205),t=i(7485),o=i(1682),a=i(679);function h(e){return s.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,s.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function x(e){const{values:n,children:i}=e;return(0,s.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:i,attributes:s,default:d}}=e;return{value:n,label:i,attributes:s,default:d}}))}(i);return function(e){const n=(0,o.X)(e,((e,n)=>e.value===n.value));if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[n,i])}function j(e){let{value:n,tabValues:i}=e;return i.some((e=>e.value===n))}function u(e){let{queryString:n=!1,groupId:i}=e;const d=(0,l.W6)(),r=function(e){let{queryString:n=!1,groupId:i}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!i)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return i??null}({queryString:n,groupId:i});return[(0,t.aZ)(r),(0,s.useCallback)((e=>{if(!r)return;const n=new URLSearchParams(d.location.search);n.set(r,e),d.replace({...d.location,search:n.toString()})}),[r,d])]}function p(e){const{defaultValue:n,queryString:i=!1,groupId:d}=e,r=x(e),[l,t]=(0,s.useState)((()=>function(e){let{defaultValue:n,tabValues:i}=e;if(0===i.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!j({value:n,tabValues:i}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${i.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const s=i.find((e=>e.default))??i[0];if(!s)throw new Error("Unexpected error: 0 tabValues");return s.value}({defaultValue:n,tabValues:r}))),[o,h]=u({queryString:i,groupId:d}),[p,m]=function(e){let{groupId:n}=e;const i=function(e){return e?`docusaurus.tab.${e}`:null}(n),[d,r]=(0,a.Dv)(i);return[d,(0,s.useCallback)((e=>{i&&r.set(e)}),[i,r])]}({groupId:d}),b=(()=>{const e=o??p;return j({value:e,tabValues:r})?e:null})();(0,c.A)((()=>{b&&t(b)}),[b]);return{selectedValue:l,selectValue:(0,s.useCallback)((e=>{if(!j({value:e,tabValues:r}))throw new Error(`Can't select invalid tab value=${e}`);t(e),h(e),m(e)}),[h,m,r]),tabValues:r}}var m=i(2303);const b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var f=i(4848);function g(e){let{className:n,block:i,selectedValue:s,selectValue:l,tabValues:c}=e;const t=[],{blockElementScrollPositionUntilNextRender:o}=(0,r.a_)(),a=e=>{const n=e.currentTarget,i=t.indexOf(n),d=c[i].value;d!==s&&(o(n),l(d))},h=e=>{let n=null;switch(e.key){case"Enter":a(e);break;case"ArrowRight":{const i=t.indexOf(e.currentTarget)+1;n=t[i]??t[0];break}case"ArrowLeft":{const i=t.indexOf(e.currentTarget)-1;n=t[i]??t[t.length-1];break}}n?.focus()};return(0,f.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,d.A)("tabs",{"tabs--block":i},n),children:c.map((e=>{let{value:n,label:i,attributes:r}=e;return(0,f.jsx)("li",{role:"tab",tabIndex:s===n?0:-1,"aria-selected":s===n,ref:e=>t.push(e),onKeyDown:h,onClick:a,...r,className:(0,d.A)("tabs__item",b.tabItem,r?.className,{"tabs__item--active":s===n}),children:i??n},n)}))})}function y(e){let{lazy:n,children:i,selectedValue:d}=e;const r=(Array.isArray(i)?i:[i]).filter(Boolean);if(n){const e=r.find((e=>e.props.value===d));return e?(0,s.cloneElement)(e,{className:"margin-top--md"}):null}return(0,f.jsx)("div",{className:"margin-top--md",children:r.map(((e,n)=>(0,s.cloneElement)(e,{key:n,hidden:e.props.value!==d})))})}function T(e){const n=p(e);return(0,f.jsxs)("div",{className:(0,d.A)("tabs-container",b.tabList),children:[(0,f.jsx)(g,{...n,...e}),(0,f.jsx)(y,{...n,...e})]})}function _(e){const n=(0,m.A)();return(0,f.jsx)(T,{...e,children:h(e.children)},String(n))}},6684:(e,n,i)=>{i.d(n,{A:()=>a});var s=i(6540),d=i(3427),r=i(6347);const l={apiTable:"apiTable_flxF"};var c=i(4848);function t(e,n){let{name:i,children:l}=e;const t=function(e){let n=e;for(;(0,s.isValidElement)(n);)[n]=s.Children.toArray(n.props.children);if("string"!=typeof n)throw new Error(`Could not extract APITable row name from JSX tree:\n${JSON.stringify(e,null,2)}`);return n}(l),o=i?`${i}-${t}`:t,a=`#${o}`,h=(0,r.W6)();return(0,d.A)().collectAnchor(o),(0,c.jsx)("tr",{id:o,tabIndex:0,ref:h.location.hash===a?n:void 0,onClick:e=>{const n=e.target;[n,n.parentElement].some((e=>"A"===e?.tagName.toUpperCase()))||h.push(a)},onKeyDown:e=>{"Enter"===e.key&&h.push(a)},children:l.props.children})}const o=s.forwardRef(t);function a(e){let{children:n,name:i}=e;if("table"!==n.type)throw new Error("Bad usage of APITable component.\nIt is probably that your Markdown table is malformed.\nMake sure to double-check you have the appropriate number of columns for each table row.");const[d,r]=s.Children.toArray(n.props.children),t=(0,s.useRef)(null);(0,s.useEffect)((()=>{t.current?.focus()}),[t]);const a=s.Children.map(r.props.children,(e=>(0,c.jsx)(o,{name:i,ref:t,children:e})));return(0,c.jsxs)("table",{className:l.apiTable,children:[d,(0,c.jsx)("tbody",{children:a})]})}},7324:(e,n,i)=>{i.d(n,{$E:()=>m,A3:()=>f,CW:()=>b,Dx:()=>a,F4:()=>x,Fi:()=>o,J_:()=>_,LQ:()=>g,Lf:()=>v,OO:()=>d,Q7:()=>y,b:()=>c,cy:()=>t,gg:()=>u,kl:()=>j,os:()=>h,pW:()=>r,ux:()=>p,vf:()=>s,xj:()=>l,xt:()=>T});const s="shell",d="database",r="application",l="bash",c="pwsh",t="zsh",o="maria",a="mysql",h="postgres",x="sqlite",j="application",u="bash",p="pwsh",m="zsh",b="MariaDB",f="MySQL",g="PostgreSQL",y="SQLite",T="tinyorm.org",_="$HOME/Code/c/",v="$env:USERPROFILE\\Code\\c\\"},6362:(e,n,i)=>{i.d(n,{A:()=>r});var s=i(6540),d=i(1838);function r(){const e=(0,s.useContext)(d.A);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6694:(e,n,i)=>{i.d(n,{OZ:()=>t,Sn:()=>l,T3:()=>a,bw:()=>o,nC:()=>h,np:()=>c});var s=i(6362),d=i(2303),r=i(7324);const l=function(e,n){return void 0===n&&(n=!0),x((0,s.A)().rootFolder[e]??o(e),e,n)},c=()=>(0,s.A)().rootFolder[r.pW]??o(r.pW),t=function(e,n){if(void 0===n&&(n=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const i=n||e!==r.b?"/":"\\";return x(l(e)+i+c(),e,n)};function o(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,d.A)())return"";switch(e){case r.b:return r.Lf;case r.xj:return r.J_;case r.pW:return r.xt;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function a(e){return e===r.pW}function h(e,n){if(null==n||""===n)return n;const i="$ENV{$1}$2";switch(e){case r.b:return u(n).replace(/\$env:(.+?)(\/.*)/,i);case r.xj:return n.replace(/\$(.+?)(\/.*)/,i);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function x(e,n,i){if(void 0===i&&(i=!0),null==e||""===e)return e;if(n!==r.b)return j(e);const s=j(e);return i?u(s):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(s)}function j(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function u(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},2721:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-additional_arguments-14d3b6b82ad6d28db5b999a462500a6a.png"},7619:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-build_settings-7caa6d7c86232484b82acb24b5a3a6a7.png"},885:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-configure_project-0b6821ea0523567dab9f21b3215055a3.png"}}]); \ No newline at end of file diff --git a/assets/js/5b254f70.48fa5efd.js b/assets/js/5b254f70.45cd6b2c.js similarity index 99% rename from assets/js/5b254f70.48fa5efd.js rename to assets/js/5b254f70.45cd6b2c.js index 1d7ac443a..653a3ea0f 100644 --- a/assets/js/5b254f70.48fa5efd.js +++ b/assets/js/5b254f70.45cd6b2c.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[82],{560:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>m,frontMatter:()=>l,metadata:()=>r,toc:()=>c});var i=t(4848),s=t(8453),a=t(8774);const l={sidebar_position:0,sidebar_label:"Getting Started",description:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.',keywords:["c++ orm","orm","getting started","tinyorm"]},d="TinyORM: Getting Started",r={id:"tinyorm/getting-started",title:"TinyORM: Getting Started",description:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.',source:"@site/docs/tinyorm/getting-started.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/getting-started",permalink:"/tinyorm/getting-started",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"Getting Started",description:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.',keywords:["c++ orm","orm","getting started","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Seeding",permalink:"/database/seeding"},next:{title:"Relationships",permalink:"/tinyorm/relationships"}},o={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Generating Model Classes",id:"generating-model-classes",level:2},{value:"TinyORM Model Conventions",id:"tinyorm-model-conventions",level:2},{value:"Table Names",id:"table-names",level:3},{value:"Primary Keys",id:"primary-keys",level:3},{value:""Composite" Primary Keys",id:"composite-primary-keys",level:4},{value:"Timestamps",id:"timestamps",level:3},{value:"Unix timestamps",id:"unix-timestamps",level:5},{value:"Custom timestamp column names",id:"custom-timestamp-column-names",level:5},{value:"Touching timestamps",id:"touching-timestamps",level:4},{value:"Database Connections",id:"database-connections",level:3},{value:"Default Attribute Values",id:"default-attribute-values",level:2},{value:"QDateTime and connection name problem",id:"qdatetime-and-connection-name-problem",level:5},{value:"Retrieving Models",id:"retrieving-models",level:2},{value:"Building Queries",id:"building-queries",level:4},{value:"Refreshing Models",id:"refreshing-models",level:4},{value:"Containers",id:"containers",level:3},{value:"Chunking Results",id:"chunking-results",level:3},{value:"Advanced Subqueries",id:"advanced-subqueries",level:3},{value:"Subquery Selects",id:"subquery-selects",level:4},{value:"Subquery Ordering",id:"subquery-ordering",level:4},{value:"Retrieving Single Models / Aggregates",id:"retrieving-single-models-and-aggregates",level:2},{value:"Not Found Exceptions",id:"not-found-exceptions",level:4},{value:"Retrieving Or Creating Models",id:"retrieving-or-creating-models",level:3},{value:"Retrieving Aggregates",id:"retrieving-aggregates",level:3},{value:"Inserting & Updating Models",id:"inserting-and-updating-models",level:2},{value:"Inserts",id:"inserts",level:3},{value:"Updates",id:"updates",level:3},{value:"Mass Updates",id:"mass-updates",level:4},{value:"Examining Attribute Changes",id:"examining-attribute-changes",level:4},{value:"Mass Assignment",id:"mass-assignment",level:3},{value:"Allowing Mass Assignment",id:"allowing-mass-assignment",level:4},{value:"Upserts",id:"upserts",level:3},{value:"Deleting Models",id:"deleting-models",level:2},{value:"Deleting An Existing Model By Its Primary Key",id:"deleting-an-existing-model-by-its-primary-key",level:4},{value:"Deleting Models Using Queries",id:"deleting-models-using-queries",level:4},{value:"Soft Deleting",id:"soft-deleting",level:3},{value:"Restoring Soft Deleted Models",id:"restoring-soft-deleted-models",level:4},{value:"Permanently Deleting Models",id:"permanently-deleting-models",level:4},{value:"Querying Soft Deleted Models",id:"querying-soft-deleted-models",level:3},{value:"Including Soft Deleted Models",id:"including-soft-deleted-models",level:4},{value:"Retrieving Only Soft Deleted Models",id:"retrieving-only-soft-deleted-models",level:4},{value:"Excluding Soft Deleted Models",id:"excluding-soft-deleted-models",level:4},{value:"Truncate Table",id:"truncate-table",level:3},{value:"Replicating Models",id:"replicating-models",level:2},{value:"Comparing Models",id:"comparing-models",level:2},{value:"Equality comparison",id:"equality-comparison",level:5}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"tinyorm-getting-started",children:"TinyORM: Getting Started"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#generating-model-classes",children:"Generating Model Classes"})}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#tinyorm-model-conventions",children:"TinyORM Model Conventions"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#table-names",children:"Table Names"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#primary-keys",children:"Primary Keys"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#timestamps",children:"Timestamps"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#database-connections",children:"Database Connections"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#default-attribute-values",children:"Default Attribute Values"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#retrieving-models",children:"Retrieving Models"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#containers",children:"Containers"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#chunking-results",children:"Chunking Results"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#advanced-subqueries",children:"Advanced Subqueries"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#retrieving-single-models-and-aggregates",children:"Retrieving Single Models / Aggregates"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#retrieving-or-creating-models",children:"Retrieving Or Creating Models"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#retrieving-aggregates",children:"Retrieving Aggregates"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#inserting-and-updating-models",children:"Inserting & Updating Models"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#inserts",children:"Inserts"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#updates",children:"Updates"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#mass-assignment",children:"Mass Assignment"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#upserts",children:"Upserts"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#deleting-models",children:"Deleting Models"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#soft-deleting",children:"Soft Deleting"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#querying-soft-deleted-models",children:"Querying Soft Deleted Models"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#truncate-table",children:"Truncate Table"})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#replicating-models",children:"Replicating Models"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#comparing-models",children:"Comparing Models"})}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsx)(n.p,{children:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.'}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Before getting started, be sure to configure a database connection in your application. For more information on configuring your database, check out the ",(0,i.jsx)(n.a,{href:"/database/getting-started#configuration",children:"database configuration documentation"}),"."]})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["If you want to see a model in which are used all possible TinyORM features you can look at the ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/models/models/torrent.hpp",children:(0,i.jsx)(n.code,{children:"torrent.hpp"})})," in the TinyORM's tests, this ",(0,i.jsx)(n.code,{children:"Models::Torrent"})," class serves also as a showcase, so all possible features are defined in it."]})}),"\n",(0,i.jsx)(n.h2,{id:"generating-model-classes",children:"Generating Model Classes"}),"\n",(0,i.jsxs)(n.p,{children:["To get started, let's create the simplest TinyORM model. Models typically live in the ",(0,i.jsx)(n.code,{children:"database\\models"})," directory and extend the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Model"})," class. You may use the ",(0,i.jsx)(n.code,{children:"make:model"})," command to generate a new model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model User\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you would like to generate a database ",(0,i.jsx)(n.a,{href:"/database/migrations",children:"migration"})," or ",(0,i.jsx)(n.a,{href:"/database/seeding",children:"seeder"})," when you generate the model, you may use the ",(0,i.jsx)(n.code,{children:"--migration"}),"/",(0,i.jsx)(n.code,{children:"-m"})," or ",(0,i.jsx)(n.code,{children:"--seeder"}),"/",(0,i.jsx)(n.code,{children:"-s"})," options:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model User --migration --seeder\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"--force"})," option forces overwriting of existing files:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model User --migration --seeder --force\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"make:model"})," is king \ud83d\udc51 among scaffolding commands that you can use to generate complete TinyORM model classes, it supports all features that TinyORM models offer. All advanced features are described in the ",(0,i.jsx)(n.code,{children:"make:model"})," help command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model --help\n"})}),"\n",(0,i.jsx)(n.p,{children:"Few examples:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"# Setting some model attributes\ntom make:model User --table=users --fillable=name,email,banned_at `\n --guarded=password --dates=banned_at\n\n# Generate relationship methods\ntom make:model User --one-to-one=Passport `\n --one-to-many=Post --foreign-key=post_id `\n --one-to-many=Car\n\n# Generate a basic many-to-many relationship\ntom make:model User --belongs-to-many=Tag --with-timestamps\n\n# Generate a many-to-many relationship\ntom make:model User --belongs-to-many=Tag --foreign-key=tag_id `\n --pivot-table=user_tag --as=tagged `\n --with-pivot=active,soft --with-timestamps `\n --pivot=Tagged\n\n# Generate a pivot model\ntom make:model Tagged --pivot-model\ntom make:model Tagged --pivot-model --incrementing\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Writing a ",(0,i.jsx)(n.code,{children:"make:model"})," commands is superb with the ",(0,i.jsx)(n.a,{href:"/database/migrations#tab-completion",children:"tab completion"}),"."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"--path"})," and ",(0,i.jsx)(n.code,{children:"--realpath"})," options work the same as for the ",(0,i.jsx)(n.a,{href:"/database/migrations#generating-migrations",children:(0,i.jsx)(n.code,{children:"make:migration"})})," command."]})}),"\n",(0,i.jsx)(n.h2,{id:"tinyorm-model-conventions",children:"TinyORM Model Conventions"}),"\n",(0,i.jsx)(n.p,{children:"Let's examine a basic model class and discuss some of TinyORM's key conventions:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#pragma once\n#ifndef FLIGHT_HPP\n#define FLIGHT_HPP\n\n#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n\n using Model::Model;\n};\n\n#endif // FLIGHT_HPP\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/models/models/torrent.hpp#L43",children:(0,i.jsx)(n.code,{children:"Torrent"})})," example model that also acts as the full-fledged example model. It has defined and also nicely commented all possible features that model classes can use or define."]})}),"\n",(0,i.jsx)(n.h3,{id:"table-names",children:"Table Names"}),"\n",(0,i.jsxs)(n.p,{children:["After glancing at the example above, you may have noticed that we did not tell TinyORM which database table corresponds to our ",(0,i.jsx)(n.code,{children:"Flight"}),' model. By convention, the "snake_case", plural name of the class will be used as the table name unless another name is explicitly specified. So, in this case, TinyORM will assume the ',(0,i.jsx)(n.code,{children:"Flight"})," model stores records in the ",(0,i.jsx)(n.code,{children:"flights"})," table, while an ",(0,i.jsx)(n.code,{children:"AirTrafficController"})," model would store records in an ",(0,i.jsx)(n.code,{children:"air_traffic_controllers"})," table."]}),"\n",(0,i.jsxs)(n.p,{children:["If your model's corresponding database table does not fit this convention, you may manually specify the model's table name by defining the private ",(0,i.jsx)(n.code,{children:"u_table"})," data member on the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The table associated with the model. */\n QString u_table {"flights"};\n};\n'})}),"\n",(0,i.jsx)(n.h3,{id:"primary-keys",children:"Primary Keys"}),"\n",(0,i.jsxs)(n.p,{children:["TinyORM will also assume that each model's corresponding database table has a primary key column named ",(0,i.jsx)(n.code,{children:"id"}),". If necessary, you may define a private ",(0,i.jsx)(n.code,{children:"u_primaryKey"})," data member on your model to specify a different column that serves as your model's primary key:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The primary key associated with the table. */\n QString u_primaryKey {"id"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["In addition, TinyORM assumes that the primary key is an incrementing integer value. If you wish to use a non-incrementing or a non-numeric primary key you must define a private ",(0,i.jsx)(n.code,{children:"u_incrementing"})," data member on your model that is set to ",(0,i.jsx)(n.code,{children:"false"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! Indicates if the model's ID is auto-incrementing. */\n bool u_incrementing = false;\n};\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["Non-numeric primary keys are not currently implemented, ",(0,i.jsx)(n.code,{children:"u_incrementing"})," code logic is fully implemented, but it is only one part to make it fully work."]})}),"\n",(0,i.jsx)(n.h4,{id:"composite-primary-keys",children:'"Composite" Primary Keys'}),"\n",(0,i.jsx)(n.p,{children:'TinyORM requires each model to have at least one uniquely identifying "ID" that can serve as its primary key. "Composite" primary keys are not supported by TinyORM models. However, you are free to add additional multi-column unique indexes to your database tables, in addition to the table\'s uniquely identifying primary key.'}),"\n",(0,i.jsx)(n.h3,{id:"timestamps",children:"Timestamps"}),"\n",(0,i.jsxs)(n.p,{children:["By default, TinyORM expects ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," columns to exist on your model's corresponding database table. TinyORM will automatically set these column's values when models are created or updated. If you do not want these columns to be automatically managed by TinyORM, you should define a private ",(0,i.jsx)(n.code,{children:"u_timestamps"})," data member on your model with a value of ",(0,i.jsx)(n.code,{children:"false"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! Indicates if the model should be timestamped. */\n bool u_timestamps = false;\n};\n"})}),"\n",(0,i.jsx)(a.A,{id:"timestamps-u_dates"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"u_dates"})," static data member controls the casting of timestamp attributes. The ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," columns are automatically added to the ",(0,i.jsx)(n.code,{children:"u_dates"})," string list when the ",(0,i.jsx)(n.code,{children:"u_timestamps"})," is ",(0,i.jsx)(n.code,{children:"true"}),". Also, the ",(0,i.jsx)(n.a,{href:"#soft-deleting",children:(0,i.jsx)(n.code,{children:"Soft Deleting"})})," feature adds the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to the ",(0,i.jsx)(n.code,{children:"u_dates"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["You may add additional columns to the ",(0,i.jsx)(n.code,{children:"u_dates"})," list. After that, these columns will be automatically formatted using the format in the ",(0,i.jsx)(n.code,{children:"u_dateFormat"})," data member during the ",(0,i.jsx)(n.code,{children:"setAttribute"})," method call:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'class Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The attributes that should be mutated to dates. */\n inline static const QStringList u_dates {"departure_at"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If you need to customize the format of your model's timestamps, set the private ",(0,i.jsx)(n.code,{children:"u_dateFormat"})," data member on your model. This data member determines how date attributes are stored in the database, supported formats are described in the ",(0,i.jsx)(n.code,{children:"QDateTime"})," documentation:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The storage format of the model\'s date columns. */\n QString u_dateFormat {"yyyy-MM-dd HH:mm:ss"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If you need to customize the format of your model's time columns, set the private ",(0,i.jsx)(n.code,{children:"u_timeFormat"})," data member on your model. This data member determines how time attributes are stored in the database, supported formats are described in the ",(0,i.jsx)(n.code,{children:"QTime"})," documentation. The default value for ",(0,i.jsx)(n.code,{children:"u_timeFormat"})," is ",(0,i.jsx)(n.code,{children:"HH:mm:ss"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'/*! The storage format of the model\'s time columns. */\nQString u_timeFormat {"HH:mm:ss.zzz"};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The default value for datetime or timestamp columns is ",(0,i.jsx)(n.code,{children:"yyyy-MM-dd HH:mm:ss"})," and for time columns is ",(0,i.jsx)(n.code,{children:"HH:mm:ss"}),"."]}),"\n",(0,i.jsx)(n.h5,{id:"unix-timestamps",children:"Unix timestamps"}),"\n",(0,i.jsxs)(n.p,{children:["You can set the ",(0,i.jsx)(n.code,{children:"u_dateFormat"})," to ",(0,i.jsx)(n.code,{children:"U"})," if you want to store dates in the database as unix timestamps:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"QString u_dateFormat {QLatin1Char('U')};\n"})}),"\n",(0,i.jsxs)(n.p,{children:["In this case ",(0,i.jsx)(n.strong,{children:"all"})," date attributes set in the ",(0,i.jsx)(n.code,{children:"u_dates"})," will be handled as unix timestamps, so also the ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamp attributes."]}),"\n",(0,i.jsxs)(n.p,{children:["To create unix timestamp columns using the ",(0,i.jsx)(n.a,{href:"/database/migrations",children:"tom migrations"})," you should use ",(0,i.jsx)(n.code,{children:"integer"})," types:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Schema::table("flights", [](Blueprint &table)\n{\n table.bigInteger("created_at").nullable();\n table.bigInteger("updated_at").nullable();\n});\n'})}),"\n",(0,i.jsx)(n.h5,{id:"custom-timestamp-column-names",children:"Custom timestamp column names"}),"\n",(0,i.jsxs)(n.p,{children:["If you need to customize the names of the columns used to store the timestamps, you may define ",(0,i.jsx)(n.code,{children:"CREATED_AT"})," and ",(0,i.jsx)(n.code,{children:"UPDATED_AT"})," private static getter methods on your model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The name of the "created at" column. */\n static QString CREATED_AT() { return QStringLiteral("creation_date"); }\n /*! The name of the "updated at" column. */\n static QString UPDATED_AT() { return QStringLiteral("updated_date"); }\n};\n'})}),"\n",(0,i.jsx)(n.h4,{id:"touching-timestamps",children:"Touching timestamps"}),"\n",(0,i.jsxs)(n.p,{children:["You can explicitly touch timestamps using the ",(0,i.jsx)(n.code,{children:"touch"})," method defined on the Model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::find(1);\n\nflight->touch();\nflight->touch("added_on"); // Custom column name\n'})}),"\n",(0,i.jsxs)(n.p,{children:["You can also touch multiple rows at once using the ",(0,i.jsx)(n.code,{children:"touch"})," method defined on the TinyBuilder:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto [affected, query] = Flight::whereEq("status", "new")->touch();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"touch"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'flight->history()->touch();\nflight->history()->whereEq("status", "new").touch();\n'})}),"\n",(0,i.jsx)(n.h3,{id:"database-connections",children:"Database Connections"}),"\n",(0,i.jsxs)(n.p,{children:["By default, all TinyORM models will use the default database connection that is configured for your application. If you would like to specify a different connection that should be used when interacting with a particular model, you should define a ",(0,i.jsx)(n.code,{children:"u_connection"})," private data member on the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The database connection that should be used by the model. */\n QString u_connection {"sqlite"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["In special cases, when you want to query the database through a different connection, you can use ",(0,i.jsx)(n.code,{children:"Model::on"})," method, which takes the connection name as the first argument:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto user = User::on("sqlite")->find(1);\n'})}),"\n",(0,i.jsx)(n.h2,{id:"default-attribute-values",children:"Default Attribute Values"}),"\n",(0,i.jsxs)(n.p,{children:["By default, a newly instantiated model instance will not contain any attribute values. If you would like to define the default values for some of your model's attributes, you may define an ",(0,i.jsx)(n.code,{children:"u_attributes"})," data member on your model, it has to be ",(0,i.jsx)(n.strong,{children:"static"})," and can be ",(0,i.jsx)(n.strong,{children:"const"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\n#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The model\'s default values for attributes. */\n inline static const QVector u_attributes {\n {"delayed", false},\n {"progress", 0},\n {"added_on", QDateTime::currentDateTimeUtc()},\n };\n};\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["Use the ",(0,i.jsx)(n.code,{children:"Model::instance"})," or ",(0,i.jsx)(n.code,{children:"Model::instanceHeap"})," related methods to instantiate a model that contains a ",(0,i.jsx)(n.code,{children:"QDateTime"})," in Default Attribute Values, or if attributes you want to pass to the model's constructor contain a ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance ",(0,i.jsx)("small",{children:"(problem is described below)"}),"."]})}),"\n",(0,i.jsx)(n.h5,{id:"qdatetime-and-connection-name-problem",children:"QDateTime and connection name problem"}),"\n",(0,i.jsxs)(n.p,{children:["If your Default Attribute Values or attributes that you can pass to the ",(0,i.jsx)(n.code,{children:"Model"})," constructor contain the ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance, then ",(0,i.jsx)(n.code,{children:"TinyORM"})," throws an exception. You have to use the ",(0,i.jsx)(n.code,{children:"Model::instance"})," related methods to create such a Model."]}),"\n",(0,i.jsxs)(n.p,{children:["Virtually everything important is covered in the thrown exception, but let me summarize it. The problem is that the ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance is converted to a string based on the ",(0,i.jsx)(n.code,{children:"Model::u_dateFormat"}),", or if not defined, the date format from ",(0,i.jsx)(n.code,{children:"Orm::Query::Grammars::Grammar"})," will be used. This ",(0,i.jsx)(n.code,{children:"QueryGrammar"})," is obtained from ",(0,i.jsx)(n.code,{children:"Orm::DatabaseConnection"})," and because of that TinyORM needs to know the ",(0,i.jsx)(n.strong,{children:"connection name"})," and that's the crux of this problem. You can define your connection name using the ",(0,i.jsx)(n.code,{children:"Model::u_connection"})," in your derived model class, but this derived model ",(0,i.jsx)(n.strong,{children:"is not yet initialized"}),", so the ",(0,i.jsx)(n.code,{children:"Model::u_connection"})," is also not initialized."]}),"\n",(0,i.jsxs)(n.p,{children:["So if the ",(0,i.jsx)(n.code,{children:"Model::u_connection"})," is not yet initialized, ",(0,i.jsx)(n.code,{children:"TinyORM"})," can't obtain the ",(0,i.jsx)(n.code,{children:"Orm::DatabaseConnection"})," -> ",(0,i.jsx)(n.code,{children:"QueryGrammar"})," -> ",(0,i.jsx)(n.code,{children:"dateFormat"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"retrieving-models",children:"Retrieving Models"}),"\n",(0,i.jsxs)(n.p,{children:["Once you have created a model and its associated database table, you are ready to start retrieving data from your database. You can think of each TinyORM model as a powerful ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"})," allowing you to fluently query the database table associated with the model. The model's ",(0,i.jsx)(n.code,{children:"all"})," method will retrieve all of the records from the model's associated database table:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\n#include "models/flight.hpp"\n\nfor (const auto &flight : Flight::all())\n qDebug() << flight["name"].toString();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"building-queries",children:"Building Queries"}),"\n",(0,i.jsxs)(n.p,{children:["The TinyORM ",(0,i.jsx)(n.code,{children:"all"})," method will return all of the results in the model's table. However, since each TinyORM model serves as a ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"}),", you may add additional constraints to queries and then invoke the ",(0,i.jsx)(n.code,{children:"get"})," method to retrieve the results:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::whereEq("active", 1)\n ->orderBy("name")\n .take(10)\n .get();\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Since TinyORM models are query builders, you should review all of the methods provided by TinyORM's ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"}),". You may use any of these methods when writing your TinyORM queries."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["All the static methods defined on the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Model"})," class, which start building queries like ",(0,i.jsx)(n.code,{children:"where"}),", ",(0,i.jsx)(n.code,{children:"latest"}),", ",(0,i.jsx)(n.code,{children:"oldest"}),", ",(0,i.jsx)(n.code,{children:"with"}),", ... return ",(0,i.jsx)(n.code,{children:"std::unique_ptr>"}),", ",(0,i.jsx)(n.code,{children:"TinyBuilder = Orm::Tiny::Builder"})," and ",(0,i.jsx)(n.code,{children:"Model"})," template argument is queried model class."]})}),"\n",(0,i.jsx)(n.h4,{id:"refreshing-models",children:"Refreshing Models"}),"\n",(0,i.jsxs)(n.p,{children:['If you already have an instance of the TinyORM model that was retrieved from the database, you can "refresh" the model using the ',(0,i.jsx)(n.code,{children:"fresh"})," and ",(0,i.jsx)(n.code,{children:"refresh"})," methods. The ",(0,i.jsx)(n.code,{children:"fresh"})," method will re-retrieve the model from the database. The existing model instance will not be affected:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::whereEq("number", "FR 900")->first();\n\nauto freshFlight = flight->fresh();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"refresh"})," method will re-hydrate the existing model using fresh data from the database. In addition, all of its loaded relationships will be refreshed as well:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::whereEq("number", "FR 900")->first();\n\nflight->setAttribute("number", "FR 456");\n\nflight->refresh();\n\nflight->getAttribute("number"); // "FR 900"\n'})}),"\n",(0,i.jsx)(n.h3,{id:"containers",children:"Containers"}),"\n",(0,i.jsxs)(n.p,{children:["As we have seen, TinyORM methods like ",(0,i.jsx)(n.code,{children:"all"})," and ",(0,i.jsx)(n.code,{children:"get"})," retrieve multiple records from the database. Since these methods return a ",(0,i.jsx)(n.code,{children:"QVector"}),", you can iterate it like any other container with the ",(0,i.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/language/range-for",children:"Range-based for loop"}),", ",(0,i.jsx)(n.a,{href:"https://doc.qt.io/qt/containers.html#stl-style-iterators",children:"STL-Style Iterators"}),", ",(0,i.jsx)(n.a,{href:"https://doc.qt.io/qt/containers.html#java-style-iterators",children:"Java-Style Iterators"})," or ",(0,i.jsx)(n.a,{href:"https://www.walletfox.com/course/quickref_range_v3.php",children:"Ranges"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\n#include "models/flight.hpp"\n\nfor (const auto &flight : Flight::all())\n qDebug() << flight["name"].toString();\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["An ",(0,i.jsx)(n.code,{children:"all"})," method is defined on the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Model"})," class and ",(0,i.jsx)(n.code,{children:"get"})," method is defined on the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Builder"}),", may be also referred as ",(0,i.jsx)(n.code,{children:"TinyBuilder"}),", and on the ",(0,i.jsx)(n.code,{children:"Orm::Query::Builder"})," alias ",(0,i.jsx)(n.code,{children:"QueryBuilder"}),"."]})}),"\n",(0,i.jsx)(n.h3,{id:"chunking-results",children:"Chunking Results"}),"\n",(0,i.jsxs)(n.p,{children:["Your application may run out of memory if you attempt to load tens of thousands of TinyORM records via the ",(0,i.jsx)(n.code,{children:"all"})," or ",(0,i.jsx)(n.code,{children:"get"})," methods. Instead of using these methods, the ",(0,i.jsx)(n.code,{children:"chunk"})," method may be used to process large numbers of models more efficiently."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"chunk"})," method will retrieve a subset of TinyORM models, passing them to a lambda expression for processing. Since only the current chunk of TinyORM models is retrieved at a time, the ",(0,i.jsx)(n.code,{children:"chunk"})," method will provide significantly reduced memory usage when working with a large number of models:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"Flight::chunk(200, [](QVector &&flights, const int /*unused*/)\n{\n for (auto &&flight : flights) {\n //\n }\n\n return true;\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The first argument passed to the ",(0,i.jsx)(n.code,{children:"chunk"}),' method is the number of records you wish to receive per "chunk". The lambda expression passed as the second argument will be invoked for each chunk that is retrieved from the database. A database query will be executed to retrieve each chunk of records passed to the lambda expression.']}),"\n",(0,i.jsxs)(n.p,{children:["If you are filtering the results of the ",(0,i.jsx)(n.code,{children:"chunk"})," method based on a column that you will also be updating while iterating over the results, you should use the ",(0,i.jsx)(n.code,{children:"chunkById"})," method. Using the ",(0,i.jsx)(n.code,{children:"chunk"})," method in these scenarios could lead to unexpected and inconsistent results. Internally, the ",(0,i.jsx)(n.code,{children:"chunkById"})," method will always retrieve models with an ",(0,i.jsx)(n.code,{children:"id"})," column greater than the last model in the previous chunk:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::whereEq("departed", true)\n ->chunkById(200, [](QVector &&flights, const int /*unused*/)\n {\n for (auto &&flight : flights)\n flight.update({{"departed", false}});\n\n return true;\n });\n'})}),"\n",(0,i.jsx)(n.h3,{id:"advanced-subqueries",children:"Advanced Subqueries"}),"\n",(0,i.jsx)(n.h4,{id:"subquery-selects",children:"Subquery Selects"}),"\n",(0,i.jsxs)(n.p,{children:["TinyORM also offers advanced subquery support, which allows you to pull information from related tables in a single query. For example, let's imagine that we have a table of flight ",(0,i.jsx)(n.code,{children:"destinations"})," and a table of ",(0,i.jsx)(n.code,{children:"flights"})," to destinations. The ",(0,i.jsx)(n.code,{children:"flights"})," table contains an ",(0,i.jsx)(n.code,{children:"arrived_at"})," column which indicates when the flight arrived at the destination."]}),"\n",(0,i.jsxs)(n.p,{children:["Using the subquery functionality available to the query builder's ",(0,i.jsx)(n.code,{children:"select"})," and ",(0,i.jsx)(n.code,{children:"addSelect"})," methods, we can select all of the ",(0,i.jsx)(n.code,{children:"destinations"})," and the name of the flight that most recently arrived at that destination using a single query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/destination.hpp"\n#include "models/flight.hpp"\n\nreturn Destination::addSelect(\n Flight::select("name")\n ->whereColumnEq("destination_id", "destinations.id")\n .orderByDesc("arrived_at")\n .limit(1)\n .toBase(),\n "last_flight")\n ->get();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"subquery-ordering",children:"Subquery Ordering"}),"\n",(0,i.jsxs)(n.p,{children:["In addition, the query builder's ",(0,i.jsx)(n.code,{children:"orderBy"})," function supports subqueries. Continuing to use our flight example, we may use this functionality to sort all destinations based on when the last flight arrived at that destination. Again, this may be done while executing a single database query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'return Destination::orderByDesc(\n Flight::select("arrived_at")\n ->whereColumnEq("destination_id", "destinations.id")\n .orderByDesc("arrived_at")\n .limit(1)\n .toBase())\n ->get();\n'})}),"\n",(0,i.jsx)(n.h2,{id:"retrieving-single-models-and-aggregates",children:"Retrieving Single Models / Aggregates"}),"\n",(0,i.jsxs)(n.p,{children:["In addition to retrieving all of the records matching a given query, you may also retrieve single records using the ",(0,i.jsx)(n.code,{children:"find"}),", ",(0,i.jsx)(n.code,{children:"first"}),", ",(0,i.jsx)(n.code,{children:"firstWhere"}),", or ",(0,i.jsx)(n.code,{children:"firstWhereEq"})," methods. Instead of returning a vector of models, these methods return a single model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\n// Retrieve a model by its primary key...\nauto flight = Flight::find(1);\n\n// Retrieve the first model matching the query constraints...\nauto flight = Flight::whereEq("active", 1)->first();\n\n// Alternative to retrieving the first model matching the query constraints...\nauto flight = Flight::firstWhere("active", "=", 1);\n\n// Alternative firstWhere method syntax\nauto flight = Flight::firstWhereEq("active", 1);\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes you may wish to perform some other action if no results are found. The ",(0,i.jsx)(n.code,{children:"findOr"})," methods will return a single model instance or, if no results are found, execute the given lambda expression. The value returned by the lambda will be considered the result of the method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"auto flight = Flight::findOr(1, [] {\n // ...\n});\n\nauto flight = Flight::findOr(1, [] {\n // ...\n return 10;\n});\n\nauto flight = Flight::findOr>(1, [] {\n // ...\n return Flight::find(10);\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["To obtain only a subset of the model's attributes you may use the ",(0,i.jsx)(n.code,{children:"Model::only"})," method, it returns the ",(0,i.jsx)(n.code,{children:"QVector"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nusing Orm::Constants::ID;\nusing Orm::Constants::NAME;\n\nauto flight = Flight::find(1);\n\nauto attributes = flight->only({ID, NAME});\n'})}),"\n",(0,i.jsx)(n.h4,{id:"not-found-exceptions",children:"Not Found Exceptions"}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes you may wish to throw an exception if a model is not found. The ",(0,i.jsx)(n.code,{children:"findOrFail"})," and ",(0,i.jsx)(n.code,{children:"firstOrFail"})," methods will retrieve the first result of the query; however, if no result is found, an ",(0,i.jsx)(n.code,{children:"Orm::Tiny::ModelNotFoundError"})," will be thrown:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::findOrFail(1);\n\nauto flight = Flight::where("legs", ">", 3)->firstOrFail();\n'})}),"\n",(0,i.jsx)(n.h3,{id:"retrieving-or-creating-models",children:"Retrieving Or Creating Models"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"firstOrCreate"})," method will attempt to locate a database record using the given column / value pairs. If the model can not be found in the database, a record will be inserted with the attributes resulting from merging the first ",(0,i.jsx)(n.code,{children:"QVector"})," argument with the optional second ",(0,i.jsx)(n.code,{children:"QVector"})," argument:"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"firstOrNew"})," method, like ",(0,i.jsx)(n.code,{children:"firstOrCreate"}),", will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by ",(0,i.jsx)(n.code,{children:"firstOrNew"})," has not yet been persisted to the database. You will need to manually call the ",(0,i.jsx)(n.code,{children:"save"})," method to persist it:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\n// Retrieve flight by name or create it if it doesn\'t exist...\nauto flight = Flight::firstOrCreate({\n {"name", "London to Paris"}\n});\n\n// Retrieve flight by name or create it with the name, delayed, and arrival_time attributes...\nauto flight = Flight::firstOrCreate(\n {{"name", "London to Paris"}},\n {{"delayed", 1}, {"arrival_time", "11:30"}}\n);\n\n// Retrieve flight by name or instantiate a new Flight instance...\nauto flight = Flight::firstOrNew({\n {"name", "London to Paris"}\n});\n\n// Retrieve flight by name or instantiate with the name, delayed, and arrival_time attributes...\nauto flight = Flight::firstOrNew(\n {{"name", "Tokyo to Sydney"}},\n {{"delayed", 1}, {"arrival_time", "11:30"}}\n);\n'})}),"\n",(0,i.jsx)(n.h3,{id:"retrieving-aggregates",children:"Retrieving Aggregates"}),"\n",(0,i.jsxs)(n.p,{children:["When interacting with TinyORM models, you may also use the ",(0,i.jsx)(n.code,{children:"count"}),", ",(0,i.jsx)(n.code,{children:"sum"}),", ",(0,i.jsx)(n.code,{children:"max"}),", and other ",(0,i.jsx)(n.a,{href:"/database/query-builder#aggregates",children:"aggregate methods"})," provided by the ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"}),". As you might expect, these methods return a scalar value instead of a TinyORM model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto count = Flight::whereEq("active", 1)->count();\n\nauto max = Flight::whereEq("active", 1)->max("price");\n'})}),"\n",(0,i.jsx)(n.h2,{id:"inserting-and-updating-models",children:"Inserting & Updating Models"}),"\n",(0,i.jsx)(n.h3,{id:"inserts",children:"Inserts"}),"\n",(0,i.jsxs)(n.p,{children:["Of course, when using TinyORM, we don't only need to retrieve models from the database. We also need to insert new records. Thankfully, TinyORM makes it simple. To insert a new record into the database, you should instantiate a new model instance and set attributes on the model. Then, call the ",(0,i.jsx)(n.code,{children:"save"})," method on the model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\n// Store a new flight in the database\nFlight flight;\nflight.setAttribute("name", "Slovakia to Czech");\nflight.save();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["In this example, we assign the ",(0,i.jsx)(n.code,{children:"name"})," attribute of the ",(0,i.jsx)(n.code,{children:"Flight"})," model instance. When we call the ",(0,i.jsx)(n.code,{children:"save"})," method, a record will be inserted into the database. The model's ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamps will automatically be set when the ",(0,i.jsx)(n.code,{children:"save"})," method is called, so there is no need to set them manually."]}),"\n",(0,i.jsxs)(n.p,{children:["Alternatively, you may use the ",(0,i.jsx)(n.code,{children:"create"}),' method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the ',(0,i.jsx)(n.code,{children:"create"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::create({\n {"name", "London to Paris"},\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["However, before using the ",(0,i.jsx)(n.code,{children:"create"})," method, you will need to specify either a ",(0,i.jsx)(n.code,{children:"u_fillable"})," or ",(0,i.jsx)(n.code,{children:"u_guarded"})," static data member on your model class. These static data members are required because all TinyORM models are protected against mass assignment vulnerabilities by default. To learn more about mass assignment, please consult the ",(0,i.jsx)(n.a,{href:"#mass-assignment",children:"mass assignment documentation"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"updates",children:"Updates"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"save"})," method may also be used to update models that already exist in the database. To update a model, you should retrieve it and set any attributes you wish to update. Then, you should call the model's ",(0,i.jsx)(n.code,{children:"save"})," method. Again, the ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamp will automatically be updated, so there is no need to manually set its value:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::find(1);\n\nflight->setAttribute("name", "Paris to London");\n\nflight->save();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"mass-updates",children:"Mass Updates"}),"\n",(0,i.jsxs)(n.p,{children:["Updates can also be performed against models that match a given query. In this example, all flights that are ",(0,i.jsx)(n.code,{children:"active"})," and have a ",(0,i.jsx)(n.code,{children:"destination"})," of ",(0,i.jsx)(n.code,{children:"San Diego"})," will be marked as delayed:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::whereEq("active", 1)\n ->whereEq("destination", "San Diego")\n .update({{"delayed", 1}});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"update"})," method expects the ",(0,i.jsx)(n.code,{children:"QVector"})," of column and value pairs representing the columns that should be updated."]}),"\n",(0,i.jsx)(n.h4,{id:"examining-attribute-changes",children:"Examining Attribute Changes"}),"\n",(0,i.jsxs)(n.p,{children:["TinyORM provides the ",(0,i.jsx)(n.code,{children:"isDirty"}),", ",(0,i.jsx)(n.code,{children:"isClean"}),", and ",(0,i.jsx)(n.code,{children:"wasChanged"})," methods to examine the internal state of your model and determine how its attributes have changed from when the model was originally retrieved."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"isDirty"})," method determines if any of the model's attributes have been changed since the model was retrieved. You may pass a specific attribute name to the ",(0,i.jsx)(n.code,{children:"isDirty"})," method to determine if a particular attribute is dirty. The ",(0,i.jsx)(n.code,{children:"isClean"})," will determine if an attribute has remained unchanged since the model was retrieved. This method also accepts an optional attribute argument:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nauto user = User::create({\n {"first_name", "Silver"},\n {"last_name", "Zachara"},\n {"title", "Developer"},\n});\n\nuser.setAttribute("title", "Painter");\n\nuser.isDirty(); // true\nuser.isDirty("title"); // true\nuser.isDirty("first_name"); // false\n\nuser.isClean(); // false\nuser.isClean("title"); // false\nuser.isClean("first_name"); // true\n\nuser.save();\n\nuser.isDirty(); // false\nuser.isClean(); // true\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"wasChanged"})," method determines if any attributes were changed after the model was last saved into the database. If needed, you may pass an attribute name to see if a particular attribute was changed:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto user = User::create({\n {"first_name", "Silver"},\n {"last_name", "Zachara"},\n {"title", "Developer"},\n});\n\nuser.setAttribute("title", "Painter");\n\nuser.wasChanged(); // false\n\nuser.save();\n\nuser.wasChanged(); // true\nuser.wasChanged("title"); // true\nuser.wasChanged("first_name"); // false\n'})}),"\n",(0,i.jsx)(n.h3,{id:"mass-assignment",children:"Mass Assignment"}),"\n",(0,i.jsxs)(n.p,{children:["You may use the ",(0,i.jsx)(n.code,{children:"create"}),' method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the method:']}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::create({\n {"name", "London to Paris"},\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["However, before using the ",(0,i.jsx)(n.code,{children:"create"})," method, you will need to specify either a ",(0,i.jsx)(n.code,{children:"u_fillable"})," or ",(0,i.jsx)(n.code,{children:"u_guarded"})," static data member on your model class. These data members are required because all TinyORM models are protected against mass assignment vulnerabilities by default."]}),"\n",(0,i.jsxs)(n.p,{children:["A mass assignment vulnerability occurs when a user passes an unexpected HTTP request field and that field changes a column in your database that you did not expect. For example, a malicious user might send an ",(0,i.jsx)(n.code,{children:"is_admin"})," parameter through an HTTP request, which is then passed to your model's ",(0,i.jsx)(n.code,{children:"create"})," method, allowing the user to escalate themselves to an administrator."]}),"\n",(0,i.jsxs)(n.p,{children:["So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the ",(0,i.jsx)(n.code,{children:"u_fillable"})," static data member on the model. For example, let's make the ",(0,i.jsx)(n.code,{children:"name"})," attribute of our ",(0,i.jsx)(n.code,{children:"Flight"})," model mass assignable:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n\n using Model::Model;\n\n /*! The attributes that are mass assignable. */\n inline static QStringList u_fillable {\n "name",\n };\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Once you have specified which attributes are mass assignable, you may use the ",(0,i.jsx)(n.code,{children:"create"})," method to insert a new record in the database. The ",(0,i.jsx)(n.code,{children:"create"})," method returns the newly created model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::create({{"name", "London to Paris"}});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If you already have a model instance, you may use the ",(0,i.jsx)(n.code,{children:"fill"})," method to populate it with the vector of attributes:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'flight.fill({{"name", "Amsterdam to Frankfurt"}});\n'})}),"\n",(0,i.jsx)(n.h4,{id:"allowing-mass-assignment",children:"Allowing Mass Assignment"}),"\n",(0,i.jsxs)(n.p,{children:["If you would like to make all of your attributes mass assignable, you may define your model's ",(0,i.jsx)(n.code,{children:"u_guarded"})," static data member as an empty vector. If you choose to unguard your model, you should take special care to always hand-craft the vectors passed to TinyORM's ",(0,i.jsx)(n.code,{children:"fill"}),", ",(0,i.jsx)(n.code,{children:"create"}),", and ",(0,i.jsx)(n.code,{children:"update"})," methods:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n\n using Model::Model;\n\n /*! The attributes that aren't mass assignable. */\n inline static QStringList u_guarded {};\n};\n"})}),"\n",(0,i.jsx)(n.h3,{id:"upserts",children:"Upserts"}),"\n",(0,i.jsx)(n.p,{children:"Occasionally, you may need to update an existing model or create a new model if no matching model exists."}),"\n",(0,i.jsxs)(n.p,{children:["In the example below, if a flight exists with a ",(0,i.jsx)(n.code,{children:"departure"})," location of ",(0,i.jsx)(n.code,{children:"Oakland"})," and a ",(0,i.jsx)(n.code,{children:"destination"})," location of ",(0,i.jsx)(n.code,{children:"San Diego"}),", its ",(0,i.jsx)(n.code,{children:"price"})," and ",(0,i.jsx)(n.code,{children:"discounted"})," columns will be updated. If no such flight exists, a new flight will be created which has the attributes resulting from merging the first argument vector with the second argument vector:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::updateOrCreate(\n {{"departure", "Oakland"}, {"destination", "San Diego"}},\n {{"price", 99}, {"discounted", 1}}\n);\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"firstOrCreate"})," and ",(0,i.jsx)(n.code,{children:"updateOrCreate"})," methods persist the model, so there's no need to manually call the ",(0,i.jsx)(n.code,{children:"save"})," method."]})}),"\n",(0,i.jsxs)(n.p,{children:['If you would like to perform multiple "upserts" in a single query, then you should use the ',(0,i.jsx)(n.code,{children:"upsert"})," method instead. The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table. The method's third and final argument is the vector of the columns that should be updated if a matching record already exists in the database. The ",(0,i.jsx)(n.code,{children:"upsert"})," method will automatically set the ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamps if timestamps are enabled on the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::upsert(\n {{{"departure", "Oakland"}, {"destination", "San Diego"}, {"price", 99}},\n {{"departure", "Chicago"}, {"destination", "New York"}, {"price", 150}}},\n {"departure", "destination"},\n {"price"}\n);\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["All databases except SQL Server require the columns in the second argument of the ",(0,i.jsx)(n.code,{children:"upsert"}),' method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the ',(0,i.jsx)(n.code,{children:"upsert"}),' method and always uses the "primary" and "unique" indexes of the table to detect existing records.']})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["Row and column aliases will be used with the MySQL server >=8.0.19 instead of the VALUES() function as is described in the MySQL ",(0,i.jsx)(n.a,{href:"https://dev.mysql.com/doc/refman/8.4/en/insert-on-duplicate.html",children:"documentation"}),". The MySQL server version is auto-detected and can be overridden in the ",(0,i.jsx)(n.a,{href:"/database/getting-started#configuration",children:"configuration"}),"."]})}),"\n",(0,i.jsx)(n.h2,{id:"deleting-models",children:"Deleting Models"}),"\n",(0,i.jsxs)(n.p,{children:["To delete a model, you may call the ",(0,i.jsx)(n.code,{children:"remove"}),", or an alias ",(0,i.jsx)(n.code,{children:"deleteRow"})," method on the model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::find(1);\n\nflight->remove();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"deleting-an-existing-model-by-its-primary-key",children:"Deleting An Existing Model By Its Primary Key"}),"\n",(0,i.jsxs)(n.p,{children:["In the example above, we are retrieving the model from the database before calling the ",(0,i.jsx)(n.code,{children:"remove"})," method. However, if you know the primary key of the model, you may delete the model without explicitly retrieving it by calling the ",(0,i.jsx)(n.code,{children:"destroy"})," method. In addition to accepting the single primary key, the ",(0,i.jsx)(n.code,{children:"destroy"})," method can accept multiple primary keys:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"Flight::destroy(1);\n\nFlight::destroy({1, 2, 3});\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"destroy"})," method loads models from the database and calls the ",(0,i.jsx)(n.code,{children:"remove"})," method on each model individually, the reason for this is future compatibility with events."]})}),"\n",(0,i.jsx)(n.h4,{id:"deleting-models-using-queries",children:"Deleting Models Using Queries"}),"\n",(0,i.jsx)(n.p,{children:"Of course, you may build the query to delete all models matching your query's criteria. In this example, we will delete all flights that are marked as inactive:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto deletedRows = Flight::whereEq("active", 0)->remove();\n'})}),"\n",(0,i.jsx)(n.h3,{id:"soft-deleting",children:"Soft Deleting"}),"\n",(0,i.jsxs)(n.p,{children:['In addition to actually removing records from your database, TinyORM can also "soft delete" models. When models are soft deleted, they are not actually removed from your database. Instead, a ',(0,i.jsx)(n.code,{children:"deleted_at"}),' attribute is set on the model indicating the date and time at which the model was "deleted". To enable soft deletes for a model, add the ',(0,i.jsx)(n.code,{children:"Orm::Tiny::SoftDeletes"})," base class to the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n#include \n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::SoftDeletes;\n\nclass Flight final : public Model,\n public SoftDeletes\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The table associated with the model. */\n QString u_table {"flights"};\n};\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"SoftDeletes"})," base class will automatically cast the ",(0,i.jsx)(n.code,{children:"deleted_at"})," attribute to the ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance for you (it adds the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to the model's ",(0,i.jsx)(n.a,{href:"#timestamps-u_dates",children:(0,i.jsx)(n.code,{children:"u_dates"})})," list)."]})}),"\n",(0,i.jsxs)(n.p,{children:["You should also add the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to your database table. The TinyORM ",(0,i.jsx)(n.a,{href:"/database/migrations",children:"schema builder"})," contains a helper method to create this column:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Schema::table("flights", [](Blueprint &table)\n{\n table.softDeletes();\n});\n\nSchema::table("flights", [](Blueprint &table)\n{\n table.dropSoftDeletes();\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Now, when you call the ",(0,i.jsx)(n.code,{children:"remove"})," or ",(0,i.jsx)(n.code,{children:"deleteModel"})," method on the model, the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column will be set to the current date and time. However, the model's database record will be left in the table. When querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results."]}),"\n",(0,i.jsxs)(n.p,{children:["To determine if a given model instance has been soft deleted, you may use the ",(0,i.jsx)(n.code,{children:"trashed"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"if (flight->trashed()) {\n //\n}\n"})}),"\n",(0,i.jsx)(n.h4,{id:"restoring-soft-deleted-models",children:"Restoring Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:['Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model, you may call the ',(0,i.jsx)(n.code,{children:"restore"})," method on a model instance. The ",(0,i.jsx)(n.code,{children:"restore"})," method will set the model's ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to ",(0,i.jsx)(n.code,{children:"null"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->restore();\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You may also use the ",(0,i.jsx)(n.code,{children:"restore"})," method in a query to restore multiple models:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::withTrashed()\n ->whereEq("airline_id", 1)\n .restore();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"restore"})," method may also be used when building ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," queries:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->restore();\n"})}),"\n",(0,i.jsx)(n.h4,{id:"permanently-deleting-models",children:"Permanently Deleting Models"}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes you may need to truly remove a model from your database. You may use the ",(0,i.jsx)(n.code,{children:"forceDelete"})," method (or it's alias ",(0,i.jsx)(n.code,{children:"forceRemove"}),") to permanently remove a soft deleted model from the database table:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->forceDelete();\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You may also use the ",(0,i.jsx)(n.code,{children:"forceDelete"})," method when building TinyORM relationship queries:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->forceDelete();\n"})}),"\n",(0,i.jsx)(n.h3,{id:"querying-soft-deleted-models",children:"Querying Soft Deleted Models"}),"\n",(0,i.jsx)(n.h4,{id:"including-soft-deleted-models",children:"Including Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:["As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be included in a query's results by calling the ",(0,i.jsx)(n.code,{children:"withTrashed"})," method on the query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::withTrashed()\n ->whereEq("account_id", 1)\n .get();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"withTrashed"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->withTrashed().get();\n"})}),"\n",(0,i.jsx)(n.h4,{id:"retrieving-only-soft-deleted-models",children:"Retrieving Only Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"onlyTrashed"})," method will retrieve ",(0,i.jsx)(n.strong,{children:"only"})," soft deleted models:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::onlyTrashed()\n ->whereEq("airline_id", 1)\n .get();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"onlyTrashed"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->onlyTrashed().get();\n"})}),"\n",(0,i.jsx)(n.h4,{id:"excluding-soft-deleted-models",children:"Excluding Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:["As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be ",(0,i.jsx)(n.strong,{children:"excluded"})," in a query's results by calling the ",(0,i.jsx)(n.code,{children:"withoutTrashed"})," method on the query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::withoutTrashed()\n ->whereEq("account_id", 1)\n .get();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"withoutTrashed"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->withoutTrashed().get();\n"})}),"\n",(0,i.jsx)(n.h3,{id:"truncate-table",children:"Truncate Table"}),"\n",(0,i.jsxs)(n.p,{children:["You may call the ",(0,i.jsx)(n.code,{children:"truncate"})," method to delete all of the model's associated database records. The ",(0,i.jsx)(n.code,{children:"truncate"})," operation will also reset any auto-incrementing IDs on the model's associated table:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"Flight::truncate();\n"})}),"\n",(0,i.jsx)(n.h2,{id:"replicating-models",children:"Replicating Models"}),"\n",(0,i.jsxs)(n.p,{children:["You may create an unsaved copy of an existing model instance using the ",(0,i.jsx)(n.code,{children:"replicate"})," method. This method is particularly useful when you have model instances that share many of the same attributes:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto shipping = Address::create({\n {"type", "shipping"},\n {"line_1", "123 Example Street"},\n {"city", "Victorville"},\n {"state", "CA"},\n {"postcode", "90001"},\n});\n\nauto billing = shipping.replicate();\n\nbilling.fill({\n {"type", "billing"},\n});\n\nbilling.save();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["To exclude one or more attributes from being replicated to the new model, you may pass an unordered_set to the ",(0,i.jsx)(n.code,{children:"replicate"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::create({\n {"destination", "LAX"},\n {"origin", "LHR"},\n {"last_flown", "2020-03-04 11:00:00"},\n {"last_pilot_id", 747},\n});\n\nflight = flight.replicate({\n "last_flown",\n "last_pilot_id",\n});\n'})}),"\n",(0,i.jsx)(n.h2,{id:"comparing-models",children:"Comparing Models"}),"\n",(0,i.jsxs)(n.p,{children:['Sometimes you may need to determine if two models are the "same" or not. The ',(0,i.jsx)(n.code,{children:"is"})," and ",(0,i.jsx)(n.code,{children:"isNot"})," methods may be used to quickly verify two models have the same primary key, table, and database connection or not:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"if (post->is(anotherPost)) {\n //\n}\n\nif (post->isNot(anotherPost)) {\n //\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"is"})," and ",(0,i.jsx)(n.code,{children:"isNot"})," methods are also available when using the ",(0,i.jsx)(n.code,{children:"belongsTo"})," and ",(0,i.jsx)(n.code,{children:"hasOne"})," ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationships"}),". This method is particularly helpful when you would like to compare a related model without issuing a query to retrieve that model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"if (post->author()->is(user)) {\n //\n}\n"})}),"\n",(0,i.jsx)(n.h5,{id:"equality-comparison",children:"Equality comparison"}),"\n",(0,i.jsxs)(n.p,{children:["The base ",(0,i.jsx)(n.code,{children:"Model"})," class also defines the ",(0,i.jsx)(n.code,{children:"operator=="})," that allows precisely comparing two models. It compares the content of all the model's data members, from all base classes to the most derived model class. The ",(0,i.jsx)(n.code,{children:"model1 == model2"})," expression guarantees that these two models are exactly the same."]}),"\n",(0,i.jsxs)(n.p,{children:["It would be appropriate to mention that this comparison also includes relations, which means it will also compare ",(0,i.jsx)(n.strong,{children:"all"})," models (including their data members) these relations contain."]})]})}function m(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>d});var i=t(6540);const s={},a=i.createContext(s);function l(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[82],{560:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>d,default:()=>m,frontMatter:()=>l,metadata:()=>r,toc:()=>c});var i=t(4848),s=t(8453),a=t(8774);const l={sidebar_position:0,sidebar_label:"Getting Started",description:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.',keywords:["c++ orm","orm","getting started","tinyorm"]},d="TinyORM: Getting Started",r={id:"tinyorm/getting-started",title:"TinyORM: Getting Started",description:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.',source:"@site/docs/tinyorm/getting-started.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/getting-started",permalink:"/tinyorm/getting-started",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"Getting Started",description:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.',keywords:["c++ orm","orm","getting started","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Seeding",permalink:"/database/seeding"},next:{title:"Relationships",permalink:"/tinyorm/relationships"}},o={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Generating Model Classes",id:"generating-model-classes",level:2},{value:"TinyORM Model Conventions",id:"tinyorm-model-conventions",level:2},{value:"Table Names",id:"table-names",level:3},{value:"Primary Keys",id:"primary-keys",level:3},{value:""Composite" Primary Keys",id:"composite-primary-keys",level:4},{value:"Timestamps",id:"timestamps",level:3},{value:"Unix timestamps",id:"unix-timestamps",level:5},{value:"Custom timestamp column names",id:"custom-timestamp-column-names",level:5},{value:"Touching timestamps",id:"touching-timestamps",level:4},{value:"Database Connections",id:"database-connections",level:3},{value:"Default Attribute Values",id:"default-attribute-values",level:2},{value:"QDateTime and connection name problem",id:"qdatetime-and-connection-name-problem",level:5},{value:"Retrieving Models",id:"retrieving-models",level:2},{value:"Building Queries",id:"building-queries",level:4},{value:"Refreshing Models",id:"refreshing-models",level:4},{value:"Containers",id:"containers",level:3},{value:"Chunking Results",id:"chunking-results",level:3},{value:"Advanced Subqueries",id:"advanced-subqueries",level:3},{value:"Subquery Selects",id:"subquery-selects",level:4},{value:"Subquery Ordering",id:"subquery-ordering",level:4},{value:"Retrieving Single Models / Aggregates",id:"retrieving-single-models-and-aggregates",level:2},{value:"Not Found Exceptions",id:"not-found-exceptions",level:4},{value:"Retrieving Or Creating Models",id:"retrieving-or-creating-models",level:3},{value:"Retrieving Aggregates",id:"retrieving-aggregates",level:3},{value:"Inserting & Updating Models",id:"inserting-and-updating-models",level:2},{value:"Inserts",id:"inserts",level:3},{value:"Updates",id:"updates",level:3},{value:"Mass Updates",id:"mass-updates",level:4},{value:"Examining Attribute Changes",id:"examining-attribute-changes",level:4},{value:"Mass Assignment",id:"mass-assignment",level:3},{value:"Allowing Mass Assignment",id:"allowing-mass-assignment",level:4},{value:"Upserts",id:"upserts",level:3},{value:"Deleting Models",id:"deleting-models",level:2},{value:"Deleting An Existing Model By Its Primary Key",id:"deleting-an-existing-model-by-its-primary-key",level:4},{value:"Deleting Models Using Queries",id:"deleting-models-using-queries",level:4},{value:"Soft Deleting",id:"soft-deleting",level:3},{value:"Restoring Soft Deleted Models",id:"restoring-soft-deleted-models",level:4},{value:"Permanently Deleting Models",id:"permanently-deleting-models",level:4},{value:"Querying Soft Deleted Models",id:"querying-soft-deleted-models",level:3},{value:"Including Soft Deleted Models",id:"including-soft-deleted-models",level:4},{value:"Retrieving Only Soft Deleted Models",id:"retrieving-only-soft-deleted-models",level:4},{value:"Excluding Soft Deleted Models",id:"excluding-soft-deleted-models",level:4},{value:"Truncate Table",id:"truncate-table",level:3},{value:"Replicating Models",id:"replicating-models",level:2},{value:"Comparing Models",id:"comparing-models",level:2},{value:"Equality comparison",id:"equality-comparison",level:5}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"tinyorm-getting-started",children:"TinyORM: Getting Started"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#generating-model-classes",children:"Generating Model Classes"})}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#tinyorm-model-conventions",children:"TinyORM Model Conventions"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#table-names",children:"Table Names"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#primary-keys",children:"Primary Keys"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#timestamps",children:"Timestamps"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#database-connections",children:"Database Connections"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#default-attribute-values",children:"Default Attribute Values"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#retrieving-models",children:"Retrieving Models"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#containers",children:"Containers"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#chunking-results",children:"Chunking Results"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#advanced-subqueries",children:"Advanced Subqueries"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#retrieving-single-models-and-aggregates",children:"Retrieving Single Models / Aggregates"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#retrieving-or-creating-models",children:"Retrieving Or Creating Models"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#retrieving-aggregates",children:"Retrieving Aggregates"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#inserting-and-updating-models",children:"Inserting & Updating Models"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#inserts",children:"Inserts"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#updates",children:"Updates"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#mass-assignment",children:"Mass Assignment"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#upserts",children:"Upserts"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#deleting-models",children:"Deleting Models"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#soft-deleting",children:"Soft Deleting"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#querying-soft-deleted-models",children:"Querying Soft Deleted Models"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#truncate-table",children:"Truncate Table"})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#replicating-models",children:"Replicating Models"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#comparing-models",children:"Comparing Models"})}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsx)(n.p,{children:'TinyORM is an object-relational mapper (ORM) that makes it enjoyable to interact with your database. When using TinyORM, each database table has a corresponding "Model" that is used to interact with that table. In addition to retrieving records from the database table, TinyORM models allow you to insert, update, and delete records from the table as well.'}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Before getting started, be sure to configure a database connection in your application. For more information on configuring your database, check out the ",(0,i.jsx)(n.a,{href:"/database/getting-started#configuration",children:"database configuration documentation"}),"."]})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["If you want to see a model in which are used all possible TinyORM features you can look at the ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/models/models/torrent.hpp",children:(0,i.jsx)(n.code,{children:"torrent.hpp"})})," in the TinyORM's tests, this ",(0,i.jsx)(n.code,{children:"Models::Torrent"})," class serves also as a showcase, so all possible features are defined in it."]})}),"\n",(0,i.jsx)(n.h2,{id:"generating-model-classes",children:"Generating Model Classes"}),"\n",(0,i.jsxs)(n.p,{children:["To get started, let's create the simplest TinyORM model. Models typically live in the ",(0,i.jsx)(n.code,{children:"database\\models"})," directory and extend the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Model"})," class. You may use the ",(0,i.jsx)(n.code,{children:"make:model"})," command to generate a new model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model User\n"})}),"\n",(0,i.jsxs)(n.p,{children:["If you would like to generate a database ",(0,i.jsx)(n.a,{href:"/database/migrations",children:"migration"})," or ",(0,i.jsx)(n.a,{href:"/database/seeding",children:"seeder"})," when you generate the model, you may use the ",(0,i.jsx)(n.code,{children:"--migration"}),"/",(0,i.jsx)(n.code,{children:"-m"})," or ",(0,i.jsx)(n.code,{children:"--seeder"}),"/",(0,i.jsx)(n.code,{children:"-s"})," options:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model User --migration --seeder\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"--force"})," option forces overwriting of existing files:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model User --migration --seeder --force\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"make:model"})," is king \ud83d\udc51 among scaffolding commands that you can use to generate complete TinyORM model classes, it supports all features that TinyORM models offer. All advanced features are described in the ",(0,i.jsx)(n.code,{children:"make:model"})," help command:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"tom make:model --help\n"})}),"\n",(0,i.jsx)(n.p,{children:"Few examples:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"# Setting some model attributes\ntom make:model User --table=users --fillable=name,email,banned_at `\n --guarded=password --dates=banned_at\n\n# Generate relationship methods\ntom make:model User --one-to-one=Passport `\n --one-to-many=Post --foreign-key=post_id `\n --one-to-many=Car\n\n# Generate a basic many-to-many relationship\ntom make:model User --belongs-to-many=Tag --with-timestamps\n\n# Generate a many-to-many relationship\ntom make:model User --belongs-to-many=Tag --foreign-key=tag_id `\n --pivot-table=user_tag --as=tagged `\n --with-pivot=active,soft --with-timestamps `\n --pivot=Tagged\n\n# Generate a pivot model\ntom make:model Tagged --pivot-model\ntom make:model Tagged --pivot-model --incrementing\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Writing a ",(0,i.jsx)(n.code,{children:"make:model"})," commands is superb with the ",(0,i.jsx)(n.a,{href:"/database/migrations#tab-completion",children:"tab completion"}),"."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"--path"})," and ",(0,i.jsx)(n.code,{children:"--realpath"})," options work the same as for the ",(0,i.jsx)(n.a,{href:"/database/migrations#generating-migrations",children:(0,i.jsx)(n.code,{children:"make:migration"})})," command."]})}),"\n",(0,i.jsx)(n.h2,{id:"tinyorm-model-conventions",children:"TinyORM Model Conventions"}),"\n",(0,i.jsx)(n.p,{children:"Let's examine a basic model class and discuss some of TinyORM's key conventions:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#pragma once\n#ifndef FLIGHT_HPP\n#define FLIGHT_HPP\n\n#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n\n using Model::Model;\n};\n\n#endif // FLIGHT_HPP\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/models/models/torrent.hpp#L43",children:(0,i.jsx)(n.code,{children:"Torrent"})})," example model that also acts as the full-fledged example model. It has defined and also nicely commented all possible features that model classes can use or define."]})}),"\n",(0,i.jsx)(n.h3,{id:"table-names",children:"Table Names"}),"\n",(0,i.jsxs)(n.p,{children:["After glancing at the example above, you may have noticed that we did not tell TinyORM which database table corresponds to our ",(0,i.jsx)(n.code,{children:"Flight"}),' model. By convention, the "snake_case", plural name of the class will be used as the table name unless another name is explicitly specified. So, in this case, TinyORM will assume the ',(0,i.jsx)(n.code,{children:"Flight"})," model stores records in the ",(0,i.jsx)(n.code,{children:"flights"})," table, while an ",(0,i.jsx)(n.code,{children:"AirTrafficController"})," model would store records in an ",(0,i.jsx)(n.code,{children:"air_traffic_controllers"})," table."]}),"\n",(0,i.jsxs)(n.p,{children:["If your model's corresponding database table does not fit this convention, you may manually specify the model's table name by defining the private ",(0,i.jsx)(n.code,{children:"u_table"})," data member on the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The table associated with the model. */\n QString u_table {"flights"};\n};\n'})}),"\n",(0,i.jsx)(n.h3,{id:"primary-keys",children:"Primary Keys"}),"\n",(0,i.jsxs)(n.p,{children:["TinyORM will also assume that each model's corresponding database table has a primary key column named ",(0,i.jsx)(n.code,{children:"id"}),". If necessary, you may define a private ",(0,i.jsx)(n.code,{children:"u_primaryKey"})," data member on your model to specify a different column that serves as your model's primary key:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The primary key associated with the table. */\n QString u_primaryKey {"id"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["In addition, TinyORM assumes that the primary key is an incrementing integer value. If you wish to use a non-incrementing or a non-numeric primary key you must define a private ",(0,i.jsx)(n.code,{children:"u_incrementing"})," data member on your model that is set to ",(0,i.jsx)(n.code,{children:"false"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! Indicates if the model's ID is auto-incrementing. */\n bool u_incrementing = false;\n};\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["Non-numeric primary keys are not currently implemented, ",(0,i.jsx)(n.code,{children:"u_incrementing"})," code logic is fully implemented, but it is only one part to make it fully work."]})}),"\n",(0,i.jsx)(n.h4,{id:"composite-primary-keys",children:'"Composite" Primary Keys'}),"\n",(0,i.jsx)(n.p,{children:'TinyORM requires each model to have at least one uniquely identifying "ID" that can serve as its primary key. "Composite" primary keys are not supported by TinyORM models. However, you are free to add additional multi-column unique indexes to your database tables, in addition to the table\'s uniquely identifying primary key.'}),"\n",(0,i.jsx)(n.h3,{id:"timestamps",children:"Timestamps"}),"\n",(0,i.jsxs)(n.p,{children:["By default, TinyORM expects ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," columns to exist on your model's corresponding database table. TinyORM will automatically set these column's values when models are created or updated. If you do not want these columns to be automatically managed by TinyORM, you should define a private ",(0,i.jsx)(n.code,{children:"u_timestamps"})," data member on your model with a value of ",(0,i.jsx)(n.code,{children:"false"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! Indicates if the model should be timestamped. */\n bool u_timestamps = false;\n};\n"})}),"\n",(0,i.jsx)(a.A,{id:"timestamps-u_dates"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"u_dates"})," static data member controls the casting of timestamp attributes. The ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," columns are automatically added to the ",(0,i.jsx)(n.code,{children:"u_dates"})," string list when the ",(0,i.jsx)(n.code,{children:"u_timestamps"})," is ",(0,i.jsx)(n.code,{children:"true"}),". Also, the ",(0,i.jsx)(n.a,{href:"#soft-deleting",children:(0,i.jsx)(n.code,{children:"Soft Deleting"})})," feature adds the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to the ",(0,i.jsx)(n.code,{children:"u_dates"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["You may add additional columns to the ",(0,i.jsx)(n.code,{children:"u_dates"})," list. After that, these columns will be automatically formatted using the format in the ",(0,i.jsx)(n.code,{children:"u_dateFormat"})," data member during the ",(0,i.jsx)(n.code,{children:"setAttribute"})," method call:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'class Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The attributes that should be mutated to dates. */\n inline static const QStringList u_dates {"departure_at"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If you need to customize the format of your model's timestamps, set the private ",(0,i.jsx)(n.code,{children:"u_dateFormat"})," data member on your model. This data member determines how date attributes are stored in the database, supported formats are described in the ",(0,i.jsx)(n.code,{children:"QDateTime"})," documentation:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The storage format of the model\'s date columns. */\n QString u_dateFormat {"yyyy-MM-dd HH:mm:ss"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If you need to customize the format of your model's time columns, set the private ",(0,i.jsx)(n.code,{children:"u_timeFormat"})," data member on your model. This data member determines how time attributes are stored in the database, supported formats are described in the ",(0,i.jsx)(n.code,{children:"QTime"})," documentation. The default value for ",(0,i.jsx)(n.code,{children:"u_timeFormat"})," is ",(0,i.jsx)(n.code,{children:"HH:mm:ss"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'/*! The storage format of the model\'s time columns. */\nQString u_timeFormat {"HH:mm:ss.zzz"};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The default value for datetime or timestamp columns is ",(0,i.jsx)(n.code,{children:"yyyy-MM-dd HH:mm:ss"})," and for time columns is ",(0,i.jsx)(n.code,{children:"HH:mm:ss"}),"."]}),"\n",(0,i.jsx)(n.h5,{id:"unix-timestamps",children:"Unix timestamps"}),"\n",(0,i.jsxs)(n.p,{children:["You can set the ",(0,i.jsx)(n.code,{children:"u_dateFormat"})," to ",(0,i.jsx)(n.code,{children:"U"})," if you want to store dates in the database as Unix timestamps:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"QString u_dateFormat {QLatin1Char('U')};\n"})}),"\n",(0,i.jsxs)(n.p,{children:["In this case ",(0,i.jsx)(n.strong,{children:"all"})," date attributes set in the ",(0,i.jsx)(n.code,{children:"u_dates"})," will be handled as Unix timestamps, so also the ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamp attributes."]}),"\n",(0,i.jsxs)(n.p,{children:["To create Unix timestamp columns using the ",(0,i.jsx)(n.a,{href:"/database/migrations",children:"tom migrations"})," you should use ",(0,i.jsx)(n.code,{children:"integer"})," types:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Schema::table("flights", [](Blueprint &table)\n{\n table.bigInteger("created_at").nullable();\n table.bigInteger("updated_at").nullable();\n});\n'})}),"\n",(0,i.jsx)(n.h5,{id:"custom-timestamp-column-names",children:"Custom timestamp column names"}),"\n",(0,i.jsxs)(n.p,{children:["If you need to customize the names of the columns used to store the timestamps, you may define ",(0,i.jsx)(n.code,{children:"CREATED_AT"})," and ",(0,i.jsx)(n.code,{children:"UPDATED_AT"})," private static getter methods on your model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The name of the "created at" column. */\n static QString CREATED_AT() { return QStringLiteral("creation_date"); }\n /*! The name of the "updated at" column. */\n static QString UPDATED_AT() { return QStringLiteral("updated_date"); }\n};\n'})}),"\n",(0,i.jsx)(n.h4,{id:"touching-timestamps",children:"Touching timestamps"}),"\n",(0,i.jsxs)(n.p,{children:["You can explicitly touch timestamps using the ",(0,i.jsx)(n.code,{children:"touch"})," method defined on the Model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::find(1);\n\nflight->touch();\nflight->touch("added_on"); // Custom column name\n'})}),"\n",(0,i.jsxs)(n.p,{children:["You can also touch multiple rows at once using the ",(0,i.jsx)(n.code,{children:"touch"})," method defined on the TinyBuilder:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto [affected, query] = Flight::whereEq("status", "new")->touch();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"touch"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'flight->history()->touch();\nflight->history()->whereEq("status", "new").touch();\n'})}),"\n",(0,i.jsx)(n.h3,{id:"database-connections",children:"Database Connections"}),"\n",(0,i.jsxs)(n.p,{children:["By default, all TinyORM models will use the default database connection that is configured for your application. If you would like to specify a different connection that should be used when interacting with a particular model, you should define a ",(0,i.jsx)(n.code,{children:"u_connection"})," private data member on the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The database connection that should be used by the model. */\n QString u_connection {"sqlite"};\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["In special cases, when you want to query the database through a different connection, you can use ",(0,i.jsx)(n.code,{children:"Model::on"})," method, which takes the connection name as the first argument:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto user = User::on("sqlite")->find(1);\n'})}),"\n",(0,i.jsx)(n.h2,{id:"default-attribute-values",children:"Default Attribute Values"}),"\n",(0,i.jsxs)(n.p,{children:["By default, a newly instantiated model instance will not contain any attribute values. If you would like to define the default values for some of your model's attributes, you may define an ",(0,i.jsx)(n.code,{children:"u_attributes"})," data member on your model, it has to be ",(0,i.jsx)(n.strong,{children:"static"})," and can be ",(0,i.jsx)(n.strong,{children:"const"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\n#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The model\'s default values for attributes. */\n inline static const QVector u_attributes {\n {"delayed", false},\n {"progress", 0},\n {"added_on", QDateTime::currentDateTimeUtc()},\n };\n};\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["Use the ",(0,i.jsx)(n.code,{children:"Model::instance"})," or ",(0,i.jsx)(n.code,{children:"Model::instanceHeap"})," related methods to instantiate a model that contains a ",(0,i.jsx)(n.code,{children:"QDateTime"})," in Default Attribute Values, or if attributes you want to pass to the model's constructor contain a ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance ",(0,i.jsx)("small",{children:"(problem is described below)"}),"."]})}),"\n",(0,i.jsx)(n.h5,{id:"qdatetime-and-connection-name-problem",children:"QDateTime and connection name problem"}),"\n",(0,i.jsxs)(n.p,{children:["If your Default Attribute Values or attributes that you can pass to the ",(0,i.jsx)(n.code,{children:"Model"})," constructor contain the ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance, then ",(0,i.jsx)(n.code,{children:"TinyORM"})," throws an exception. You have to use the ",(0,i.jsx)(n.code,{children:"Model::instance"})," related methods to create such a Model."]}),"\n",(0,i.jsxs)(n.p,{children:["Virtually everything important is covered in the thrown exception, but let me summarize it. The problem is that the ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance is converted to a string based on the ",(0,i.jsx)(n.code,{children:"Model::u_dateFormat"}),", or if not defined, the date format from ",(0,i.jsx)(n.code,{children:"Orm::Query::Grammars::Grammar"})," will be used. This ",(0,i.jsx)(n.code,{children:"QueryGrammar"})," is obtained from ",(0,i.jsx)(n.code,{children:"Orm::DatabaseConnection"})," and because of that TinyORM needs to know the ",(0,i.jsx)(n.strong,{children:"connection name"})," and that's the crux of this problem. You can define your connection name using the ",(0,i.jsx)(n.code,{children:"Model::u_connection"})," in your derived model class, but this derived model ",(0,i.jsx)(n.strong,{children:"is not yet initialized"}),", so the ",(0,i.jsx)(n.code,{children:"Model::u_connection"})," is also not initialized."]}),"\n",(0,i.jsxs)(n.p,{children:["So if the ",(0,i.jsx)(n.code,{children:"Model::u_connection"})," is not yet initialized, ",(0,i.jsx)(n.code,{children:"TinyORM"})," can't obtain the ",(0,i.jsx)(n.code,{children:"Orm::DatabaseConnection"})," -> ",(0,i.jsx)(n.code,{children:"QueryGrammar"})," -> ",(0,i.jsx)(n.code,{children:"dateFormat"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"retrieving-models",children:"Retrieving Models"}),"\n",(0,i.jsxs)(n.p,{children:["Once you have created a model and its associated database table, you are ready to start retrieving data from your database. You can think of each TinyORM model as a powerful ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"})," allowing you to fluently query the database table associated with the model. The model's ",(0,i.jsx)(n.code,{children:"all"})," method will retrieve all of the records from the model's associated database table:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\n#include "models/flight.hpp"\n\nfor (const auto &flight : Flight::all())\n qDebug() << flight["name"].toString();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"building-queries",children:"Building Queries"}),"\n",(0,i.jsxs)(n.p,{children:["The TinyORM ",(0,i.jsx)(n.code,{children:"all"})," method will return all of the results in the model's table. However, since each TinyORM model serves as a ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"}),", you may add additional constraints to queries and then invoke the ",(0,i.jsx)(n.code,{children:"get"})," method to retrieve the results:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::whereEq("active", 1)\n ->orderBy("name")\n .take(10)\n .get();\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Since TinyORM models are query builders, you should review all of the methods provided by TinyORM's ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"}),". You may use any of these methods when writing your TinyORM queries."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["All the static methods defined on the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Model"})," class, which start building queries like ",(0,i.jsx)(n.code,{children:"where"}),", ",(0,i.jsx)(n.code,{children:"latest"}),", ",(0,i.jsx)(n.code,{children:"oldest"}),", ",(0,i.jsx)(n.code,{children:"with"}),", ... return ",(0,i.jsx)(n.code,{children:"std::unique_ptr>"}),", ",(0,i.jsx)(n.code,{children:"TinyBuilder = Orm::Tiny::Builder"})," and ",(0,i.jsx)(n.code,{children:"Model"})," template argument is queried model class."]})}),"\n",(0,i.jsx)(n.h4,{id:"refreshing-models",children:"Refreshing Models"}),"\n",(0,i.jsxs)(n.p,{children:['If you already have an instance of the TinyORM model that was retrieved from the database, you can "refresh" the model using the ',(0,i.jsx)(n.code,{children:"fresh"})," and ",(0,i.jsx)(n.code,{children:"refresh"})," methods. The ",(0,i.jsx)(n.code,{children:"fresh"})," method will re-retrieve the model from the database. The existing model instance will not be affected:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::whereEq("number", "FR 900")->first();\n\nauto freshFlight = flight->fresh();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"refresh"})," method will re-hydrate the existing model using fresh data from the database. In addition, all of its loaded relationships will be refreshed as well:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::whereEq("number", "FR 900")->first();\n\nflight->setAttribute("number", "FR 456");\n\nflight->refresh();\n\nflight->getAttribute("number"); // "FR 900"\n'})}),"\n",(0,i.jsx)(n.h3,{id:"containers",children:"Containers"}),"\n",(0,i.jsxs)(n.p,{children:["As we have seen, TinyORM methods like ",(0,i.jsx)(n.code,{children:"all"})," and ",(0,i.jsx)(n.code,{children:"get"})," retrieve multiple records from the database. Since these methods return a ",(0,i.jsx)(n.code,{children:"QVector"}),", you can iterate it like any other container with the ",(0,i.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/language/range-for",children:"Range-based for loop"}),", ",(0,i.jsx)(n.a,{href:"https://doc.qt.io/qt/containers.html#stl-style-iterators",children:"STL-Style Iterators"}),", ",(0,i.jsx)(n.a,{href:"https://doc.qt.io/qt/containers.html#java-style-iterators",children:"Java-Style Iterators"})," or ",(0,i.jsx)(n.a,{href:"https://www.walletfox.com/course/quickref_range_v3.php",children:"Ranges"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\n#include "models/flight.hpp"\n\nfor (const auto &flight : Flight::all())\n qDebug() << flight["name"].toString();\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["An ",(0,i.jsx)(n.code,{children:"all"})," method is defined on the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Model"})," class and ",(0,i.jsx)(n.code,{children:"get"})," method is defined on the ",(0,i.jsx)(n.code,{children:"Orm::Tiny::Builder"}),", may be also referred as ",(0,i.jsx)(n.code,{children:"TinyBuilder"}),", and on the ",(0,i.jsx)(n.code,{children:"Orm::Query::Builder"})," alias ",(0,i.jsx)(n.code,{children:"QueryBuilder"}),"."]})}),"\n",(0,i.jsx)(n.h3,{id:"chunking-results",children:"Chunking Results"}),"\n",(0,i.jsxs)(n.p,{children:["Your application may run out of memory if you attempt to load tens of thousands of TinyORM records via the ",(0,i.jsx)(n.code,{children:"all"})," or ",(0,i.jsx)(n.code,{children:"get"})," methods. Instead of using these methods, the ",(0,i.jsx)(n.code,{children:"chunk"})," method may be used to process large numbers of models more efficiently."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"chunk"})," method will retrieve a subset of TinyORM models, passing them to a lambda expression for processing. Since only the current chunk of TinyORM models is retrieved at a time, the ",(0,i.jsx)(n.code,{children:"chunk"})," method will provide significantly reduced memory usage when working with a large number of models:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"Flight::chunk(200, [](QVector &&flights, const int /*unused*/)\n{\n for (auto &&flight : flights) {\n //\n }\n\n return true;\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The first argument passed to the ",(0,i.jsx)(n.code,{children:"chunk"}),' method is the number of records you wish to receive per "chunk". The lambda expression passed as the second argument will be invoked for each chunk that is retrieved from the database. A database query will be executed to retrieve each chunk of records passed to the lambda expression.']}),"\n",(0,i.jsxs)(n.p,{children:["If you are filtering the results of the ",(0,i.jsx)(n.code,{children:"chunk"})," method based on a column that you will also be updating while iterating over the results, you should use the ",(0,i.jsx)(n.code,{children:"chunkById"})," method. Using the ",(0,i.jsx)(n.code,{children:"chunk"})," method in these scenarios could lead to unexpected and inconsistent results. Internally, the ",(0,i.jsx)(n.code,{children:"chunkById"})," method will always retrieve models with an ",(0,i.jsx)(n.code,{children:"id"})," column greater than the last model in the previous chunk:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::whereEq("departed", true)\n ->chunkById(200, [](QVector &&flights, const int /*unused*/)\n {\n for (auto &&flight : flights)\n flight.update({{"departed", false}});\n\n return true;\n });\n'})}),"\n",(0,i.jsx)(n.h3,{id:"advanced-subqueries",children:"Advanced Subqueries"}),"\n",(0,i.jsx)(n.h4,{id:"subquery-selects",children:"Subquery Selects"}),"\n",(0,i.jsxs)(n.p,{children:["TinyORM also offers advanced subquery support, which allows you to pull information from related tables in a single query. For example, let's imagine that we have a table of flight ",(0,i.jsx)(n.code,{children:"destinations"})," and a table of ",(0,i.jsx)(n.code,{children:"flights"})," to destinations. The ",(0,i.jsx)(n.code,{children:"flights"})," table contains an ",(0,i.jsx)(n.code,{children:"arrived_at"})," column which indicates when the flight arrived at the destination."]}),"\n",(0,i.jsxs)(n.p,{children:["Using the subquery functionality available to the query builder's ",(0,i.jsx)(n.code,{children:"select"})," and ",(0,i.jsx)(n.code,{children:"addSelect"})," methods, we can select all of the ",(0,i.jsx)(n.code,{children:"destinations"})," and the name of the flight that most recently arrived at that destination using a single query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/destination.hpp"\n#include "models/flight.hpp"\n\nreturn Destination::addSelect(\n Flight::select("name")\n ->whereColumnEq("destination_id", "destinations.id")\n .orderByDesc("arrived_at")\n .limit(1)\n .toBase(),\n "last_flight")\n ->get();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"subquery-ordering",children:"Subquery Ordering"}),"\n",(0,i.jsxs)(n.p,{children:["In addition, the query builder's ",(0,i.jsx)(n.code,{children:"orderBy"})," function supports subqueries. Continuing to use our flight example, we may use this functionality to sort all destinations based on when the last flight arrived at that destination. Again, this may be done while executing a single database query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'return Destination::orderByDesc(\n Flight::select("arrived_at")\n ->whereColumnEq("destination_id", "destinations.id")\n .orderByDesc("arrived_at")\n .limit(1)\n .toBase())\n ->get();\n'})}),"\n",(0,i.jsx)(n.h2,{id:"retrieving-single-models-and-aggregates",children:"Retrieving Single Models / Aggregates"}),"\n",(0,i.jsxs)(n.p,{children:["In addition to retrieving all of the records matching a given query, you may also retrieve single records using the ",(0,i.jsx)(n.code,{children:"find"}),", ",(0,i.jsx)(n.code,{children:"first"}),", ",(0,i.jsx)(n.code,{children:"firstWhere"}),", or ",(0,i.jsx)(n.code,{children:"firstWhereEq"})," methods. Instead of returning a vector of models, these methods return a single model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\n// Retrieve a model by its primary key...\nauto flight = Flight::find(1);\n\n// Retrieve the first model matching the query constraints...\nauto flight = Flight::whereEq("active", 1)->first();\n\n// Alternative to retrieving the first model matching the query constraints...\nauto flight = Flight::firstWhere("active", "=", 1);\n\n// Alternative firstWhere method syntax\nauto flight = Flight::firstWhereEq("active", 1);\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes you may wish to perform some other action if no results are found. The ",(0,i.jsx)(n.code,{children:"findOr"})," methods will return a single model instance or, if no results are found, execute the given lambda expression. The value returned by the lambda will be considered the result of the method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"auto flight = Flight::findOr(1, [] {\n // ...\n});\n\nauto flight = Flight::findOr(1, [] {\n // ...\n return 10;\n});\n\nauto flight = Flight::findOr>(1, [] {\n // ...\n return Flight::find(10);\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["To obtain only a subset of the model's attributes you may use the ",(0,i.jsx)(n.code,{children:"Model::only"})," method, it returns the ",(0,i.jsx)(n.code,{children:"QVector"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nusing Orm::Constants::ID;\nusing Orm::Constants::NAME;\n\nauto flight = Flight::find(1);\n\nauto attributes = flight->only({ID, NAME});\n'})}),"\n",(0,i.jsx)(n.h4,{id:"not-found-exceptions",children:"Not Found Exceptions"}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes you may wish to throw an exception if a model is not found. The ",(0,i.jsx)(n.code,{children:"findOrFail"})," and ",(0,i.jsx)(n.code,{children:"firstOrFail"})," methods will retrieve the first result of the query; however, if no result is found, an ",(0,i.jsx)(n.code,{children:"Orm::Tiny::ModelNotFoundError"})," will be thrown:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::findOrFail(1);\n\nauto flight = Flight::where("legs", ">", 3)->firstOrFail();\n'})}),"\n",(0,i.jsx)(n.h3,{id:"retrieving-or-creating-models",children:"Retrieving Or Creating Models"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"firstOrCreate"})," method will attempt to locate a database record using the given column / value pairs. If the model can not be found in the database, a record will be inserted with the attributes resulting from merging the first ",(0,i.jsx)(n.code,{children:"QVector"})," argument with the optional second ",(0,i.jsx)(n.code,{children:"QVector"})," argument:"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"firstOrNew"})," method, like ",(0,i.jsx)(n.code,{children:"firstOrCreate"}),", will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by ",(0,i.jsx)(n.code,{children:"firstOrNew"})," has not yet been persisted to the database. You will need to manually call the ",(0,i.jsx)(n.code,{children:"save"})," method to persist it:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\n// Retrieve flight by name or create it if it doesn\'t exist...\nauto flight = Flight::firstOrCreate({\n {"name", "London to Paris"}\n});\n\n// Retrieve flight by name or create it with the name, delayed, and arrival_time attributes...\nauto flight = Flight::firstOrCreate(\n {{"name", "London to Paris"}},\n {{"delayed", 1}, {"arrival_time", "11:30"}}\n);\n\n// Retrieve flight by name or instantiate a new Flight instance...\nauto flight = Flight::firstOrNew({\n {"name", "London to Paris"}\n});\n\n// Retrieve flight by name or instantiate with the name, delayed, and arrival_time attributes...\nauto flight = Flight::firstOrNew(\n {{"name", "Tokyo to Sydney"}},\n {{"delayed", 1}, {"arrival_time", "11:30"}}\n);\n'})}),"\n",(0,i.jsx)(n.h3,{id:"retrieving-aggregates",children:"Retrieving Aggregates"}),"\n",(0,i.jsxs)(n.p,{children:["When interacting with TinyORM models, you may also use the ",(0,i.jsx)(n.code,{children:"count"}),", ",(0,i.jsx)(n.code,{children:"sum"}),", ",(0,i.jsx)(n.code,{children:"max"}),", and other ",(0,i.jsx)(n.a,{href:"/database/query-builder#aggregates",children:"aggregate methods"})," provided by the ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"}),". As you might expect, these methods return a scalar value instead of a TinyORM model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto count = Flight::whereEq("active", 1)->count();\n\nauto max = Flight::whereEq("active", 1)->max("price");\n'})}),"\n",(0,i.jsx)(n.h2,{id:"inserting-and-updating-models",children:"Inserting & Updating Models"}),"\n",(0,i.jsx)(n.h3,{id:"inserts",children:"Inserts"}),"\n",(0,i.jsxs)(n.p,{children:["Of course, when using TinyORM, we don't only need to retrieve models from the database. We also need to insert new records. Thankfully, TinyORM makes it simple. To insert a new record into the database, you should instantiate a new model instance and set attributes on the model. Then, call the ",(0,i.jsx)(n.code,{children:"save"})," method on the model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\n// Store a new flight in the database\nFlight flight;\nflight.setAttribute("name", "Slovakia to Czech");\nflight.save();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["In this example, we assign the ",(0,i.jsx)(n.code,{children:"name"})," attribute of the ",(0,i.jsx)(n.code,{children:"Flight"})," model instance. When we call the ",(0,i.jsx)(n.code,{children:"save"})," method, a record will be inserted into the database. The model's ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamps will automatically be set when the ",(0,i.jsx)(n.code,{children:"save"})," method is called, so there is no need to set them manually."]}),"\n",(0,i.jsxs)(n.p,{children:["Alternatively, you may use the ",(0,i.jsx)(n.code,{children:"create"}),' method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the ',(0,i.jsx)(n.code,{children:"create"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::create({\n {"name", "London to Paris"},\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["However, before using the ",(0,i.jsx)(n.code,{children:"create"})," method, you will need to specify either a ",(0,i.jsx)(n.code,{children:"u_fillable"})," or ",(0,i.jsx)(n.code,{children:"u_guarded"})," static data member on your model class. These static data members are required because all TinyORM models are protected against mass assignment vulnerabilities by default. To learn more about mass assignment, please consult the ",(0,i.jsx)(n.a,{href:"#mass-assignment",children:"mass assignment documentation"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"updates",children:"Updates"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"save"})," method may also be used to update models that already exist in the database. To update a model, you should retrieve it and set any attributes you wish to update. Then, you should call the model's ",(0,i.jsx)(n.code,{children:"save"})," method. Again, the ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamp will automatically be updated, so there is no need to manually set its value:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::find(1);\n\nflight->setAttribute("name", "Paris to London");\n\nflight->save();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"mass-updates",children:"Mass Updates"}),"\n",(0,i.jsxs)(n.p,{children:["Updates can also be performed against models that match a given query. In this example, all flights that are ",(0,i.jsx)(n.code,{children:"active"})," and have a ",(0,i.jsx)(n.code,{children:"destination"})," of ",(0,i.jsx)(n.code,{children:"San Diego"})," will be marked as delayed:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::whereEq("active", 1)\n ->whereEq("destination", "San Diego")\n .update({{"delayed", 1}});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"update"})," method expects the ",(0,i.jsx)(n.code,{children:"QVector"})," of column and value pairs representing the columns that should be updated."]}),"\n",(0,i.jsx)(n.h4,{id:"examining-attribute-changes",children:"Examining Attribute Changes"}),"\n",(0,i.jsxs)(n.p,{children:["TinyORM provides the ",(0,i.jsx)(n.code,{children:"isDirty"}),", ",(0,i.jsx)(n.code,{children:"isClean"}),", and ",(0,i.jsx)(n.code,{children:"wasChanged"})," methods to examine the internal state of your model and determine how its attributes have changed from when the model was originally retrieved."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"isDirty"})," method determines if any of the model's attributes have been changed since the model was retrieved. You may pass a specific attribute name to the ",(0,i.jsx)(n.code,{children:"isDirty"})," method to determine if a particular attribute is dirty. The ",(0,i.jsx)(n.code,{children:"isClean"})," will determine if an attribute has remained unchanged since the model was retrieved. This method also accepts an optional attribute argument:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nauto user = User::create({\n {"first_name", "Silver"},\n {"last_name", "Zachara"},\n {"title", "Developer"},\n});\n\nuser.setAttribute("title", "Painter");\n\nuser.isDirty(); // true\nuser.isDirty("title"); // true\nuser.isDirty("first_name"); // false\n\nuser.isClean(); // false\nuser.isClean("title"); // false\nuser.isClean("first_name"); // true\n\nuser.save();\n\nuser.isDirty(); // false\nuser.isClean(); // true\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"wasChanged"})," method determines if any attributes were changed after the model was last saved into the database. If needed, you may pass an attribute name to see if a particular attribute was changed:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto user = User::create({\n {"first_name", "Silver"},\n {"last_name", "Zachara"},\n {"title", "Developer"},\n});\n\nuser.setAttribute("title", "Painter");\n\nuser.wasChanged(); // false\n\nuser.save();\n\nuser.wasChanged(); // true\nuser.wasChanged("title"); // true\nuser.wasChanged("first_name"); // false\n'})}),"\n",(0,i.jsx)(n.h3,{id:"mass-assignment",children:"Mass Assignment"}),"\n",(0,i.jsxs)(n.p,{children:["You may use the ",(0,i.jsx)(n.code,{children:"create"}),' method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the method:']}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::create({\n {"name", "London to Paris"},\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["However, before using the ",(0,i.jsx)(n.code,{children:"create"})," method, you will need to specify either a ",(0,i.jsx)(n.code,{children:"u_fillable"})," or ",(0,i.jsx)(n.code,{children:"u_guarded"})," static data member on your model class. These data members are required because all TinyORM models are protected against mass assignment vulnerabilities by default."]}),"\n",(0,i.jsxs)(n.p,{children:["A mass assignment vulnerability occurs when a user passes an unexpected HTTP request field and that field changes a column in your database that you did not expect. For example, a malicious user might send an ",(0,i.jsx)(n.code,{children:"is_admin"})," parameter through an HTTP request, which is then passed to your model's ",(0,i.jsx)(n.code,{children:"create"})," method, allowing the user to escalate themselves to an administrator."]}),"\n",(0,i.jsxs)(n.p,{children:["So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the ",(0,i.jsx)(n.code,{children:"u_fillable"})," static data member on the model. For example, let's make the ",(0,i.jsx)(n.code,{children:"name"})," attribute of our ",(0,i.jsx)(n.code,{children:"Flight"})," model mass assignable:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n\n using Model::Model;\n\n /*! The attributes that are mass assignable. */\n inline static QStringList u_fillable {\n "name",\n };\n};\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Once you have specified which attributes are mass assignable, you may use the ",(0,i.jsx)(n.code,{children:"create"})," method to insert a new record in the database. The ",(0,i.jsx)(n.code,{children:"create"})," method returns the newly created model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::create({{"name", "London to Paris"}});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If you already have a model instance, you may use the ",(0,i.jsx)(n.code,{children:"fill"})," method to populate it with the vector of attributes:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'flight.fill({{"name", "Amsterdam to Frankfurt"}});\n'})}),"\n",(0,i.jsx)(n.h4,{id:"allowing-mass-assignment",children:"Allowing Mass Assignment"}),"\n",(0,i.jsxs)(n.p,{children:["If you would like to make all of your attributes mass assignable, you may define your model's ",(0,i.jsx)(n.code,{children:"u_guarded"})," static data member as an empty vector. If you choose to unguard your model, you should take special care to always hand-craft the vectors passed to TinyORM's ",(0,i.jsx)(n.code,{children:"fill"}),", ",(0,i.jsx)(n.code,{children:"create"}),", and ",(0,i.jsx)(n.code,{children:"update"})," methods:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#include \n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model\n{\n friend Model;\n\n using Model::Model;\n\n /*! The attributes that aren't mass assignable. */\n inline static QStringList u_guarded {};\n};\n"})}),"\n",(0,i.jsx)(n.h3,{id:"upserts",children:"Upserts"}),"\n",(0,i.jsx)(n.p,{children:"Occasionally, you may need to update an existing model or create a new model if no matching model exists."}),"\n",(0,i.jsxs)(n.p,{children:["In the example below, if a flight exists with a ",(0,i.jsx)(n.code,{children:"departure"})," location of ",(0,i.jsx)(n.code,{children:"Oakland"})," and a ",(0,i.jsx)(n.code,{children:"destination"})," location of ",(0,i.jsx)(n.code,{children:"San Diego"}),", its ",(0,i.jsx)(n.code,{children:"price"})," and ",(0,i.jsx)(n.code,{children:"discounted"})," columns will be updated. If no such flight exists, a new flight will be created which has the attributes resulting from merging the first argument vector with the second argument vector:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::updateOrCreate(\n {{"departure", "Oakland"}, {"destination", "San Diego"}},\n {{"price", 99}, {"discounted", 1}}\n);\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"firstOrCreate"})," and ",(0,i.jsx)(n.code,{children:"updateOrCreate"})," methods persist the model, so there's no need to manually call the ",(0,i.jsx)(n.code,{children:"save"})," method."]})}),"\n",(0,i.jsxs)(n.p,{children:['If you would like to perform multiple "upserts" in a single query, then you should use the ',(0,i.jsx)(n.code,{children:"upsert"})," method instead. The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table. The method's third and final argument is the vector of the columns that should be updated if a matching record already exists in the database. The ",(0,i.jsx)(n.code,{children:"upsert"})," method will automatically set the ",(0,i.jsx)(n.code,{children:"created_at"})," and ",(0,i.jsx)(n.code,{children:"updated_at"})," timestamps if timestamps are enabled on the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::upsert(\n {{{"departure", "Oakland"}, {"destination", "San Diego"}, {"price", 99}},\n {{"departure", "Chicago"}, {"destination", "New York"}, {"price", 150}}},\n {"departure", "destination"},\n {"price"}\n);\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["All databases except SQL Server require the columns in the second argument of the ",(0,i.jsx)(n.code,{children:"upsert"}),' method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the ',(0,i.jsx)(n.code,{children:"upsert"}),' method and always uses the "primary" and "unique" indexes of the table to detect existing records.']})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["Row and column aliases will be used with the MySQL server >=8.0.19 instead of the VALUES() function as is described in the MySQL ",(0,i.jsx)(n.a,{href:"https://dev.mysql.com/doc/refman/8.4/en/insert-on-duplicate.html",children:"documentation"}),". The MySQL server version is auto-detected and can be overridden in the ",(0,i.jsx)(n.a,{href:"/database/getting-started#configuration",children:"configuration"}),"."]})}),"\n",(0,i.jsx)(n.h2,{id:"deleting-models",children:"Deleting Models"}),"\n",(0,i.jsxs)(n.p,{children:["To delete a model, you may call the ",(0,i.jsx)(n.code,{children:"remove"}),", or an alias ",(0,i.jsx)(n.code,{children:"deleteRow"})," method on the model instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include "models/flight.hpp"\n\nauto flight = Flight::find(1);\n\nflight->remove();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"deleting-an-existing-model-by-its-primary-key",children:"Deleting An Existing Model By Its Primary Key"}),"\n",(0,i.jsxs)(n.p,{children:["In the example above, we are retrieving the model from the database before calling the ",(0,i.jsx)(n.code,{children:"remove"})," method. However, if you know the primary key of the model, you may delete the model without explicitly retrieving it by calling the ",(0,i.jsx)(n.code,{children:"destroy"})," method. In addition to accepting the single primary key, the ",(0,i.jsx)(n.code,{children:"destroy"})," method can accept multiple primary keys:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"Flight::destroy(1);\n\nFlight::destroy({1, 2, 3});\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"destroy"})," method loads models from the database and calls the ",(0,i.jsx)(n.code,{children:"remove"})," method on each model individually, the reason for this is future compatibility with events."]})}),"\n",(0,i.jsx)(n.h4,{id:"deleting-models-using-queries",children:"Deleting Models Using Queries"}),"\n",(0,i.jsx)(n.p,{children:"Of course, you may build the query to delete all models matching your query's criteria. In this example, we will delete all flights that are marked as inactive:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto deletedRows = Flight::whereEq("active", 0)->remove();\n'})}),"\n",(0,i.jsx)(n.h3,{id:"soft-deleting",children:"Soft Deleting"}),"\n",(0,i.jsxs)(n.p,{children:['In addition to actually removing records from your database, TinyORM can also "soft delete" models. When models are soft deleted, they are not actually removed from your database. Instead, a ',(0,i.jsx)(n.code,{children:"deleted_at"}),' attribute is set on the model indicating the date and time at which the model was "deleted". To enable soft deletes for a model, add the ',(0,i.jsx)(n.code,{children:"Orm::Tiny::SoftDeletes"})," base class to the model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include \n#include \n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::SoftDeletes;\n\nclass Flight final : public Model,\n public SoftDeletes\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The table associated with the model. */\n QString u_table {"flights"};\n};\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"SoftDeletes"})," base class will automatically cast the ",(0,i.jsx)(n.code,{children:"deleted_at"})," attribute to the ",(0,i.jsx)(n.code,{children:"QDateTime"})," instance for you (it adds the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to the model's ",(0,i.jsx)(n.a,{href:"#timestamps-u_dates",children:(0,i.jsx)(n.code,{children:"u_dates"})})," list)."]})}),"\n",(0,i.jsxs)(n.p,{children:["You should also add the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to your database table. The TinyORM ",(0,i.jsx)(n.a,{href:"/database/migrations",children:"schema builder"})," contains a helper method to create this column:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Schema::table("flights", [](Blueprint &table)\n{\n table.softDeletes();\n});\n\nSchema::table("flights", [](Blueprint &table)\n{\n table.dropSoftDeletes();\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Now, when you call the ",(0,i.jsx)(n.code,{children:"remove"})," or ",(0,i.jsx)(n.code,{children:"deleteModel"})," method on the model, the ",(0,i.jsx)(n.code,{children:"deleted_at"})," column will be set to the current date and time. However, the model's database record will be left in the table. When querying a model that uses soft deletes, the soft deleted models will automatically be excluded from all query results."]}),"\n",(0,i.jsxs)(n.p,{children:["To determine if a given model instance has been soft deleted, you may use the ",(0,i.jsx)(n.code,{children:"trashed"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"if (flight->trashed()) {\n //\n}\n"})}),"\n",(0,i.jsx)(n.h4,{id:"restoring-soft-deleted-models",children:"Restoring Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:['Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model, you may call the ',(0,i.jsx)(n.code,{children:"restore"})," method on a model instance. The ",(0,i.jsx)(n.code,{children:"restore"})," method will set the model's ",(0,i.jsx)(n.code,{children:"deleted_at"})," column to ",(0,i.jsx)(n.code,{children:"null"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->restore();\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You may also use the ",(0,i.jsx)(n.code,{children:"restore"})," method in a query to restore multiple models:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'Flight::withTrashed()\n ->whereEq("airline_id", 1)\n .restore();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"restore"})," method may also be used when building ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," queries:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->restore();\n"})}),"\n",(0,i.jsx)(n.h4,{id:"permanently-deleting-models",children:"Permanently Deleting Models"}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes you may need to truly remove a model from your database. You may use the ",(0,i.jsx)(n.code,{children:"forceDelete"})," method (or it's alias ",(0,i.jsx)(n.code,{children:"forceRemove"}),") to permanently remove a soft deleted model from the database table:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->forceDelete();\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You may also use the ",(0,i.jsx)(n.code,{children:"forceDelete"})," method when building TinyORM relationship queries:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->forceDelete();\n"})}),"\n",(0,i.jsx)(n.h3,{id:"querying-soft-deleted-models",children:"Querying Soft Deleted Models"}),"\n",(0,i.jsx)(n.h4,{id:"including-soft-deleted-models",children:"Including Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:["As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be included in a query's results by calling the ",(0,i.jsx)(n.code,{children:"withTrashed"})," method on the query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::withTrashed()\n ->whereEq("account_id", 1)\n .get();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"withTrashed"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->withTrashed().get();\n"})}),"\n",(0,i.jsx)(n.h4,{id:"retrieving-only-soft-deleted-models",children:"Retrieving Only Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"onlyTrashed"})," method will retrieve ",(0,i.jsx)(n.strong,{children:"only"})," soft deleted models:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::onlyTrashed()\n ->whereEq("airline_id", 1)\n .get();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"onlyTrashed"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->onlyTrashed().get();\n"})}),"\n",(0,i.jsx)(n.h4,{id:"excluding-soft-deleted-models",children:"Excluding Soft Deleted Models"}),"\n",(0,i.jsxs)(n.p,{children:["As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be ",(0,i.jsx)(n.strong,{children:"excluded"})," in a query's results by calling the ",(0,i.jsx)(n.code,{children:"withoutTrashed"})," method on the query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flights = Flight::withoutTrashed()\n ->whereEq("account_id", 1)\n .get();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"withoutTrashed"})," method may also be called when building a ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationship"})," query:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"flight->history()->withoutTrashed().get();\n"})}),"\n",(0,i.jsx)(n.h3,{id:"truncate-table",children:"Truncate Table"}),"\n",(0,i.jsxs)(n.p,{children:["You may call the ",(0,i.jsx)(n.code,{children:"truncate"})," method to delete all of the model's associated database records. The ",(0,i.jsx)(n.code,{children:"truncate"})," operation will also reset any auto-incrementing IDs on the model's associated table:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"Flight::truncate();\n"})}),"\n",(0,i.jsx)(n.h2,{id:"replicating-models",children:"Replicating Models"}),"\n",(0,i.jsxs)(n.p,{children:["You may create an unsaved copy of an existing model instance using the ",(0,i.jsx)(n.code,{children:"replicate"})," method. This method is particularly useful when you have model instances that share many of the same attributes:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto shipping = Address::create({\n {"type", "shipping"},\n {"line_1", "123 Example Street"},\n {"city", "Victorville"},\n {"state", "CA"},\n {"postcode", "90001"},\n});\n\nauto billing = shipping.replicate();\n\nbilling.fill({\n {"type", "billing"},\n});\n\nbilling.save();\n'})}),"\n",(0,i.jsxs)(n.p,{children:["To exclude one or more attributes from being replicated to the new model, you may pass an unordered_set to the ",(0,i.jsx)(n.code,{children:"replicate"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'auto flight = Flight::create({\n {"destination", "LAX"},\n {"origin", "LHR"},\n {"last_flown", "2020-03-04 11:00:00"},\n {"last_pilot_id", 747},\n});\n\nflight = flight.replicate({\n "last_flown",\n "last_pilot_id",\n});\n'})}),"\n",(0,i.jsx)(n.h2,{id:"comparing-models",children:"Comparing Models"}),"\n",(0,i.jsxs)(n.p,{children:['Sometimes you may need to determine if two models are the "same" or not. The ',(0,i.jsx)(n.code,{children:"is"})," and ",(0,i.jsx)(n.code,{children:"isNot"})," methods may be used to quickly verify two models have the same primary key, table, and database connection or not:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"if (post->is(anotherPost)) {\n //\n}\n\nif (post->isNot(anotherPost)) {\n //\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"is"})," and ",(0,i.jsx)(n.code,{children:"isNot"})," methods are also available when using the ",(0,i.jsx)(n.code,{children:"belongsTo"})," and ",(0,i.jsx)(n.code,{children:"hasOne"})," ",(0,i.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationships"}),". This method is particularly helpful when you would like to compare a related model without issuing a query to retrieve that model:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"if (post->author()->is(user)) {\n //\n}\n"})}),"\n",(0,i.jsx)(n.h5,{id:"equality-comparison",children:"Equality comparison"}),"\n",(0,i.jsxs)(n.p,{children:["The base ",(0,i.jsx)(n.code,{children:"Model"})," class also defines the ",(0,i.jsx)(n.code,{children:"operator=="})," that allows precisely comparing two models. It compares the content of all the model's data members, from all base classes to the most derived model class. The ",(0,i.jsx)(n.code,{children:"model1 == model2"})," expression guarantees that these two models are exactly the same."]}),"\n",(0,i.jsxs)(n.p,{children:["It would be appropriate to mention that this comparison also includes relations, which means it will also compare ",(0,i.jsx)(n.strong,{children:"all"})," models (including their data members) these relations contain."]})]})}function m(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>d});var i=t(6540);const s={},a=i.createContext(s);function l(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:l(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/62a1276f.40d6303a.js b/assets/js/62a1276f.5965aaeb.js similarity index 99% rename from assets/js/62a1276f.40d6303a.js rename to assets/js/62a1276f.5965aaeb.js index c6948ac78..3545c6055 100644 --- a/assets/js/62a1276f.40d6303a.js +++ b/assets/js/62a1276f.5965aaeb.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[304],{2403:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var s=n(4848),i=n(8453);const a={sidebar_position:3,sidebar_label:"Casts",description:"Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a `datetime` string that is stored in your database to the `QDateTime` instance when it is accessed via your TinyORM model.",keywords:["c++ orm","orm","casts","casting","attributes","tinyorm"]},r="TinyORM: Casting",o={id:"tinyorm/casts",title:"TinyORM: Casting",description:"Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a `datetime` string that is stored in your database to the `QDateTime` instance when it is accessed via your TinyORM model.",source:"@site/docs/tinyorm/casts.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/casts",permalink:"/tinyorm/casts",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,sidebar_label:"Casts",description:"Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a `datetime` string that is stored in your database to the `QDateTime` instance when it is accessed via your TinyORM model.",keywords:["c++ orm","orm","casts","casting","attributes","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Collections",permalink:"/tinyorm/collections"},next:{title:"Serialization",permalink:"/tinyorm/serialization"}},d={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Accessors",id:"accessors",level:2},{value:"Defining An Accessor",id:"defining-an-accessor",level:3},{value:"Building Value From Multiple Attributes",id:"building-value-from-multiple-attributes",level:4},{value:"Accessor Caching",id:"accessor-caching",level:4},{value:"Attribute Casting",id:"attribute-casting",level:2},{value:"Date Casting",id:"date-casting",level:3},{value:"Date Casting, Serialization & Timezones",id:"date-casting-serialization-and-timezones",level:4},{value:"Query Time Casting",id:"query-time-casting",level:3}];function l(e){const t={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,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"tinyorm-casting",children:"TinyORM: Casting"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"#accessors",children:"Accessors"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#defining-an-accessor",children:"Defining An Accessor"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"#attribute-casting",children:"Attribute Casting"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#date-casting",children:"Date Casting"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#query-time-casting",children:"Query Time Casting"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsxs)(t.p,{children:["Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a ",(0,s.jsx)(t.code,{children:"datetime"})," string that is stored in your database to the ",(0,s.jsx)(t.code,{children:"QDateTime"})," instance when it is accessed via your TinyORM model. Or, you may want to convert a ",(0,s.jsx)(t.code,{children:"tinyint"})," number that is stored in the database to the ",(0,s.jsx)(t.code,{children:"bool"})," when you access it on the TinyORM model."]}),"\n",(0,s.jsx)(t.h2,{id:"accessors",children:"Accessors"}),"\n",(0,s.jsx)(t.admonition,{type:"warning",children:(0,s.jsxs)(t.p,{children:["Accessors are currently only used during the serialization by the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#appending-values-to-json",children:"Appending Values"})," feature. They are not used during the ",(0,s.jsx)(t.code,{children:"getAttribute"})," or ",(0,s.jsx)(t.code,{children:"getAttributeValue"})," methods calls."]})}),"\n",(0,s.jsx)(t.h3,{id:"defining-an-accessor",children:"Defining An Accessor"}),"\n",(0,s.jsxs)(t.p,{children:["An accessor transforms a TinyORM attribute value when it is accessed (currently during serialization only by the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#appending-values-to-json",children:"Appending Values"}),' feature). To define an accessor, create a protected method on your model to represent the accessible attribute. This method name should correspond to the "camelCase" representation of the true underlying model attribute / database column when applicable.']}),"\n",(0,s.jsxs)(t.p,{children:["In this example, we'll define an accessor for the ",(0,s.jsx)(t.code,{children:"first_name"})," attribute. The accessor will automatically be called by TinyORM during serialization if the ",(0,s.jsx)(t.code,{children:"first_name"})," attribute is defined in the ",(0,s.jsx)(t.code,{children:"u_appends"})," data member set. All attribute accessor methods must return the ",(0,s.jsx)(t.code,{children:"Orm::Tiny::Casts::Attribute"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass User final : public Model\n{\n friend Model;\n using Model::Model;\n\nprotected:\n /*! Get the user\'s first name (accessor). */\n Attribute firstName() const noexcept\n {\n return Attribute::make(/* get */ [this]() -> QVariant\n {\n auto firstName = getAttribute("first_name");\n\n if (!firstName.isEmpty())\n firstName[0] = firstName.at(0).toUpper();\n\n return firstName;\n });\n }\n\nprivate:\n /*! Map of mutator names to methods. */\n inline static const QHash u_mutators {\n {"first_name", &User::firstName},\n };\n};\n'})}),"\n",(0,s.jsxs)(t.p,{children:["All accessor methods return an ",(0,s.jsx)(t.code,{children:"Attribute"})," instance which defines how the attribute will be accessed. To do so, we supply the ",(0,s.jsx)(t.code,{children:"get"})," argument to the ",(0,s.jsx)(t.code,{children:"Attribute"})," class constructor or ",(0,s.jsx)(t.code,{children:"Attribute::make"})," factory method."]}),"\n",(0,s.jsxs)(t.p,{children:["As you can see, the current model is captured by-reference using the ",(0,s.jsx)(t.code,{children:"[this]"})," capture, allowing you to obtain a value by the ",(0,s.jsx)(t.code,{children:"getAttribute"})," method inside the lambda expression, manipulate it and return a new value."]}),"\n",(0,s.jsxs)(t.p,{children:["You can also use the second overload that allows you to pass the ",(0,s.jsx)(t.code,{children:"ModelAttributes"})," unordered map to the lambda expression:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'protected:\n /*! Get the user\'s first name (accessor). */\n Attribute firstName() const noexcept\n {\n return Attribute::make(\n /* get */ [](const ModelAttributes &attributes) -> QVariant\n {\n auto firstName = attributes.at("first_name");\n\n if (!firstName.isEmpty())\n firstName[0] = firstName.at(0).toUpper();\n\n return firstName;\n });\n }\n'})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"https://github.com/silverqx/TinyORM/blob/main/include/orm/tiny/types/modelattributes.hpp",children:(0,s.jsx)(t.code,{children:"ModelAttributes"})})," container extends the ",(0,s.jsx)(t.code,{children:"std::unordered_map"})," and adds the ",(0,s.jsx)(t.code,{children:"at"})," method that allows you to cast the underlying QVariant value."]}),"\n",(0,s.jsxs)(t.p,{children:["Special note should be given to the ",(0,s.jsx)(t.code,{children:"u_mutators"})," static data member map, which maps accessors' attribute names to its methods. This data member is ",(0,s.jsx)(t.strong,{children:"required"})," because C++ does not currently support reflection."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["If you would like these computed values to be added to the vector, map, or JSON representations of your model, ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#appending-values-to-json",children:"you will need to append them"}),"."]})}),"\n",(0,s.jsx)(t.admonition,{type:"danger",children:(0,s.jsx)(t.p,{children:"You must guarantee that the current model will live long enough to avoid the dangling reference and crash if the current model is captured by-reference. Of course, you can capture it by-copy in edge cases or if you can't guarantee this."})}),"\n",(0,s.jsx)(t.h4,{id:"building-value-from-multiple-attributes",children:"Building Value From Multiple Attributes"}),"\n",(0,s.jsx)(t.p,{children:"Sometimes your accessor may need to transform multiple model attributes into a single value. You can use both methods described above to accomplish this:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Orm::Constants::SPACE_IN;\n\nprotected:\n /*! Get the user\'s full name (accessor). */\n Attribute fullName() const noexcept\n {\n return Attribute::make(/* get */ [this]() -> QVariant\n {\n return SPACE_IN.arg(getAttribute("first_name"),\n getAttribute("last_name"));\n });\n }\n'})}),"\n",(0,s.jsxs)(t.p,{children:["Or you can use the ",(0,s.jsx)(t.code,{children:"ModelAttributes"})," overload:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! Get the user\'s full name (accessor). */\nAttribute fullName() const noexcept\n{\n return Attribute::make(\n /* get */ [](const ModelAttributes &attributes) -> QVariant\n {\n return SPACE_IN.arg(attributes.at("first_name"),\n attributes.at("last_name"));\n });\n}\n'})}),"\n",(0,s.jsx)(t.h4,{id:"accessor-caching",children:"Accessor Caching"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes computing an attribute value can be intensive, in this case, you can enable caching for this attribute value. To accomplish this, you have to invoke the ",(0,s.jsx)(t.code,{children:"shouldCache"})," method when defining your accessor:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Orm::Constants::SPACE_IN;\n\nprotected:\n /*! Get the user\'s full name (accessor). */\n Attribute fullName() const noexcept\n {\n return Attribute::make(/* get */ [this]() -> QVariant\n {\n return SPACE_IN.arg(getAttribute("first_name"),\n getAttribute("last_name"));\n }).shouldCache();\n }\n'})}),"\n",(0,s.jsx)(t.h2,{id:"attribute-casting",children:"Attribute Casting"}),"\n",(0,s.jsxs)(t.p,{children:["Attribute casting provides functionality that allows converting model attributes to the appropriate ",(0,s.jsx)(t.code,{children:"QVariant"})," ",(0,s.jsx)(t.strong,{children:"metatype"})," when it is accessed via your TinyORM model. The core of this functionality is a model's ",(0,s.jsx)(t.code,{children:"u_casts"})," static data member that provides a convenient method of converting attributes' ",(0,s.jsx)(t.code,{children:"QVariant"})," ",(0,s.jsx)(t.strong,{children:"internal types"})," to the defined cast types."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"u_casts"})," static data member should be the ",(0,s.jsx)(t.code,{children:"std::unordered_map"})," where the key is the name of the attribute being cast and the value is the type you wish to cast the column to. The supported cast types are:"]}),"\n",(0,s.jsx)("div",{id:"casts-types-list",children:(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QString"})}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"CastType::Boolean"})," / ",(0,s.jsx)(t.code,{children:"CastType::Bool"})]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"CastType::Integer"})," / ",(0,s.jsx)(t.code,{children:"CastType::Int"})]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"CastType::UInteger"})," / ",(0,s.jsx)(t.code,{children:"CastType::UInt"})]}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::LongLong"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::ULongLong"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Short"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::UShort"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QDate"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QDateTime"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Timestamp"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Real"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Float"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Double"})}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)("code",{children:"CastType::Decimal:"}),"\n"]}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QByteArray"})}),"\n"]})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["The primary key name defined by the ",(0,s.jsx)(t.code,{children:"u_primaryKey"})," model's data member is automatically cast to the ",(0,s.jsx)(t.code,{children:"CastType::ULongLong"})," for all database drivers if the ",(0,s.jsx)(t.code,{children:"u_incrementing"})," is set to true (its default value)."]})}),"\n",(0,s.jsxs)(t.p,{children:["To demonstrate attribute casting, let's cast the ",(0,s.jsx)(t.code,{children:"is_admin"})," attribute, which is stored in our database as an integer (",(0,s.jsx)(t.code,{children:"0"})," or ",(0,s.jsx)(t.code,{children:"1"}),") to a ",(0,s.jsx)(t.code,{children:"QVariant(bool)"})," value:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'#pragma once\n\n#include \n\nusing Orm::Tiny::Model;\n\nclass User final : public Model\n{\n friend Model;\n using Model::Model;\n\n /*! The attributes that should be cast. */\n inline static std::unordered_map u_casts {\n {"is_admin", CastType::Boolean},\n };\n};\n'})}),"\n",(0,s.jsxs)(t.p,{children:["After defining the cast, the ",(0,s.jsx)(t.code,{children:"is_admin"})," attribute will always be cast to a ",(0,s.jsx)(t.code,{children:"QVariant(bool)"})," when you access it, even if the underlying value is stored in the database as an integer:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Orm::Utils::Helpers;\n\nauto isAdmin = User::find(1)->getAttribute("is_admin");\n\n// Proof of the QVariant type\nQ_ASSERT(Helpers::qVariantTypeId(isAdmin) == QMetaType::Bool);\n\nif (isAdmin.value()) {\n //\n}\n'})}),"\n",(0,s.jsxs)(t.p,{children:["If you need to add a new, ",(0,s.jsx)(t.strong,{children:"temporary"})," cast at runtime, you may use the ",(0,s.jsx)(t.code,{children:"mergeCasts"})," method. These cast definitions will be added to any of the casts already defined on the model:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'user->mergeCasts({\n {"is_paid", CastType::Boolean},\n {"income", {CastType::Decimal, 2}},\n});\n'})}),"\n",(0,s.jsx)(t.admonition,{type:"warning",children:(0,s.jsx)(t.p,{children:"You should never define a cast (or an attribute) that has the same name as a relationship."})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Attributes that are ",(0,s.jsx)(t.code,{children:"null"})," ",(0,s.jsx)(t.strong,{children:"will also be"})," cast so that the ",(0,s.jsx)(t.code,{children:"QVariant"}),"'s internal type will have the correct type."]})}),"\n",(0,s.jsx)(t.h3,{id:"date-casting",children:"Date Casting"}),"\n",(0,s.jsxs)(t.p,{children:["By default, TinyORM will cast the ",(0,s.jsx)(t.code,{children:"created_at"})," and ",(0,s.jsx)(t.code,{children:"updated_at"})," columns to instances of ",(0,s.jsx)(t.code,{children:"QDateTime"}),". You may cast additional date attributes by defining additional date casts within your model's ",(0,s.jsx)(t.code,{children:"u_casts"})," static data member unordered map. Typically, dates should be cast using the ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"}),", ",(0,s.jsx)(t.code,{children:"CastType::QDate"}),", or ",(0,s.jsx)(t.code,{children:"CastType::Timestamp"})," cast types."]}),"\n",(0,s.jsxs)(t.p,{children:["When a database column is of the date type, you may set the corresponding model attribute value to a UNIX timestamp, date string (",(0,s.jsx)(t.code,{children:"Y-m-d"}),"), date-time string, ",(0,s.jsx)(t.code,{children:"QDate"}),", or ",(0,s.jsx)(t.code,{children:"QDateTime"})," instance. The date's value will be correctly converted and stored in your database.",(0,s.jsx)("br",{}),"\nThe same is true for the datetime or timestamp database column types, you can set the corresponding model attribute value to a UNIX timestamp, date-time string, or a ",(0,s.jsx)(t.code,{children:"QDateTime"})," instance."]}),"\n",(0,s.jsxs)(t.p,{children:["When defining the ",(0,s.jsx)(t.code,{children:"CastType::QDate"})," or ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"})," cast, you may also specify the date's format. In this case you must use the ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," or ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," cast types. This format will be used when the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization",children:"model is serialized to a vector, map, or JSON"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! The attributes that should be cast. */\ninline static std::unordered_map u_casts {\n {"created_at", {CastType::CustomQDateTime, "yyyy-MM-dd"}},\n};\n'})}),"\n",(0,s.jsx)(t.admonition,{type:"note",children:(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," and ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," cast types behave exactly like the ",(0,s.jsx)(t.code,{children:"CastType::QDate"})," and ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"})," cast types with the additional ",(0,s.jsx)(t.strong,{children:"date's format"})," functionality during ",(0,s.jsx)("u",{children:(0,s.jsx)(t.strong,{children:"serialization"})}),"."]})}),"\n",(0,s.jsxs)(t.p,{children:["You may customize the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#customizing-the-default-date-format",children:"default serialization format"})," for all of your model's dates or datetimes by defining a ",(0,s.jsx)(t.code,{children:"serializeDate"})," or ",(0,s.jsx)(t.code,{children:"serializeDateTime"})," methods on your model. These methods do not affect how your dates are formatted for storage in the database:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! Prepare a date for vector, map, or JSON serialization. */\nQString serializeDate(const QDate date)\n{\n return date.toString("yyyy-MM-dd");\n}\n\n/*! Prepare a datetime for vector, map, or JSON serialization. */\nQString serializeDateTime(const QDateTime &datetime)\n{\n return datetime.toUTC().toString("yyyy-MM-ddTHH:mm:ssZ");\n}\n'})}),"\n",(0,s.jsxs)(t.p,{children:["To specify the format that should be used when actually storing a model's dates within your database, you should define a ",(0,s.jsx)(t.code,{children:"u_dateFormat"})," data member on your model:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:"/*! The storage format of the model's date columns. */\ninline static QString u_dateFormat {QLatin1Char('U')};\n"})}),"\n",(0,s.jsxs)(t.p,{children:["This format can be any format that the QDateTime's ",(0,s.jsx)(t.code,{children:"fromString"})," or ",(0,s.jsx)(t.code,{children:"toString"})," methods accept or the special ",(0,s.jsx)(t.code,{children:"U"})," format that represents the UNIX timestamp (this ",(0,s.jsx)(t.code,{children:"U"})," format is TinyORM-specific and isn't supported by ",(0,s.jsx)(t.code,{children:"QDateTime"}),")."]}),"\n",(0,s.jsxs)(t.p,{children:["Define a ",(0,s.jsx)(t.code,{children:"u_timeFormat"})," data member on your model to specify the format that should be used when storing a model's times within your database:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! The storage format of the model\'s time columns. */\ninline static QString u_timeFormat {"HH:mm:ss.zzz"};\n'})}),"\n",(0,s.jsx)(t.h4,{id:"date-casting-serialization-and-timezones",children:"Date Casting, Serialization & Timezones"}),"\n",(0,s.jsxs)(t.p,{children:["By default, the ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," and ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," casts will serialize dates to a UTC ISO-8601 date string (",(0,s.jsx)(t.code,{children:"yyyy-MM-ddTHH:mm:ss.zzzZ"}),"), regardless of the timezone specified in your database connection's ",(0,s.jsx)(t.code,{children:"qt_timezone"})," configuration option. You are strongly encouraged to always use this serialization format, as well as to store your application's dates in the UTC timezone by not changing your database connection's ",(0,s.jsx)(t.code,{children:"qt_timezone"})," configuration option from its default ",(0,s.jsx)(t.code,{children:"Qt::UTC"})," value. Consistently using the UTC timezone throughout your application will provide the maximum level of interoperability with other date manipulation libraries or services written in any programming language."]}),"\n",(0,s.jsxs)(t.p,{children:["If a custom format is applied to the ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," or ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," cast types, such as ",(0,s.jsx)(t.code,{children:'{CastType::CustomQDateTime, "yyyy-MM-dd HH:mm:ss"}'}),", the inner timezone of the QDateTime instance will be used during date serialization. Typically, this will be the timezone specified in your database connection's ",(0,s.jsx)(t.code,{children:"qt_timezone"})," configuration option."]}),"\n",(0,s.jsx)(t.h3,{id:"query-time-casting",children:"Query Time Casting"}),"\n",(0,s.jsx)(t.p,{children:"Sometimes you may need to apply casts while executing a query, such as when selecting a raw value from a table. For example, consider the following query:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Models::Post;\nusing Models::User;\n\nauto users = User::select("users.*")\n ->addSelect(\n Post::selectRaw("MAX(created_at)")\n ->whereColumnEq("user_id", "users.id")\n .toBase(),\n "last_posted_at"\n ).get();\n'})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"last_posted_at"})," attribute on the results of this query will be a simple string. It would be wonderful if we could apply a ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"})," cast to this attribute when executing the query. Thankfully, we may accomplish this using the ",(0,s.jsx)(t.code,{children:"withCasts"})," or ",(0,s.jsx)(t.code,{children:"withCast"})," methods:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'auto users = User::select("users.*")\n ->addSelect(Post::selectRaw("MAX(created_at)")\n ->whereColumnEq("user_id", "users.id")\n .toBase(),\n "last_posted_at")\n .withCast({"last_posted_at", CastType::QDateTime})\n .get();\n'})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>o});var s=n(6540);const i={},a=s.createContext(i);function r(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[304],{2403:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var s=n(4848),i=n(8453);const a={sidebar_position:3,sidebar_label:"Casts",description:"Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a `datetime` string that is stored in your database to the `QDateTime` instance when it is accessed via your TinyORM model.",keywords:["c++ orm","orm","casts","casting","attributes","tinyorm"]},r="TinyORM: Casting",o={id:"tinyorm/casts",title:"TinyORM: Casting",description:"Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a `datetime` string that is stored in your database to the `QDateTime` instance when it is accessed via your TinyORM model.",source:"@site/docs/tinyorm/casts.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/casts",permalink:"/tinyorm/casts",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,sidebar_label:"Casts",description:"Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a `datetime` string that is stored in your database to the `QDateTime` instance when it is accessed via your TinyORM model.",keywords:["c++ orm","orm","casts","casting","attributes","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Collections",permalink:"/tinyorm/collections"},next:{title:"Serialization",permalink:"/tinyorm/serialization"}},d={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Accessors",id:"accessors",level:2},{value:"Defining An Accessor",id:"defining-an-accessor",level:3},{value:"Building Value From Multiple Attributes",id:"building-value-from-multiple-attributes",level:4},{value:"Accessor Caching",id:"accessor-caching",level:4},{value:"Attribute Casting",id:"attribute-casting",level:2},{value:"Date Casting",id:"date-casting",level:3},{value:"Date Casting, Serialization & Timezones",id:"date-casting-serialization-and-timezones",level:4},{value:"Query Time Casting",id:"query-time-casting",level:3}];function l(e){const t={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,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.h1,{id:"tinyorm-casting",children:"TinyORM: Casting"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"#accessors",children:"Accessors"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#defining-an-accessor",children:"Defining An Accessor"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.a,{href:"#attribute-casting",children:"Attribute Casting"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#date-casting",children:"Date Casting"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.a,{href:"#query-time-casting",children:"Query Time Casting"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsxs)(t.p,{children:["Attribute casting allows you to transform TinyORM attribute values when you retrieve them on model instances. For example, you may want to convert a ",(0,s.jsx)(t.code,{children:"datetime"})," string that is stored in your database to the ",(0,s.jsx)(t.code,{children:"QDateTime"})," instance when it is accessed via your TinyORM model. Or, you may want to convert a ",(0,s.jsx)(t.code,{children:"tinyint"})," number that is stored in the database to the ",(0,s.jsx)(t.code,{children:"bool"})," when you access it on the TinyORM model."]}),"\n",(0,s.jsx)(t.h2,{id:"accessors",children:"Accessors"}),"\n",(0,s.jsx)(t.admonition,{type:"warning",children:(0,s.jsxs)(t.p,{children:["Accessors are currently only used during the serialization by the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#appending-values-to-json",children:"Appending Values"})," feature. They are not used during the ",(0,s.jsx)(t.code,{children:"getAttribute"})," or ",(0,s.jsx)(t.code,{children:"getAttributeValue"})," methods calls."]})}),"\n",(0,s.jsx)(t.h3,{id:"defining-an-accessor",children:"Defining An Accessor"}),"\n",(0,s.jsxs)(t.p,{children:["An accessor transforms a TinyORM attribute value when it is accessed (currently during serialization only by the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#appending-values-to-json",children:"Appending Values"}),' feature). To define an accessor, create a protected method on your model to represent the accessible attribute. This method name should correspond to the "camelCase" representation of the true underlying model attribute / database column when applicable.']}),"\n",(0,s.jsxs)(t.p,{children:["In this example, we'll define an accessor for the ",(0,s.jsx)(t.code,{children:"first_name"})," attribute. The accessor will automatically be called by TinyORM during serialization if the ",(0,s.jsx)(t.code,{children:"first_name"})," attribute is defined in the ",(0,s.jsx)(t.code,{children:"u_appends"})," data member set. All attribute accessor methods must return the ",(0,s.jsx)(t.code,{children:"Orm::Tiny::Casts::Attribute"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'#include \n\nusing Orm::Tiny::Model;\n\nclass User final : public Model\n{\n friend Model;\n using Model::Model;\n\nprotected:\n /*! Get the user\'s first name (accessor). */\n Attribute firstName() const noexcept\n {\n return Attribute::make(/* get */ [this]() -> QVariant\n {\n auto firstName = getAttribute("first_name");\n\n if (!firstName.isEmpty())\n firstName[0] = firstName.at(0).toUpper();\n\n return firstName;\n });\n }\n\nprivate:\n /*! Map of mutator names to methods. */\n inline static const QHash u_mutators {\n {"first_name", &User::firstName},\n };\n};\n'})}),"\n",(0,s.jsxs)(t.p,{children:["All accessor methods return an ",(0,s.jsx)(t.code,{children:"Attribute"})," instance which defines how the attribute will be accessed. To do so, we supply the ",(0,s.jsx)(t.code,{children:"get"})," argument to the ",(0,s.jsx)(t.code,{children:"Attribute"})," class constructor or ",(0,s.jsx)(t.code,{children:"Attribute::make"})," factory method."]}),"\n",(0,s.jsxs)(t.p,{children:["As you can see, the current model is captured by-reference using the ",(0,s.jsx)(t.code,{children:"[this]"})," capture, allowing you to obtain a value by the ",(0,s.jsx)(t.code,{children:"getAttribute"})," method inside the lambda expression, manipulate it and return a new value."]}),"\n",(0,s.jsxs)(t.p,{children:["You can also use the second overload that allows you to pass the ",(0,s.jsx)(t.code,{children:"ModelAttributes"})," unordered map to the lambda expression:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'protected:\n /*! Get the user\'s first name (accessor). */\n Attribute firstName() const noexcept\n {\n return Attribute::make(\n /* get */ [](const ModelAttributes &attributes) -> QVariant\n {\n auto firstName = attributes.at("first_name");\n\n if (!firstName.isEmpty())\n firstName[0] = firstName.at(0).toUpper();\n\n return firstName;\n });\n }\n'})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.a,{href:"https://github.com/silverqx/TinyORM/blob/main/include/orm/tiny/types/modelattributes.hpp",children:(0,s.jsx)(t.code,{children:"ModelAttributes"})})," container extends the ",(0,s.jsx)(t.code,{children:"std::unordered_map"})," and adds the ",(0,s.jsx)(t.code,{children:"at"})," method that allows you to cast the underlying QVariant value."]}),"\n",(0,s.jsxs)(t.p,{children:["Special note should be given to the ",(0,s.jsx)(t.code,{children:"u_mutators"})," static data member map, which maps accessors' attribute names to its methods. This data member is ",(0,s.jsx)(t.strong,{children:"required"})," because C++ does not currently support reflection."]}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["If you would like these computed values to be added to the vector, map, or JSON representations of your model, ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#appending-values-to-json",children:"you will need to append them"}),"."]})}),"\n",(0,s.jsx)(t.admonition,{type:"danger",children:(0,s.jsx)(t.p,{children:"You must guarantee that the current model will live long enough to avoid the dangling reference and crash if the current model is captured by-reference. Of course, you can capture it by-copy in edge cases or if you can't guarantee this."})}),"\n",(0,s.jsx)(t.h4,{id:"building-value-from-multiple-attributes",children:"Building Value From Multiple Attributes"}),"\n",(0,s.jsx)(t.p,{children:"Sometimes your accessor may need to transform multiple model attributes into a single value. You can use both methods described above to accomplish this:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Orm::Constants::SPACE_IN;\n\nprotected:\n /*! Get the user\'s full name (accessor). */\n Attribute fullName() const noexcept\n {\n return Attribute::make(/* get */ [this]() -> QVariant\n {\n return SPACE_IN.arg(getAttribute("first_name"),\n getAttribute("last_name"));\n });\n }\n'})}),"\n",(0,s.jsxs)(t.p,{children:["Or you can use the ",(0,s.jsx)(t.code,{children:"ModelAttributes"})," overload:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! Get the user\'s full name (accessor). */\nAttribute fullName() const noexcept\n{\n return Attribute::make(\n /* get */ [](const ModelAttributes &attributes) -> QVariant\n {\n return SPACE_IN.arg(attributes.at("first_name"),\n attributes.at("last_name"));\n });\n}\n'})}),"\n",(0,s.jsx)(t.h4,{id:"accessor-caching",children:"Accessor Caching"}),"\n",(0,s.jsxs)(t.p,{children:["Sometimes computing an attribute value can be intensive, in this case, you can enable caching for this attribute value. To accomplish this, you have to invoke the ",(0,s.jsx)(t.code,{children:"shouldCache"})," method when defining your accessor:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Orm::Constants::SPACE_IN;\n\nprotected:\n /*! Get the user\'s full name (accessor). */\n Attribute fullName() const noexcept\n {\n return Attribute::make(/* get */ [this]() -> QVariant\n {\n return SPACE_IN.arg(getAttribute("first_name"),\n getAttribute("last_name"));\n }).shouldCache();\n }\n'})}),"\n",(0,s.jsx)(t.h2,{id:"attribute-casting",children:"Attribute Casting"}),"\n",(0,s.jsxs)(t.p,{children:["Attribute casting provides functionality that allows converting model attributes to the appropriate ",(0,s.jsx)(t.code,{children:"QVariant"})," ",(0,s.jsx)(t.strong,{children:"metatype"})," when it is accessed via your TinyORM model. The core of this functionality is a model's ",(0,s.jsx)(t.code,{children:"u_casts"})," static data member that provides a convenient method of converting attributes' ",(0,s.jsx)(t.code,{children:"QVariant"})," ",(0,s.jsx)(t.strong,{children:"internal types"})," to the defined cast types."]}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"u_casts"})," static data member should be the ",(0,s.jsx)(t.code,{children:"std::unordered_map"})," where the key is the name of the attribute being cast and the value is the type you wish to cast the column to. The supported cast types are:"]}),"\n",(0,s.jsx)("div",{id:"casts-types-list",children:(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QString"})}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"CastType::Boolean"})," / ",(0,s.jsx)(t.code,{children:"CastType::Bool"})]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"CastType::Integer"})," / ",(0,s.jsx)(t.code,{children:"CastType::Int"})]}),"\n",(0,s.jsxs)(t.li,{children:[(0,s.jsx)(t.code,{children:"CastType::UInteger"})," / ",(0,s.jsx)(t.code,{children:"CastType::UInt"})]}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::LongLong"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::ULongLong"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Short"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::UShort"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QDate"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QDateTime"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Timestamp"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Real"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Float"})}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::Double"})}),"\n",(0,s.jsxs)(t.li,{children:["\n",(0,s.jsx)("code",{children:"CastType::Decimal:"}),"\n"]}),"\n",(0,s.jsx)(t.li,{children:(0,s.jsx)(t.code,{children:"CastType::QByteArray"})}),"\n"]})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["The primary key name defined by the ",(0,s.jsx)(t.code,{children:"u_primaryKey"})," model's data member is automatically cast to the ",(0,s.jsx)(t.code,{children:"CastType::ULongLong"})," for all database drivers if the ",(0,s.jsx)(t.code,{children:"u_incrementing"})," is set to true (its default value)."]})}),"\n",(0,s.jsxs)(t.p,{children:["To demonstrate attribute casting, let's cast the ",(0,s.jsx)(t.code,{children:"is_admin"})," attribute, which is stored in our database as an integer (",(0,s.jsx)(t.code,{children:"0"})," or ",(0,s.jsx)(t.code,{children:"1"}),") to a ",(0,s.jsx)(t.code,{children:"QVariant(bool)"})," value:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'#pragma once\n\n#include \n\nusing Orm::Tiny::Model;\n\nclass User final : public Model\n{\n friend Model;\n using Model::Model;\n\n /*! The attributes that should be cast. */\n inline static std::unordered_map u_casts {\n {"is_admin", CastType::Boolean},\n };\n};\n'})}),"\n",(0,s.jsxs)(t.p,{children:["After defining the cast, the ",(0,s.jsx)(t.code,{children:"is_admin"})," attribute will always be cast to a ",(0,s.jsx)(t.code,{children:"QVariant(bool)"})," when you access it, even if the underlying value is stored in the database as an integer:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Orm::Utils::Helpers;\n\nauto isAdmin = User::find(1)->getAttribute("is_admin");\n\n// Proof of the QVariant type\nQ_ASSERT(Helpers::qVariantTypeId(isAdmin) == QMetaType::Bool);\n\nif (isAdmin.value()) {\n //\n}\n'})}),"\n",(0,s.jsxs)(t.p,{children:["If you need to add a new, ",(0,s.jsx)(t.strong,{children:"temporary"})," cast at runtime, you may use the ",(0,s.jsx)(t.code,{children:"mergeCasts"})," method. These cast definitions will be added to any of the casts already defined on the model:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'user->mergeCasts({\n {"is_paid", CastType::Boolean},\n {"income", {CastType::Decimal, 2}},\n});\n'})}),"\n",(0,s.jsx)(t.admonition,{type:"warning",children:(0,s.jsx)(t.p,{children:"You should never define a cast (or an attribute) that has the same name as a relationship."})}),"\n",(0,s.jsx)(t.admonition,{type:"info",children:(0,s.jsxs)(t.p,{children:["Attributes that are ",(0,s.jsx)(t.code,{children:"null"})," ",(0,s.jsx)(t.strong,{children:"will also be"})," cast so that the ",(0,s.jsx)(t.code,{children:"QVariant"}),"'s internal type will have the correct type."]})}),"\n",(0,s.jsx)(t.h3,{id:"date-casting",children:"Date Casting"}),"\n",(0,s.jsxs)(t.p,{children:["By default, TinyORM will cast the ",(0,s.jsx)(t.code,{children:"created_at"})," and ",(0,s.jsx)(t.code,{children:"updated_at"})," columns to instances of ",(0,s.jsx)(t.code,{children:"QDateTime"}),". You may cast additional date attributes by defining additional date casts within your model's ",(0,s.jsx)(t.code,{children:"u_casts"})," static data member unordered map. Typically, dates should be cast using the ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"}),", ",(0,s.jsx)(t.code,{children:"CastType::QDate"}),", or ",(0,s.jsx)(t.code,{children:"CastType::Timestamp"})," cast types."]}),"\n",(0,s.jsxs)(t.p,{children:["When a database column is of the date type, you may set the corresponding model attribute value to a Unix timestamp, date string (",(0,s.jsx)(t.code,{children:"Y-m-d"}),"), date-time string, ",(0,s.jsx)(t.code,{children:"QDate"}),", or ",(0,s.jsx)(t.code,{children:"QDateTime"})," instance. The date's value will be correctly converted and stored in your database.",(0,s.jsx)("br",{}),"\nThe same is true for the datetime or timestamp database column types, you can set the corresponding model attribute value to a Unix timestamp, date-time string, or a ",(0,s.jsx)(t.code,{children:"QDateTime"})," instance."]}),"\n",(0,s.jsxs)(t.p,{children:["When defining the ",(0,s.jsx)(t.code,{children:"CastType::QDate"})," or ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"})," cast, you may also specify the date's format. In this case you must use the ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," or ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," cast types. This format will be used when the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization",children:"model is serialized to a vector, map, or JSON"}),":"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! The attributes that should be cast. */\ninline static std::unordered_map u_casts {\n {"created_at", {CastType::CustomQDateTime, "yyyy-MM-dd"}},\n};\n'})}),"\n",(0,s.jsx)(t.admonition,{type:"note",children:(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," and ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," cast types behave exactly like the ",(0,s.jsx)(t.code,{children:"CastType::QDate"})," and ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"})," cast types with the additional ",(0,s.jsx)(t.strong,{children:"date's format"})," functionality during ",(0,s.jsx)("u",{children:(0,s.jsx)(t.strong,{children:"serialization"})}),"."]})}),"\n",(0,s.jsxs)(t.p,{children:["You may customize the ",(0,s.jsx)(t.a,{href:"/tinyorm/serialization#customizing-the-default-date-format",children:"default serialization format"})," for all of your model's dates or datetimes by defining a ",(0,s.jsx)(t.code,{children:"serializeDate"})," or ",(0,s.jsx)(t.code,{children:"serializeDateTime"})," methods on your model. These methods do not affect how your dates are formatted for storage in the database:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! Prepare a date for vector, map, or JSON serialization. */\nQString serializeDate(const QDate date)\n{\n return date.toString("yyyy-MM-dd");\n}\n\n/*! Prepare a datetime for vector, map, or JSON serialization. */\nQString serializeDateTime(const QDateTime &datetime)\n{\n return datetime.toUTC().toString("yyyy-MM-ddTHH:mm:ssZ");\n}\n'})}),"\n",(0,s.jsxs)(t.p,{children:["To specify the format that should be used when actually storing a model's dates within your database, you should define a ",(0,s.jsx)(t.code,{children:"u_dateFormat"})," data member on your model:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:"/*! The storage format of the model's date columns. */\ninline static QString u_dateFormat {QLatin1Char('U')};\n"})}),"\n",(0,s.jsxs)(t.p,{children:["This format can be any format that the QDateTime's ",(0,s.jsx)(t.code,{children:"fromString"})," or ",(0,s.jsx)(t.code,{children:"toString"})," methods accept or the special ",(0,s.jsx)(t.code,{children:"U"})," format that represents the Unix timestamp (this ",(0,s.jsx)(t.code,{children:"U"})," format is TinyORM-specific and isn't supported by ",(0,s.jsx)(t.code,{children:"QDateTime"}),")."]}),"\n",(0,s.jsxs)(t.p,{children:["Define a ",(0,s.jsx)(t.code,{children:"u_timeFormat"})," data member on your model to specify the format that should be used when storing a model's times within your database:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'/*! The storage format of the model\'s time columns. */\ninline static QString u_timeFormat {"HH:mm:ss.zzz"};\n'})}),"\n",(0,s.jsx)(t.h4,{id:"date-casting-serialization-and-timezones",children:"Date Casting, Serialization & Timezones"}),"\n",(0,s.jsxs)(t.p,{children:["By default, the ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," and ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," casts will serialize dates to a UTC ISO-8601 date string (",(0,s.jsx)(t.code,{children:"yyyy-MM-ddTHH:mm:ss.zzzZ"}),"), regardless of the timezone specified in your database connection's ",(0,s.jsx)(t.code,{children:"qt_timezone"})," configuration option. You are strongly encouraged to always use this serialization format, as well as to store your application's dates in the UTC timezone by not changing your database connection's ",(0,s.jsx)(t.code,{children:"qt_timezone"})," configuration option from its default ",(0,s.jsx)(t.code,{children:"Qt::UTC"})," value. Consistently using the UTC timezone throughout your application will provide the maximum level of interoperability with other date manipulation libraries or services written in any programming language."]}),"\n",(0,s.jsxs)(t.p,{children:["If a custom format is applied to the ",(0,s.jsx)(t.code,{children:"CastType::CustomQDate"})," or ",(0,s.jsx)(t.code,{children:"CastType::CustomQDateTime"})," cast types, such as ",(0,s.jsx)(t.code,{children:'{CastType::CustomQDateTime, "yyyy-MM-dd HH:mm:ss"}'}),", the inner timezone of the QDateTime instance will be used during date serialization. Typically, this will be the timezone specified in your database connection's ",(0,s.jsx)(t.code,{children:"qt_timezone"})," configuration option."]}),"\n",(0,s.jsx)(t.h3,{id:"query-time-casting",children:"Query Time Casting"}),"\n",(0,s.jsx)(t.p,{children:"Sometimes you may need to apply casts while executing a query, such as when selecting a raw value from a table. For example, consider the following query:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'using Models::Post;\nusing Models::User;\n\nauto users = User::select("users.*")\n ->addSelect(\n Post::selectRaw("MAX(created_at)")\n ->whereColumnEq("user_id", "users.id")\n .toBase(),\n "last_posted_at"\n ).get();\n'})}),"\n",(0,s.jsxs)(t.p,{children:["The ",(0,s.jsx)(t.code,{children:"last_posted_at"})," attribute on the results of this query will be a simple string. It would be wonderful if we could apply a ",(0,s.jsx)(t.code,{children:"CastType::QDateTime"})," cast to this attribute when executing the query. Thankfully, we may accomplish this using the ",(0,s.jsx)(t.code,{children:"withCasts"})," or ",(0,s.jsx)(t.code,{children:"withCast"})," methods:"]}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-cpp",children:'auto users = User::select("users.*")\n ->addSelect(Post::selectRaw("MAX(created_at)")\n ->whereColumnEq("user_id", "users.id")\n .toBase(),\n "last_posted_at")\n .withCast({"last_posted_at", CastType::QDateTime})\n .get();\n'})})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},8453:(e,t,n)=>{n.d(t,{R:()=>r,x:()=>o});var s=n(6540);const i={},a=s.createContext(i);function r(e){const t=s.useContext(a);return s.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/8a8faf8d.2bc4a88b.js b/assets/js/8a8faf8d.1738552f.js similarity index 99% rename from assets/js/8a8faf8d.2bc4a88b.js rename to assets/js/8a8faf8d.1738552f.js index 9145f18c3..040ad650c 100644 --- a/assets/js/8a8faf8d.2bc4a88b.js +++ b/assets/js/8a8faf8d.1738552f.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[129],{6455:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>p,contentTitle:()=>u,default:()=>j,frontMatter:()=>h,metadata:()=>m,toc:()=>g});var s=i(4848),t=i(8453),a=i(8774),r=i(2364),l=i(9365),o=i(1470),d=i(7324),c=i(6694);const h={sidebar_position:3,sidebar_label:"Migrations",description:"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.",keywords:["c++ orm","building","migrations","tinyorm"]},u="Building: Migrations",m={id:"building/migrations",title:"Building: Migrations",description:"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.",source:"@site/docs/building/migrations.mdx",sourceDirName:"building",slug:"/building/migrations",permalink:"/building/migrations",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,sidebar_label:"Migrations",description:"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.",keywords:["c++ orm","building","migrations","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Hello world",permalink:"/building/hello-world"},next:{title:"\ud83d\udcc4 Features Summary",permalink:"/features-summary"}},p={},g=[{value:"Introduction",id:"introduction",level:2},{value:"Install dependencies",id:"install-dependencies",level:2},{value:"Using vcpkg.json (manifest mode)",id:"using-vcpkg-json-manifest-mode",level:4},{value:"Using vcpkg install (manually)",id:"using-vcpkg-install-manually",level:4},{value:"Source code",id:"source-code",level:2},{value:"Main file",id:"main-file",level:3},{value:"Migrations",id:"migrations",level:3},{value:"Seeders",id:"seeders",level:3},{value:"Migrations with CMake",id:"migrations-with-cmake",level:2},{value:"CMake project",id:"cmake-project",level:3},{value:"Build migrations",id:"build-migrations-cmake",level:3},{value:"Execute migrations",id:"execute-migrations-cmake",level:3},{value:"Migrations with qmake",id:"migrations-with-qmake",level:2},{value:"qmake project",id:"qmake-project",level:3},{value:"Auto-configure using .qmake.conf and .env",id:"auto-configure-using-qmakeconf-and-env",level:4},{value:"Migrations source files",id:"migrations-source-files",level:4},{value:"Seeders source files",id:"seeders-source-files",level:4},{value:"Build migrations",id:"build-migrations-qmake",level:3},{value:"Execute migrations",id:"execute-migrations-qmake",level:3},{value:"Finish",id:"finish",level:2}];function x(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,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"building-migrations",children:"Building: Migrations"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#install-dependencies",children:"Install dependencies"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-vcpkg-json-manifest-mode",children:"Using vcpkg.json"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-vcpkg-install-manually",children:"Using vcpkg install"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#source-code",children:"Source code"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#main-file",children:"Main file"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#migrations",children:"Migrations"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#seeders",children:"Seeders"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#migrations-with-cmake",children:"Migrations with CMake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#cmake-project",children:"CMake project"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#build-migrations-cmake",children:"Build migrations"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#execute-migrations-cmake",children:"Execute migrations"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#migrations-with-qmake",children:"Migrations with qmake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#qmake-project",children:"qmake project"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#build-migrations-qmake",children:"Build migrations"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#execute-migrations-qmake",children:"Execute migrations"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#finish",children:"Finish"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsxs)(n.p,{children:["We will try to create a working migrations console application called as ",(0,s.jsx)("abbr",{title:"TinyORM migrations",children:(0,s.jsx)(n.code,{children:"tom"})})," in the terminal with the ",(0,s.jsx)(n.code,{children:"CMake"})," and in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"})," with the ",(0,s.jsx)(n.code,{children:"qmake"})," build systems."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tom"})," console application also expects the following ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"}),", let's create them."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cd ${(0,c.OZ)(d.b)}\nmkdir tom/tom\ncd tom`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cd ${(0,c.OZ)(d.xj)}\nmkdir -p tom/tom\ncd tom`})})]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,s.jsx)(n.code,{children:"tom"})," example application, you can inspire or look at the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/examples/tom",children:"source code"}),". Also, ",(0,s.jsx)(n.code,{children:"TinyORM"})," unit tests use a ",(0,s.jsx)(n.code,{children:"tom"})," migrations internally to create the database structure, internally called as the ",(0,s.jsxs)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/tests/testdata_tom",children:[(0,s.jsx)(n.code,{children:"tom"})," migrations for unit tests"]}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["All these three console applications the ",(0,s.jsx)(n.code,{children:"tom"})," example, ",(0,s.jsx)(n.code,{children:"tom"})," migrations for unit tests, and the application described in this tutorial have practically identical source code (the main.cpp file)."]}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tom"})," is able to generate ",(0,s.jsx)("a",{href:"https://en.wikipedia.org/wiki/Data_definition_language",title:"Data Definition Language",children:"DDL"})," queries for all the ",(0,s.jsx)(n.a,{href:"/database/getting-started#introduction",children:"supported databases"})," databases."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can see the ",(0,s.jsx)(n.a,{href:"/features-summary#tom-console-application",children:"Tom showcase image"})," of how the resulting ",(0,s.jsx)(n.code,{children:"tom"})," console application will look like."]})}),"\n",(0,s.jsx)(n.h2,{id:"install-dependencies",children:"Install dependencies"}),"\n",(0,s.jsxs)(n.p,{children:["First, install the ",(0,s.jsx)(n.code,{children:"vcpkg"})," package manager as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#vcpkg",children:"here"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," libraries are required dependencies because ",(0,s.jsx)(n.code,{children:"TinyORM"})," uses them in header files, you have to install them before you can use ",(0,s.jsx)(n.code,{children:"TinyORM"}),". The ",(0,s.jsx)(n.code,{children:"tabulate"})," library is only needed in the ",(0,s.jsx)(n.code,{children:"tom"})," migrations it's used by the ",(0,s.jsx)(n.code,{children:"migrate:status"})," command."]}),"\n",(0,s.jsxs)(n.p,{children:["There are two ways how to install the ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," libraries using ",(0,s.jsx)(n.code,{children:"vcpkg"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Also, don't forget to build the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library with the ",(0,s.jsx)(n.code,{children:"tom"})," source code enabled (it's enabled by default) as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm",children:"here"}),"."]}),"\n",(0,s.jsxs)(n.h4,{id:"using-vcpkg-json-manifest-mode",children:["Using vcpkg.json ",(0,s.jsx)("small",{children:"(manifest mode)"})]}),"\n",(0,s.jsxs)(n.p,{children:["Create a ",(0,s.jsx)(n.code,{children:"vcpkg.json"})," file with the following content. ",(0,s.jsx)(n.code,{children:"CMake"})," example below uses this method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd tom\nvim vcpkg.json\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",metastring:"title='vcpkg.json'",children:'{\n "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",\n "name": "tom",\n "version-semver": "0.1.0",\n "maintainers": "Silver Zachara ",\n "description": "Tom console application for TinyORM C++ library",\n "homepage": "https://github.com/silverqx/TinyORM",\n "documentation": "https://www.tinyorm.org/building/migrations",\n "supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",\n "dependencies": [\n "range-v3",\n "tabulate"\n ]\n}\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["Only ",(0,s.jsx)(n.code,{children:"CMake"})," via the ",(0,s.jsx)(n.code,{children:"toolchain file"})," supports this method."]})}),"\n",(0,s.jsxs)(n.h4,{id:"using-vcpkg-install-manually",children:["Using vcpkg install ",(0,s.jsx)("small",{children:"(manually)"})]}),"\n",(0,s.jsxs)(n.p,{children:["This method can be used with both ",(0,s.jsx)(n.code,{children:"CMake"})," and ",(0,s.jsx)(n.code,{children:"qmake"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd ../../vcpkg\n\nvcpkg search range-v3\nvcpkg search tabulate\nvcpkg install range-v3 tabulate\nvcpkg list\n"})}),"\n",(0,s.jsx)(n.h2,{id:"source-code",children:"Source code"}),"\n",(0,s.jsxs)(n.p,{children:["Let's start in the ",(0,s.jsx)(n.code,{children:"tom"})," project folder."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cd ${(0,c.OZ)(d.b)}/tom/tom`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cd ${(0,c.OZ)(d.xj)}/tom/tom`})})]}),"\n",(0,s.jsx)(n.h3,{id:"main-file",children:"Main file"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"main.cpp"})," source file."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"vim main.cpp\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["To paste a source code correctly in ",(0,s.jsx)(n.code,{children:"vim"}),", press ",(0,s.jsx)("kbd",{children:"Shift"})," + ",(0,s.jsx)("kbd",{children:"p"}),"."]})}),"\n",(0,s.jsx)(n.p,{children:"And paste the following code."}),"\n",(0,s.jsx)(a.A,{id:"string-constants-example"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",metastring:"title='main.cpp'",children:'#include \n\n#include \n\n#include "migrations/2014_10_12_000000_create_posts_table.hpp"\n\n#include "seeders/databaseseeder.hpp"\n\nusing Orm::DatabaseManager;\nusing Orm::DB;\n\nusing TomApplication = Tom::Application;\n\nusing namespace Migrations; // NOLINT(google-build-using-namespace)\nusing namespace Seeders; // NOLINT(google-build-using-namespace)\n\n/*! Create the database manager instance and add a database connection. */\nstd::shared_ptr setupDatabaseManager();\n\n/*! C++ main function. */\nint main(int argc, char *argv[])\n{\n try {\n // Ownership of the shared_ptr()\n auto db = setupDatabaseManager();\n\n return TomApplication(argc, argv, std::move(db), "TOM_EXAMPLE_ENV")\n .migrations()\n .seeders()\n // Fire it up \ud83d\udd25\ud83d\ude80\u2728\n .run();\n\n } catch (const std::exception &e) {\n\n TomApplication::logException(e);\n }\n\n return EXIT_FAILURE;\n}\n\nstd::shared_ptr setupDatabaseManager()\n{\n using namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n // Ownership of the shared_ptr()\n return DB::create({\n {driver_, QMYSQL},\n {host_, qEnvironmentVariable("DB_MYSQL_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_MYSQL_PORT", P3306)},\n {database_, qEnvironmentVariable("DB_MYSQL_DATABASE", EMPTY)},\n {username_, qEnvironmentVariable("DB_MYSQL_USERNAME", EMPTY)},\n {password_, qEnvironmentVariable("DB_MYSQL_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_MYSQL_CHARSET", UTF8MB4)},\n {collation_, qEnvironmentVariable("DB_MYSQL_COLLATION", UTF8MB40900aici)},\n {timezone_, TZ00},\n /* Specifies what time zone all QDateTime-s will have, the overridden default is\n the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use\n the system local time. */\n {qt_timezone, QVariant::fromValue(Qt::UTC)},\n {strict_, true},\n },\n QStringLiteral("tinyorm_tom_mysql")); // shell:connection\n}\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["If you have defined more database connections then you can tag the lines with the database connection names with the ",(0,s.jsx)(n.code,{children:"// shell:connection"})," comment and this connection names will be provided to the bash, zsh, pwsh completions for the ",(0,s.jsx)(n.code,{children:"--database="})," option \ud83d\ude0e, ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/examples/tom/main.cpp#L74",children:"example"}),"."]})}),"\n",(0,s.jsx)(n.h3,{id:"migrations",children:"Migrations"}),"\n",(0,s.jsxs)(n.p,{children:["If you have already built the ",(0,s.jsx)(n.code,{children:"tom"})," application then you can generate a migrations using the ",(0,s.jsx)(n.a,{href:"/database/migrations#generating-migrations",children:(0,s.jsx)(n.code,{children:"make:migration"})})," command \ud83d\ude0e."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"tom make:migration create_posts_table\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Below is the expected folders structure for the migrations. The ",(0,s.jsx)(n.a,{href:"#migrations-source-files",children:(0,s.jsx)(n.code,{children:"migrations.pri"})})," file is used only by the ",(0,s.jsx)(n.code,{children:"qmake"})," build system and is not needed with ",(0,s.jsx)(n.code,{children:"CMake"})," builds."]}),"\n",(0,s.jsx)(a.A,{id:"folders-structure"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"tom/\n\u2514\u2500\u2500 database/\n \u251c\u2500\u2500 migrations/\n \u251c\u2500\u2500 seeders/\n \u251c\u2500\u2500 migrations.pri\n \u2514\u2500\u2500 seeders.pri\n"})}),"\n",(0,s.jsx)(n.p,{children:"Let's create the first migration manually."}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:"mkdir database/migrations\n\nvim database/migrations/2014_10_12_000000_create_posts_table.hpp"})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:"mkdir -p database/migrations\n\nvim database/migrations/2014_10_12_000000_create_posts_table.hpp"})})]}),"\n",(0,s.jsx)(n.p,{children:"And paste the following code."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",metastring:"title='database/migrations/2014_10_12_000000_create_posts_table.hpp'",children:'#pragma once\n\n#include \n\nnamespace Migrations\n{\n\n struct CreatePostsTable : Migration\n {\n /*! Filename of the migration file. */\n T_MIGRATION\n\n /*! Run the migrations. */\n void up() const override\n {\n Schema::create("posts", [](Blueprint &table)\n {\n table.id();\n\n table.string(NAME);\n table.timestamps();\n });\n }\n\n /*! Reverse the migrations. */\n void down() const override\n {\n Schema::dropIfExists("posts");\n }\n };\n\n} // namespace Migrations\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/database/migrations/2014_10_12_000000_create_posts_table.hpp#L5",children:(0,s.jsx)(n.code,{children:"CreatePostsTable"})})," example migration that also acts as the full-fledged example migration. It has defined and also nicely commented all possible features that migration classes can use or define."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you want, you can also build the ",(0,s.jsx)(n.code,{children:"tom"})," application without the migrations, simply comment out the ",(0,s.jsx)(n.code,{children:"migrations"})," method and the corresponding ",(0,s.jsx)(n.code,{children:'#include "migrations/xyz.hpp"'})," files."]})}),"\n",(0,s.jsx)(n.h3,{id:"seeders",children:"Seeders"}),"\n",(0,s.jsxs)(n.p,{children:["If you have already built the ",(0,s.jsx)(n.code,{children:"tom"})," application then you can generate a seeder using the ",(0,s.jsx)(n.a,{href:"/database/seeding#writing-seeders",children:(0,s.jsx)(n.code,{children:"make:seeder"})})," command \ud83d\ude0e."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"tom make:seeder PostSeeder\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The expected folders structure is described a few paragraphs ",(0,s.jsx)(n.a,{href:"#folders-structure",children:"above"}),". The ",(0,s.jsx)(n.a,{href:"#seeders-source-files",children:(0,s.jsx)(n.code,{children:"seeders.pri"})})," file is used only by the ",(0,s.jsx)(n.code,{children:"qmake"})," build system and is not needed with ",(0,s.jsx)(n.code,{children:"CMake"})," builds."]}),"\n",(0,s.jsx)(n.p,{children:"Let's create the root seeder class manually."}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:"mkdir database/seeders\n\nvim database/seeders/databaseseeder.hpp"})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:"mkdir -p database/seeders\n\nvim database/seeders/databaseseeder.hpp"})})]}),"\n",(0,s.jsx)(n.p,{children:"And paste the following code."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",metastring:"title='database/seeders/databaseseeder.hpp'",children:'#pragma once\n\n#include \n\nnamespace Seeders\n{\n\n /*! Main database seeder. */\n struct DatabaseSeeder : Seeder\n {\n /*! Run the database seeders. */\n void run() override\n {\n DB::table("posts")->insert({\n {{"name", "1. post"}},\n {{"name", "2. post"}},\n });\n }\n };\n\n} // namespace Seeders\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/database/seeders/databaseseeder.hpp#L8",children:(0,s.jsx)(n.code,{children:"DatabaseSeeder"})})," root seeder example class that also acts as the full-fledged example seeder. It has defined and also nicely commented all possible features that seeder classes can use or define."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can create more seeder classes like this and use the ",(0,s.jsx)(n.code,{children:"call<>()"})," method to invoke them as is described in the ",(0,s.jsx)(n.a,{href:"/database/seeding#calling-additional-seeders",children:"Calling Additional Seeders"})," section."]})}),"\n",(0,s.jsx)(n.h2,{id:"migrations-with-cmake",children:"Migrations with CMake"}),"\n",(0,s.jsxs)(n.p,{children:["Create a folder for the ",(0,s.jsx)(n.code,{children:"CMake"})," build."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:"cd ..\nmkdir tom-builds-cmake/build-debug\n\ncd tom"})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:"cd ..\nmkdir -p tom-builds-cmake/build-debug\n\ncd tom"})})]}),"\n",(0,s.jsx)(n.h3,{id:"cmake-project",children:"CMake project"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"CMakeLists.txt"})," file with the following content. I leave the comments in the ",(0,s.jsx)(n.code,{children:"CMakeLists.txt"})," file because it's not as simple as the ",(0,s.jsx)(n.code,{children:"Hello world"})," example; to make it clear what's going on."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cmake",metastring:"title='CMakeLists.txt'",children:'cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\n# Specify the C++ standard\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\n# Initialize variables\n# ---\n\nset(Tom_ns tom)\nset(Tom_target tom)\n\nfile(REAL_PATH "../../TinyORM" TinyMainDir)\n\nset(TinyOrmSourceDir "${TinyMainDir}/TinyORM")\nset(TinyOrmBuildDir "${TinyMainDir}/TinyORM-builds-cmake/build-debug")\n\n# TinyORM CMake modules (needed to set the executable version and RC file on Windows)\nlist(APPEND CMAKE_MODULE_PATH "${TinyOrmSourceDir}/cmake/CommonModules")\n\n# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${TinyOrmBuildDir}")\n\n# Initialize Project Version\n# ---\n\ninclude(TinyHelpers)\ntiny_read_version(TINY_VERSION\n TINY_VERSION_MAJOR TINY_VERSION_MINOR TINY_VERSION_PATCH TINY_VERSION_TWEAK\n VERSION_HEADER "${TinyOrmSourceDir}/tom/include/tom/version.hpp"\n PREFIX TINYTOM\n HEADER_FOR "${Tom_ns}"\n)\n\n# Basic project\n# ---\n\nproject(${Tom_ns}\n DESCRIPTION "Tom console application for TinyORM C++ library"\n HOMEPAGE_URL "https://www.tinyorm.org"\n LANGUAGES CXX\n VERSION ${TINY_VERSION}\n)\n\n# Tom command-line application\n# ---\n\nadd_executable(${Tom_target}\n main.cpp\n)\nadd_executable(${Tom_ns}::${Tom_target} ALIAS ${Tom_target})\n\n# Tom command-line application specific configuration\n# ---\n\nset_target_properties(${Tom_target}\n PROPERTIES\n C_VISIBILITY_PRESET "hidden"\n CXX_VISIBILITY_PRESET "hidden"\n VISIBILITY_INLINES_HIDDEN YES\n VERSION ${PROJECT_VERSION}\n)\n\ntarget_include_directories(${Tom_target}\n PRIVATE "$"\n)\n\n# Tom command-line application defines\n# ---\n\ntarget_compile_definitions(${Tom_target}\n PRIVATE\n PROJECT_TOM\n)\n\n# Windows resource and manifest files\n# ---\n\n# Find icons, tom/version.hpp, and Windows manifest file for MinGW\nif(CMAKE_SYSTEM_NAME STREQUAL "Windows")\n tiny_set_rc_flags("-I \\"${TinyOrmSourceDir}/tom/resources\\"")\nendif()\n\ninclude(TinyResourceAndManifest)\ntiny_resource_and_manifest(${Tom_target}\n OUTPUT_DIR "${TINY_BUILD_GENDIR}/tmp/"\n RESOURCES_DIR "${TinyOrmSourceDir}/tom/resources"\n)\n\n# Resolve and link dependencies\n# ---\n\nfind_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)\nfind_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)\nfind_package(TinyOrm 0.37.3 CONFIG REQUIRED)\n\n# Unconditional dependencies\ntarget_link_libraries(${Tom_target}\n PRIVATE\n Qt${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)\n'})}),"\n",(0,s.jsx)(n.h3,{id:"build-migrations-cmake",children:"Build migrations"}),"\n",(0,s.jsxs)(n.p,{children:["Now you are ready to configure ",(0,s.jsx)(n.code,{children:"tom"})," ",(0,s.jsx)(n.code,{children:"CMake"})," application. Don't forget to prepare the build environment with the ",(0,s.jsx)(n.a,{href:"/building/tinyorm#windows-prerequisites",children:(0,s.jsx)(n.code,{children:"qtenv6.ps1"})})," command if you are building with the ",(0,s.jsx)(n.code,{children:"msvc"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd ../tom-builds-cmake/build-debug\n"})}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cmake.exe \`\n-S "${(0,c.OZ)(d.b)}/tom/tom" \`\n-B "${(0,c.OZ)(d.b)}/tom/tom-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,c.Sn)(d.b)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,c.Sn)(d.b)}/tmp/tom"`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cmake \\\n-S "${(0,c.OZ)(d.xj)}/tom/tom" \\\n-B "${(0,c.OZ)(d.xj)}/tom/tom-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,c.Sn)(d.xj)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,c.Sn)(d.xj)}/tmp/tom"`})})]}),"\n",(0,s.jsx)(n.p,{children:"And build."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cmake --build . --target all\n"})}),"\n",(0,s.jsx)(n.h3,{id:"execute-migrations-cmake",children:"Execute migrations"}),"\n",(0,s.jsxs)(n.p,{children:["Do not forget to add ",(0,s.jsx)(n.code,{children:"TinyOrm0d.dll"})," on the path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux, so ",(0,s.jsx)(n.code,{children:"tom"})," application can find it during execution, as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#tinyorm-on-path-cmake",children:"here"}),"."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`$env:Path = "${(0,c.OZ)(d.b,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,c.OZ)(d.xj)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.p,{children:["Execute ",(0,s.jsx)(n.code,{children:"tom"})," application."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:".\\tom.exe migrate:status\n"})})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"./tom migrate:status\n"})})})]}),"\n",(0,s.jsx)(n.p,{children:"The output will look something like this."}),"\n",(0,s.jsx)("img",{src:i(53).A,alt:"Tom migrations - migrate:status command output",width:"660"}),"\n",(0,s.jsxs)(n.p,{children:["See also the ",(0,s.jsx)(n.a,{href:"#finish",children:"final thoughts"})," on how to verify the ",(0,s.jsx)(n.code,{children:"tom"})," executable file properties."]}),"\n",(0,s.jsx)(n.p,{children:"Happy migrating \ud83c\udf89\ud83d\udc4c"}),"\n",(0,s.jsx)(n.h2,{id:"migrations-with-qmake",children:"Migrations with qmake"}),"\n",(0,s.jsxs)(n.p,{children:["Create a folder for the ",(0,s.jsx)(n.code,{children:"qmake"})," build."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cd ${(0,c.OZ)(d.b)}/tom\n\nmkdir tom-builds-qmake`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cd ${(0,c.OZ)(d.xj)}/tom\n\nmkdir tom-builds-qmake`})})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#source-code",children:(0,s.jsx)(n.code,{children:"source code"})})," is the same as for the ",(0,s.jsx)(n.code,{children:"Migrations with CMake"})," console application."]}),"\n",(0,s.jsx)(n.h3,{id:"qmake-project",children:"qmake project"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"tom.pro"})," qmake file with the following content."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd tom\nvim tom.pro\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["To paste a source code correctly in ",(0,s.jsx)(n.code,{children:"vim"}),", press ",(0,s.jsx)("kbd",{children:"Shift"})," + ",(0,s.jsx)("kbd",{children:"p"}),"."]})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='tom.pro'",children:"QT -= gui\n\nTEMPLATE = app\nTARGET = tom\n\nCONFIG *= cmdline\n\nDEFINES *= PROJECT_TOM\n\nSOURCES += $$PWD/main.cpp\n\n# Database migrations\ninclude($$PWD/database/migrations.pri)\n# Database seeders\ninclude($$PWD/database/seeders.pri)\n\n# Auto-configure TinyORM library for the migrations purposes \ud83d\udd25\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/tom.pri)\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["The exact ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"})," is crucial in this example because the paths to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," source and build folders are relative."]})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!"})}),"\n",(0,s.jsxs)(n.h4,{id:"auto-configure-using-qmakeconf-and-env",children:[(0,s.jsx)(n.code,{children:"Auto-configure"})," using ",(0,s.jsx)(n.code,{children:".qmake.conf"})," and ",(0,s.jsx)(n.code,{children:".env"})]}),"\n",(0,s.jsxs)(n.p,{children:["If you want to have properly configured ",(0,s.jsx)(n.code,{children:"DEFINES"})," (C preprocessor macros), have Qt headers marked as system headers, or eg. have properly set properties of an executable file such as version and description, then you need to specify a path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," qmake features (",(0,s.jsx)(n.code,{children:".prf"})," files) which handle this correctly; this path is provided by the ",(0,s.jsx)(n.code,{children:"QMAKEFEATURES"})," variable and can only be set in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Read the ",(0,s.jsx)(n.a,{href:"/building/tinyorm#consume-tinyorm-library-qmake",children:"Consume TinyOrm library (qmake)"})," section, as everything that is described in that section applies here as well."]})}),"\n",(0,s.jsxs)(n.p,{children:["Create the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file in the ",(0,s.jsx)(n.code,{children:"tom"})," application root folder with the following content."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# Path to the PARENT folder of the TinyORM source folder\nTINY_MAIN_DIR = $$clean_path($$PWD/../../TinyORM/)\n# To find .env and .env.$$QMAKE_PLATFORM files\nTINY_DOTENV_ROOT = $$PWD\n# Path to the current build tree (used to guess the TinyORM build tree)\n#TINY_BUILD_TREE = $$shadowed($$PWD)\n\n# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants\nQMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Then, create a ",(0,s.jsx)("code",{children:".env.(win32|unix|mingw)"})," file in the ",(0,s.jsx)(n.code,{children:"tom"})," application root folder with the following content."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:".env.win32",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in the tom.pro\n# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!\n\n# Path to the TinyORM build folder\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSVC2022_64bit-Debug/)\n\n# Path to the vcpkg - range-v3 and tabulate\n# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty\nTINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)\nTINY_VCPKG_TRIPLET = x64-windows\n\n# Enable ccache wrapper\n#CONFIG *= ccache\n"})})}),(0,s.jsx)(l.A,{value:d.xj,label:".env.unix",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in the tom.pro\n# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!\n\n# Path to the TinyORM build folder\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_clang16_64bit_ccache-Debug/)\n\n# Path to the vcpkg - range-v3 and tabulate\n# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty\nTINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)\nTINY_VCPKG_TRIPLET = x64-linux\n\n# Use faster linker\nclang: CONFIG *= use_lld_linker\nelse: CONFIG *= use_gold_linker\n\n# Or use the mold linker\n#QMAKE_LFLAGS *= -fuse-ld=mold\n"})})}),(0,s.jsx)(l.A,{value:"mingw",label:".env.mingw",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in the tom.pro\n# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!\n\n# Path to the TinyORM build folder\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSYS2_UCRT64_clang_64bit-Debug/)\n\n# Path to the vcpkg - range-v3 and tabulate\n# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty\nTINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)\nTINY_VCPKG_TRIPLET = x64-mingw-dynamic\n\n# Enable ccache wrapper\n#CONFIG *= ccache\n\n# Use faster linker (for both GCC and Clang)\n# CONFIG *= use_lld_linker does not work on MinGW\nQMAKE_LFLAGS *= -fuse-ld=lld\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["Don't forget to update the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," and ",(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})," folder paths to your needs if you are not using the recommended ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:(0,s.jsx)(n.code,{children:"Folders structure"})}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["You can use the ",(0,s.jsxs)(n.a,{href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," if you don't like to specify it manually. Just comment out the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," and uncomment the ",(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE = $$shadowed($$PWD)"})," in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can entirely avoid the ",(0,s.jsx)(n.code,{children:".env"})," files, just move the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," to the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," or remove it by help of ",(0,s.jsxs)(n.a,{href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," and set the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable at system level as is described in ",(0,s.jsx)(n.a,{href:"/building/tinyorm#set-up-vcpkg-environment",children:(0,s.jsx)(n.code,{children:"Set up vcpkg environment"})}),"."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["Configuring by the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," and ",(0,s.jsx)(n.code,{children:".env"})," files has one big advantage, which is that you don't have to modify the project files."]})}),"\n",(0,s.jsx)(n.h4,{id:"migrations-source-files",children:"Migrations source files"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"database/migrations.pri"})," file and paste the following code."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='database/migrations.pri'",children:"INCLUDEPATH *= $$PWD\n\nHEADERS += \\\n $$PWD/migrations/2014_10_12_000000_create_posts_table.hpp \\\n"})}),"\n",(0,s.jsx)(n.h4,{id:"seeders-source-files",children:"Seeders source files"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"database/seeders.pri"})," file and paste the following code."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='database/seeders.pri'",children:"INCLUDEPATH *= $$PWD\n\nHEADERS += \\\n $$PWD/seeders/databaseseeder.hpp \\\n"})}),"\n",(0,s.jsx)(n.h3,{id:"build-migrations-qmake",children:"Build migrations"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["I recommend creating a new ",(0,s.jsx)(n.code,{children:"Session"})," in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"})," as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#open-qtcreator-ide",children:"here"}),"."]})}),"\n",(0,s.jsxs)(n.p,{children:["Now you can open the ",(0,s.jsx)(n.code,{children:"tom.pro"})," project in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["This will open the ",(0,s.jsx)(n.code,{children:"Configure Project"})," tab, select some kit and update build folder paths to meet our ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"})," or like you want."]}),"\n",(0,s.jsx)("img",{src:i(2394).A,alt:"tom - QtCreator - Configure Project",width:"760"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can force the ",(0,s.jsx)(n.code,{children:"QtCreator"})," to generate a build folders structure as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#qtcreator-default-build-directory",children:"here"}),"."]})}),"\n",(0,s.jsxs)(n.p,{children:["You are ready to configure build options, hit ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"5"})," to open ",(0,s.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,s.jsx)(n.code,{children:"Build"})," in the left sidebar to open the ",(0,s.jsx)(n.code,{children:"Build Settings"}),", it should look similar to the following picture."]}),"\n",(0,s.jsx)("img",{src:i(6106).A,className:"no-blurry",alt:"tom - QtCreator - Build Settings",width:"760"}),"\n",(0,s.jsxs)(n.p,{children:["Disable ",(0,s.jsx)(n.code,{children:"QML debugging and profiling"})," and ",(0,s.jsx)(n.code,{children:"Qt Quick Compiler"}),", they are not used."]}),"\n",(0,s.jsxs)(n.p,{children:["In the left sidebar open ",(0,s.jsx)(n.code,{children:"Dependencies"})," and check ",(0,s.jsx)(n.code,{children:"TinyORM"})," project and ",(0,s.jsx)(n.code,{children:"Synchronize configuration"}),", this setting ensures that the current project will be rebuilt correctly when the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library source code changes."]}),"\n",(0,s.jsxs)(n.p,{children:["Everything is ready to build, you can press ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"b"})," to build the project."]}),"\n",(0,s.jsx)(n.h3,{id:"execute-migrations-qmake",children:"Execute migrations"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"QtCreator"})," takes care of all the necessary configurations, sets up the build environment correctly, and also prepends dependency libraries on the system path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux."]}),"\n",(0,s.jsxs)(n.p,{children:["The only thing you might want to change is to run the ",(0,s.jsx)(n.code,{children:"tom"})," application in the new terminal window. To do so, hit ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"5"})," to open the ",(0,s.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,s.jsx)(n.code,{children:"Run"})," in the left sidebar to open the ",(0,s.jsx)(n.code,{children:"Run Settings"}),", then in the ",(0,s.jsx)(n.code,{children:"Run"})," section select the ",(0,s.jsx)(n.code,{children:"Run in terminal"})," checkbox."]}),"\n",(0,s.jsxs)(n.p,{children:["You can also set the ",(0,s.jsx)(n.code,{children:"Command line arguments"})," in this ",(0,s.jsx)(n.code,{children:"Run"})," section, eg. the ",(0,s.jsx)(n.code,{children:"migrate:status"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["To execute the ",(0,s.jsx)(n.code,{children:"tom"})," application press ",(0,s.jsx)("kbd",{children:"Ctrl"})," + ",(0,s.jsx)("kbd",{children:"r"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The output will look ",(0,s.jsx)(n.strong,{children:"very similar"})," to this if you add more migrations."]}),"\n",(0,s.jsx)("img",{src:i(53).A,alt:"Tom migrations - migrate:status command output",width:"660"}),"\n",(0,s.jsx)(n.p,{children:"Happy migrating \ud83c\udf89\ud83d\udc4c"}),"\n",(0,s.jsx)(n.h2,{id:"finish",children:"Finish"}),"\n",(0,s.jsxs)(n.p,{children:["As the last thing, you can check that all the file properties were correctly set by the ",(0,s.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/windows/win32/menurc/resource-compiler",children:(0,s.jsx)(n.code,{children:"rc"})})," compiler."]}),"\n",(0,s.jsxs)(n.p,{children:["Find the ",(0,s.jsx)(n.code,{children:"tom.exe"})," file and press ",(0,s.jsx)("kbd",{children:"Alt"})," + ",(0,s.jsx)("kbd",{children:"Enter"})," to open the file properties. To check the executable manifest you can use eg. the ",(0,s.jsx)(n.a,{href:"http://www.angusj.com/resourcehacker/",children:"Resource Hacker"}),"."]}),"\n",(0,s.jsx)("img",{src:i(4679).A,alt:"tom.exe file properties detail",width:"440"})]})}function j(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(x,{...e})}):x(e)}},9365:(e,n,i)=>{i.d(n,{A:()=>r});i(6540);var s=i(4164);const t={tabItem:"tabItem_Ymn6"};var a=i(4848);function r(e){let{children:n,hidden:i,className:r}=e;return(0,a.jsx)("div",{role:"tabpanel",className:(0,s.A)(t.tabItem,r),hidden:i,children:n})}},1470:(e,n,i)=>{i.d(n,{A:()=>v});var s=i(6540),t=i(4164),a=i(3104),r=i(6347),l=i(205),o=i(7485),d=i(1682),c=i(679);function h(e){return s.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,s.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function u(e){const{values:n,children:i}=e;return(0,s.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:i,attributes:s,default:t}}=e;return{value:n,label:i,attributes:s,default:t}}))}(i);return function(e){const n=(0,d.X)(e,((e,n)=>e.value===n.value));if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[n,i])}function m(e){let{value:n,tabValues:i}=e;return i.some((e=>e.value===n))}function p(e){let{queryString:n=!1,groupId:i}=e;const t=(0,r.W6)(),a=function(e){let{queryString:n=!1,groupId:i}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!i)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return i??null}({queryString:n,groupId:i});return[(0,o.aZ)(a),(0,s.useCallback)((e=>{if(!a)return;const n=new URLSearchParams(t.location.search);n.set(a,e),t.replace({...t.location,search:n.toString()})}),[a,t])]}function g(e){const{defaultValue:n,queryString:i=!1,groupId:t}=e,a=u(e),[r,o]=(0,s.useState)((()=>function(e){let{defaultValue:n,tabValues:i}=e;if(0===i.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:i}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${i.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const s=i.find((e=>e.default))??i[0];if(!s)throw new Error("Unexpected error: 0 tabValues");return s.value}({defaultValue:n,tabValues:a}))),[d,h]=p({queryString:i,groupId:t}),[g,x]=function(e){let{groupId:n}=e;const i=function(e){return e?`docusaurus.tab.${e}`:null}(n),[t,a]=(0,c.Dv)(i);return[t,(0,s.useCallback)((e=>{i&&a.set(e)}),[i,a])]}({groupId:t}),j=(()=>{const e=d??g;return m({value:e,tabValues:a})?e:null})();(0,l.A)((()=>{j&&o(j)}),[j]);return{selectedValue:r,selectValue:(0,s.useCallback)((e=>{if(!m({value:e,tabValues:a}))throw new Error(`Can't select invalid tab value=${e}`);o(e),h(e),x(e)}),[h,x,a]),tabValues:a}}var x=i(2303);const j={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var b=i(4848);function f(e){let{className:n,block:i,selectedValue:s,selectValue:r,tabValues:l}=e;const o=[],{blockElementScrollPositionUntilNextRender:d}=(0,a.a_)(),c=e=>{const n=e.currentTarget,i=o.indexOf(n),t=l[i].value;t!==s&&(d(n),r(t))},h=e=>{let n=null;switch(e.key){case"Enter":c(e);break;case"ArrowRight":{const i=o.indexOf(e.currentTarget)+1;n=o[i]??o[0];break}case"ArrowLeft":{const i=o.indexOf(e.currentTarget)-1;n=o[i]??o[o.length-1];break}}n?.focus()};return(0,b.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,t.A)("tabs",{"tabs--block":i},n),children:l.map((e=>{let{value:n,label:i,attributes:a}=e;return(0,b.jsx)("li",{role:"tab",tabIndex:s===n?0:-1,"aria-selected":s===n,ref:e=>o.push(e),onKeyDown:h,onClick:c,...a,className:(0,t.A)("tabs__item",j.tabItem,a?.className,{"tabs__item--active":s===n}),children:i??n},n)}))})}function _(e){let{lazy:n,children:i,selectedValue:t}=e;const a=(Array.isArray(i)?i:[i]).filter(Boolean);if(n){const e=a.find((e=>e.props.value===t));return e?(0,s.cloneElement)(e,{className:"margin-top--md"}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:a.map(((e,n)=>(0,s.cloneElement)(e,{key:n,hidden:e.props.value!==t})))})}function T(e){const n=g(e);return(0,b.jsxs)("div",{className:(0,t.A)("tabs-container",j.tabList),children:[(0,b.jsx)(f,{...n,...e}),(0,b.jsx)(_,{...n,...e})]})}function v(e){const n=(0,x.A)();return(0,b.jsx)(T,{...e,children:h(e.children)},String(n))}},7324:(e,n,i)=>{i.d(n,{$E:()=>x,A3:()=>b,CW:()=>j,Dx:()=>c,F4:()=>u,Fi:()=>d,J_:()=>v,LQ:()=>f,Lf:()=>y,OO:()=>t,Q7:()=>_,b:()=>l,cy:()=>o,gg:()=>p,kl:()=>m,os:()=>h,pW:()=>a,ux:()=>g,vf:()=>s,xj:()=>r,xt:()=>T});const s="shell",t="database",a="application",r="bash",l="pwsh",o="zsh",d="maria",c="mysql",h="postgres",u="sqlite",m="application",p="bash",g="pwsh",x="zsh",j="MariaDB",b="MySQL",f="PostgreSQL",_="SQLite",T="tinyorm.org",v="$HOME/Code/c/",y="$env:USERPROFILE\\Code\\c\\"},6362:(e,n,i)=>{i.d(n,{A:()=>a});var s=i(6540),t=i(1838);function a(){const e=(0,s.useContext)(t.A);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6694:(e,n,i)=>{i.d(n,{OZ:()=>o,Sn:()=>r,T3:()=>c,bw:()=>d,nC:()=>h,np:()=>l});var s=i(6362),t=i(2303),a=i(7324);const r=function(e,n){return void 0===n&&(n=!0),u((0,s.A)().rootFolder[e]??d(e),e,n)},l=()=>(0,s.A)().rootFolder[a.pW]??d(a.pW),o=function(e,n){if(void 0===n&&(n=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const i=n||e!==a.b?"/":"\\";return u(r(e)+i+l(),e,n)};function d(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,t.A)())return"";switch(e){case a.b:return a.Lf;case a.xj:return a.J_;case a.pW:return a.xt;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function c(e){return e===a.pW}function h(e,n){if(null==n||""===n)return n;const i="$ENV{$1}$2";switch(e){case a.b:return p(n).replace(/\$env:(.+?)(\/.*)/,i);case a.xj:return n.replace(/\$(.+?)(\/.*)/,i);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function u(e,n,i){if(void 0===i&&(i=!0),null==e||""===e)return e;if(n!==a.b)return m(e);const s=m(e);return i?p(s):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(s)}function m(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function p(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},6106:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-build_settings-e10927d1c4ed852620f9eb7564198940.png"},2394:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-configure_project-4721257090370204b0272d166512adef.png"},4679:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/tom_file_properties-0df513c47ceadd5c09165e41c6b53086.png"},53:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/tom_migrate_status-63c129a10bfe6bffe8d2d5ea280860e5.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[129],{6455:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>p,contentTitle:()=>u,default:()=>j,frontMatter:()=>h,metadata:()=>m,toc:()=>g});var s=i(4848),t=i(8453),a=i(8774),r=i(2364),l=i(9365),o=i(1470),d=i(7324),c=i(6694);const h={sidebar_position:3,sidebar_label:"Migrations",description:"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.",keywords:["c++ orm","building","migrations","tinyorm"]},u="Building: Migrations",m={id:"building/migrations",title:"Building: Migrations",description:"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.",source:"@site/docs/building/migrations.mdx",sourceDirName:"building",slug:"/building/migrations",permalink:"/building/migrations",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,sidebar_label:"Migrations",description:"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.",keywords:["c++ orm","building","migrations","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Hello world",permalink:"/building/hello-world"},next:{title:"\ud83d\udcc4 Features Summary",permalink:"/features-summary"}},p={},g=[{value:"Introduction",id:"introduction",level:2},{value:"Install dependencies",id:"install-dependencies",level:2},{value:"Using vcpkg.json (manifest mode)",id:"using-vcpkg-json-manifest-mode",level:4},{value:"Using vcpkg install (manually)",id:"using-vcpkg-install-manually",level:4},{value:"Source code",id:"source-code",level:2},{value:"Main file",id:"main-file",level:3},{value:"Migrations",id:"migrations",level:3},{value:"Seeders",id:"seeders",level:3},{value:"Migrations with CMake",id:"migrations-with-cmake",level:2},{value:"CMake project",id:"cmake-project",level:3},{value:"Build migrations",id:"build-migrations-cmake",level:3},{value:"Execute migrations",id:"execute-migrations-cmake",level:3},{value:"Migrations with qmake",id:"migrations-with-qmake",level:2},{value:"qmake project",id:"qmake-project",level:3},{value:"Auto-configure using .qmake.conf and .env",id:"auto-configure-using-qmakeconf-and-env",level:4},{value:"Migrations source files",id:"migrations-source-files",level:4},{value:"Seeders source files",id:"seeders-source-files",level:4},{value:"Build migrations",id:"build-migrations-qmake",level:3},{value:"Execute migrations",id:"execute-migrations-qmake",level:3},{value:"Finish",id:"finish",level:2}];function x(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,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"building-migrations",children:"Building: Migrations"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#install-dependencies",children:"Install dependencies"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-vcpkg-json-manifest-mode",children:"Using vcpkg.json"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-vcpkg-install-manually",children:"Using vcpkg install"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#source-code",children:"Source code"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#main-file",children:"Main file"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#migrations",children:"Migrations"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#seeders",children:"Seeders"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#migrations-with-cmake",children:"Migrations with CMake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#cmake-project",children:"CMake project"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#build-migrations-cmake",children:"Build migrations"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#execute-migrations-cmake",children:"Execute migrations"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#migrations-with-qmake",children:"Migrations with qmake"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#qmake-project",children:"qmake project"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#build-migrations-qmake",children:"Build migrations"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#execute-migrations-qmake",children:"Execute migrations"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#finish",children:"Finish"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsxs)(n.p,{children:["We will try to create a working migrations console application called as ",(0,s.jsx)("abbr",{title:"TinyORM migrations",children:(0,s.jsx)(n.code,{children:"tom"})})," in the terminal with the ",(0,s.jsx)(n.code,{children:"CMake"})," and in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"})," with the ",(0,s.jsx)(n.code,{children:"qmake"})," build systems."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tom"})," console application also expects the following ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"}),", let's create them."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cd ${(0,c.OZ)(d.b)}\nmkdir tom/tom\ncd tom`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cd ${(0,c.OZ)(d.xj)}\nmkdir -p tom/tom\ncd tom`})})]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,s.jsx)(n.code,{children:"tom"})," example application, you can inspire or look at the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/examples/tom",children:"source code"}),". Also, ",(0,s.jsx)(n.code,{children:"TinyORM"})," unit tests use a ",(0,s.jsx)(n.code,{children:"tom"})," migrations internally to create the database structure, internally called as the ",(0,s.jsxs)(n.a,{href:"https://github.com/silverqx/TinyORM/tree/main/tests/testdata_tom",children:[(0,s.jsx)(n.code,{children:"tom"})," migrations for unit tests"]}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["All these three console applications the ",(0,s.jsx)(n.code,{children:"tom"})," example, ",(0,s.jsx)(n.code,{children:"tom"})," migrations for unit tests, and the application described in this tutorial have practically identical source code (the main.cpp file)."]}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"tom"})," is able to generate ",(0,s.jsx)("a",{href:"https://en.wikipedia.org/wiki/Data_definition_language",title:"Data Definition Language",children:"DDL"})," queries for all the ",(0,s.jsx)(n.a,{href:"/database/getting-started#introduction",children:"supported databases"})," databases."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["You can see the ",(0,s.jsx)(n.a,{href:"/features-summary#tom-console-application",children:"Tom showcase image"})," of how the resulting ",(0,s.jsx)(n.code,{children:"tom"})," console application will look like."]})}),"\n",(0,s.jsx)(n.h2,{id:"install-dependencies",children:"Install dependencies"}),"\n",(0,s.jsxs)(n.p,{children:["First, install the ",(0,s.jsx)(n.code,{children:"vcpkg"})," package manager as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#vcpkg",children:"here"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," libraries are required dependencies because ",(0,s.jsx)(n.code,{children:"TinyORM"})," uses them in header files, you have to install them before you can use ",(0,s.jsx)(n.code,{children:"TinyORM"}),". The ",(0,s.jsx)(n.code,{children:"tabulate"})," library is only needed in the ",(0,s.jsx)(n.code,{children:"tom"})," migrations it's used by the ",(0,s.jsx)(n.code,{children:"migrate:status"})," command."]}),"\n",(0,s.jsxs)(n.p,{children:["There are two ways how to install the ",(0,s.jsx)(n.code,{children:"range-v3"})," and ",(0,s.jsx)(n.code,{children:"tabulate"})," libraries using ",(0,s.jsx)(n.code,{children:"vcpkg"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Also, don't forget to build the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library with the ",(0,s.jsx)(n.code,{children:"tom"})," source code enabled (it's enabled by default) as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm",children:"here"}),"."]}),"\n",(0,s.jsxs)(n.h4,{id:"using-vcpkg-json-manifest-mode",children:["Using vcpkg.json ",(0,s.jsx)("small",{children:"(manifest mode)"})]}),"\n",(0,s.jsxs)(n.p,{children:["Create a ",(0,s.jsx)(n.code,{children:"vcpkg.json"})," file with the following content. ",(0,s.jsx)(n.code,{children:"CMake"})," example below uses this method."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd tom\nvim vcpkg.json\n"})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",metastring:"title='vcpkg.json'",children:'{\n "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",\n "name": "tom",\n "version-semver": "0.1.0",\n "maintainers": "Silver Zachara ",\n "description": "Tom console application for TinyORM C++ library",\n "homepage": "https://github.com/silverqx/TinyORM",\n "documentation": "https://www.tinyorm.org/building/migrations",\n "supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",\n "dependencies": [\n "range-v3",\n "tabulate"\n ]\n}\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["Only ",(0,s.jsx)(n.code,{children:"CMake"})," via the ",(0,s.jsx)(n.code,{children:"toolchain file"})," supports this method."]})}),"\n",(0,s.jsxs)(n.h4,{id:"using-vcpkg-install-manually",children:["Using vcpkg install ",(0,s.jsx)("small",{children:"(manually)"})]}),"\n",(0,s.jsxs)(n.p,{children:["This method can be used with both ",(0,s.jsx)(n.code,{children:"CMake"})," and ",(0,s.jsx)(n.code,{children:"qmake"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd ../../vcpkg\n\nvcpkg search range-v3\nvcpkg search tabulate\nvcpkg install range-v3 tabulate\nvcpkg list\n"})}),"\n",(0,s.jsx)(n.h2,{id:"source-code",children:"Source code"}),"\n",(0,s.jsxs)(n.p,{children:["Let's start in the ",(0,s.jsx)(n.code,{children:"tom"})," project folder."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cd ${(0,c.OZ)(d.b)}/tom/tom`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cd ${(0,c.OZ)(d.xj)}/tom/tom`})})]}),"\n",(0,s.jsx)(n.h3,{id:"main-file",children:"Main file"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"main.cpp"})," source file."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"vim main.cpp\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["To paste a source code correctly in ",(0,s.jsx)(n.code,{children:"vim"}),", press ",(0,s.jsx)("kbd",{children:"Shift"})," + ",(0,s.jsx)("kbd",{children:"p"}),"."]})}),"\n",(0,s.jsx)(n.p,{children:"And paste the following code."}),"\n",(0,s.jsx)(a.A,{id:"string-constants-example"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",metastring:"title='main.cpp'",children:'#include \n\n#include \n\n#include "migrations/2014_10_12_000000_create_posts_table.hpp"\n\n#include "seeders/databaseseeder.hpp"\n\nusing Orm::DatabaseManager;\nusing Orm::DB;\n\nusing TomApplication = Tom::Application;\n\nusing namespace Migrations; // NOLINT(google-build-using-namespace)\nusing namespace Seeders; // NOLINT(google-build-using-namespace)\n\n/*! Create the database manager instance and add a database connection. */\nstd::shared_ptr setupDatabaseManager();\n\n/*! C++ main function. */\nint main(int argc, char *argv[])\n{\n try {\n // Ownership of the shared_ptr()\n auto db = setupDatabaseManager();\n\n return TomApplication(argc, argv, std::move(db), "TOM_EXAMPLE_ENV")\n .migrations()\n .seeders()\n // Fire it up \ud83d\udd25\ud83d\ude80\u2728\n .run();\n\n } catch (const std::exception &e) {\n\n TomApplication::logException(e);\n }\n\n return EXIT_FAILURE;\n}\n\nstd::shared_ptr setupDatabaseManager()\n{\n using namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n // Ownership of the shared_ptr()\n return DB::create({\n {driver_, QMYSQL},\n {host_, qEnvironmentVariable("DB_MYSQL_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_MYSQL_PORT", P3306)},\n {database_, qEnvironmentVariable("DB_MYSQL_DATABASE", EMPTY)},\n {username_, qEnvironmentVariable("DB_MYSQL_USERNAME", EMPTY)},\n {password_, qEnvironmentVariable("DB_MYSQL_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_MYSQL_CHARSET", UTF8MB4)},\n {collation_, qEnvironmentVariable("DB_MYSQL_COLLATION", UTF8MB40900aici)},\n {timezone_, TZ00},\n /* Specifies what time zone all QDateTime-s will have, the overridden default is\n the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use\n the system local time. */\n {qt_timezone, QVariant::fromValue(Qt::UTC)},\n {strict_, true},\n },\n QStringLiteral("tinyorm_tom_mysql")); // shell:connection\n}\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["If you have defined more database connections then you can tag the lines with the database connection names with the ",(0,s.jsx)(n.code,{children:"// shell:connection"})," comment and this connection names will be provided to the bash, zsh, pwsh completions for the ",(0,s.jsx)(n.code,{children:"--database="})," option \ud83d\ude0e, ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/examples/tom/main.cpp#L74",children:"example"}),"."]})}),"\n",(0,s.jsx)(n.h3,{id:"migrations",children:"Migrations"}),"\n",(0,s.jsxs)(n.p,{children:["If you have already built the ",(0,s.jsx)(n.code,{children:"tom"})," application then you can generate a migrations using the ",(0,s.jsx)(n.a,{href:"/database/migrations#generating-migrations",children:(0,s.jsx)(n.code,{children:"make:migration"})})," command \ud83d\ude0e."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"tom make:migration create_posts_table\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Below is the expected folders structure for the migrations. The ",(0,s.jsx)(n.a,{href:"#migrations-source-files",children:(0,s.jsx)(n.code,{children:"migrations.pri"})})," file is used only by the ",(0,s.jsx)(n.code,{children:"qmake"})," build system and is not needed with ",(0,s.jsx)(n.code,{children:"CMake"})," builds."]}),"\n",(0,s.jsx)(a.A,{id:"folders-structure"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"tom/\n\u2514\u2500\u2500 database/\n \u251c\u2500\u2500 migrations/\n \u251c\u2500\u2500 seeders/\n \u251c\u2500\u2500 migrations.pri\n \u2514\u2500\u2500 seeders.pri\n"})}),"\n",(0,s.jsx)(n.p,{children:"Let's create the first migration manually."}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:"mkdir database/migrations\n\nvim database/migrations/2014_10_12_000000_create_posts_table.hpp"})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:"mkdir -p database/migrations\n\nvim database/migrations/2014_10_12_000000_create_posts_table.hpp"})})]}),"\n",(0,s.jsx)(n.p,{children:"And paste the following code."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",metastring:"title='database/migrations/2014_10_12_000000_create_posts_table.hpp'",children:'#pragma once\n\n#include \n\nnamespace Migrations\n{\n\n struct CreatePostsTable : Migration\n {\n /*! Filename of the migration file. */\n T_MIGRATION\n\n /*! Run the migrations. */\n void up() const override\n {\n Schema::create("posts", [](Blueprint &table)\n {\n table.id();\n\n table.string(NAME);\n table.timestamps();\n });\n }\n\n /*! Reverse the migrations. */\n void down() const override\n {\n Schema::dropIfExists("posts");\n }\n };\n\n} // namespace Migrations\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/database/migrations/2014_10_12_000000_create_posts_table.hpp#L5",children:(0,s.jsx)(n.code,{children:"CreatePostsTable"})})," example migration that also acts as the full-fledged example migration. It has defined and also nicely commented all possible features that migration classes can use or define."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["If you want, you can also build the ",(0,s.jsx)(n.code,{children:"tom"})," application without the migrations, simply comment out the ",(0,s.jsx)(n.code,{children:"migrations"})," method and the corresponding ",(0,s.jsx)(n.code,{children:'#include "migrations/xyz.hpp"'})," files."]})}),"\n",(0,s.jsx)(n.h3,{id:"seeders",children:"Seeders"}),"\n",(0,s.jsxs)(n.p,{children:["If you have already built the ",(0,s.jsx)(n.code,{children:"tom"})," application then you can generate a seeder using the ",(0,s.jsx)(n.a,{href:"/database/seeding#writing-seeders",children:(0,s.jsx)(n.code,{children:"make:seeder"})})," command \ud83d\ude0e."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"tom make:seeder PostSeeder\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The expected folders structure is described a few paragraphs ",(0,s.jsx)(n.a,{href:"#folders-structure",children:"above"}),". The ",(0,s.jsx)(n.a,{href:"#seeders-source-files",children:(0,s.jsx)(n.code,{children:"seeders.pri"})})," file is used only by the ",(0,s.jsx)(n.code,{children:"qmake"})," build system and is not needed with ",(0,s.jsx)(n.code,{children:"CMake"})," builds."]}),"\n",(0,s.jsx)(n.p,{children:"Let's create the root seeder class manually."}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:"mkdir database/seeders\n\nvim database/seeders/databaseseeder.hpp"})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:"mkdir -p database/seeders\n\nvim database/seeders/databaseseeder.hpp"})})]}),"\n",(0,s.jsx)(n.p,{children:"And paste the following code."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",metastring:"title='database/seeders/databaseseeder.hpp'",children:'#pragma once\n\n#include \n\nnamespace Seeders\n{\n\n /*! Main database seeder. */\n struct DatabaseSeeder : Seeder\n {\n /*! Run the database seeders. */\n void run() override\n {\n DB::table("posts")->insert({\n {{"name", "1. post"}},\n {{"name", "2. post"}},\n });\n }\n };\n\n} // namespace Seeders\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"TinyORM"})," source tree contains the ",(0,s.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/tests/database/seeders/databaseseeder.hpp#L8",children:(0,s.jsx)(n.code,{children:"DatabaseSeeder"})})," root seeder example class that also acts as the full-fledged example seeder. It has defined and also nicely commented all possible features that seeder classes can use or define."]})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can create more seeder classes like this and use the ",(0,s.jsx)(n.code,{children:"call<>()"})," method to invoke them as is described in the ",(0,s.jsx)(n.a,{href:"/database/seeding#calling-additional-seeders",children:"Calling Additional Seeders"})," section."]})}),"\n",(0,s.jsx)(n.h2,{id:"migrations-with-cmake",children:"Migrations with CMake"}),"\n",(0,s.jsxs)(n.p,{children:["Create a folder for the ",(0,s.jsx)(n.code,{children:"CMake"})," build."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:"cd ..\nmkdir tom-builds-cmake/build-debug\n\ncd tom"})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:"cd ..\nmkdir -p tom-builds-cmake/build-debug\n\ncd tom"})})]}),"\n",(0,s.jsx)(n.h3,{id:"cmake-project",children:"CMake project"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"CMakeLists.txt"})," file with the following content. I leave the comments in the ",(0,s.jsx)(n.code,{children:"CMakeLists.txt"})," file because it's not as simple as the ",(0,s.jsx)(n.code,{children:"Hello world"})," example; to make it clear what's going on."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cmake",metastring:"title='CMakeLists.txt'",children:'cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\n# Specify the C++ standard\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\n# Initialize variables\n# ---\n\nset(Tom_ns tom)\nset(Tom_target tom)\n\nfile(REAL_PATH "../../TinyORM" TinyMainDir)\n\nset(TinyOrmSourceDir "${TinyMainDir}/TinyORM")\nset(TinyOrmBuildDir "${TinyMainDir}/TinyORM-builds-cmake/build-debug")\n\n# TinyORM CMake modules (needed to set the executable version and RC file on Windows)\nlist(APPEND CMAKE_MODULE_PATH "${TinyOrmSourceDir}/cmake/CommonModules")\n\n# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${TinyOrmBuildDir}")\n\n# Initialize Project Version\n# ---\n\ninclude(TinyHelpers)\ntiny_read_version(TINY_VERSION\n TINY_VERSION_MAJOR TINY_VERSION_MINOR TINY_VERSION_PATCH TINY_VERSION_TWEAK\n VERSION_HEADER "${TinyOrmSourceDir}/tom/include/tom/version.hpp"\n PREFIX TINYTOM\n HEADER_FOR "${Tom_ns}"\n)\n\n# Basic project\n# ---\n\nproject(${Tom_ns}\n DESCRIPTION "Tom console application for TinyORM C++ library"\n HOMEPAGE_URL "https://www.tinyorm.org"\n LANGUAGES CXX\n VERSION ${TINY_VERSION}\n)\n\n# Tom command-line application\n# ---\n\nadd_executable(${Tom_target}\n main.cpp\n)\nadd_executable(${Tom_ns}::${Tom_target} ALIAS ${Tom_target})\n\n# Tom command-line application specific configuration\n# ---\n\nset_target_properties(${Tom_target}\n PROPERTIES\n C_VISIBILITY_PRESET "hidden"\n CXX_VISIBILITY_PRESET "hidden"\n VISIBILITY_INLINES_HIDDEN YES\n VERSION ${PROJECT_VERSION}\n)\n\ntarget_include_directories(${Tom_target}\n PRIVATE "$"\n)\n\n# Tom command-line application defines\n# ---\n\ntarget_compile_definitions(${Tom_target}\n PRIVATE\n PROJECT_TOM\n)\n\n# Windows resource and manifest files\n# ---\n\n# Find icons, tom/version.hpp, and Windows manifest file for MinGW\nif(CMAKE_SYSTEM_NAME STREQUAL "Windows")\n tiny_set_rc_flags("-I \\"${TinyOrmSourceDir}/tom/resources\\"")\nendif()\n\ninclude(TinyResourceAndManifest)\ntiny_resource_and_manifest(${Tom_target}\n OUTPUT_DIR "${TINY_BUILD_GENDIR}/tmp/"\n RESOURCES_DIR "${TinyOrmSourceDir}/tom/resources"\n)\n\n# Resolve and link dependencies\n# ---\n\nfind_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)\nfind_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)\nfind_package(TinyOrm 0.37.3 CONFIG REQUIRED)\n\n# Unconditional dependencies\ntarget_link_libraries(${Tom_target}\n PRIVATE\n Qt${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)\n'})}),"\n",(0,s.jsx)(n.h3,{id:"build-migrations-cmake",children:"Build migrations"}),"\n",(0,s.jsxs)(n.p,{children:["Now you are ready to configure ",(0,s.jsx)(n.code,{children:"tom"})," ",(0,s.jsx)(n.code,{children:"CMake"})," application. Don't forget to prepare the build environment with the ",(0,s.jsx)(n.a,{href:"/building/tinyorm#windows-prerequisites",children:(0,s.jsx)(n.code,{children:"qtenv6.ps1"})})," command if you are building with the ",(0,s.jsx)(n.code,{children:"MSVC"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd ../tom-builds-cmake/build-debug\n"})}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cmake.exe \`\n-S "${(0,c.OZ)(d.b)}/tom/tom" \`\n-B "${(0,c.OZ)(d.b)}/tom/tom-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,c.Sn)(d.b)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,c.Sn)(d.b)}/tmp/tom"`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cmake \\\n-S "${(0,c.OZ)(d.xj)}/tom/tom" \\\n-B "${(0,c.OZ)(d.xj)}/tom/tom-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,c.Sn)(d.xj)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,c.Sn)(d.xj)}/tmp/tom"`})})]}),"\n",(0,s.jsx)(n.p,{children:"And build."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cmake --build . --target all\n"})}),"\n",(0,s.jsx)(n.h3,{id:"execute-migrations-cmake",children:"Execute migrations"}),"\n",(0,s.jsxs)(n.p,{children:["Do not forget to add ",(0,s.jsx)(n.code,{children:"TinyOrm0d.dll"})," on the path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux, so ",(0,s.jsx)(n.code,{children:"tom"})," application can find it during execution, as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#tinyorm-on-path-cmake",children:"here"}),"."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`$env:Path = "${(0,c.OZ)(d.b,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,c.OZ)(d.xj)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`})})]}),"\n",(0,s.jsxs)(n.p,{children:["Execute ",(0,s.jsx)(n.code,{children:"tom"})," application."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-powershell",children:".\\tom.exe migrate:status\n"})})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"./tom migrate:status\n"})})})]}),"\n",(0,s.jsx)(n.p,{children:"The output will look something like this."}),"\n",(0,s.jsx)("img",{src:i(53).A,alt:"Tom migrations - migrate:status command output",width:"660"}),"\n",(0,s.jsxs)(n.p,{children:["See also the ",(0,s.jsx)(n.a,{href:"#finish",children:"final thoughts"})," on how to verify the ",(0,s.jsx)(n.code,{children:"tom"})," executable file properties."]}),"\n",(0,s.jsx)(n.p,{children:"Happy migrating \ud83c\udf89\ud83d\udc4c"}),"\n",(0,s.jsx)(n.h2,{id:"migrations-with-qmake",children:"Migrations with qmake"}),"\n",(0,s.jsxs)(n.p,{children:["Create a folder for the ",(0,s.jsx)(n.code,{children:"qmake"})," build."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:d.ux,children:(0,s.jsx)(r.A,{className:"language-powershell",children:`cd ${(0,c.OZ)(d.b)}/tom\n\nmkdir tom-builds-qmake`})}),(0,s.jsx)(l.A,{value:d.xj,label:d.gg,children:(0,s.jsx)(r.A,{className:"language-bash",children:`cd ${(0,c.OZ)(d.xj)}/tom\n\nmkdir tom-builds-qmake`})})]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"#source-code",children:(0,s.jsx)(n.code,{children:"source code"})})," is the same as for the ",(0,s.jsx)(n.code,{children:"Migrations with CMake"})," console application."]}),"\n",(0,s.jsx)(n.h3,{id:"qmake-project",children:"qmake project"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"tom.pro"})," qmake file with the following content."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"cd tom\nvim tom.pro\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["To paste a source code correctly in ",(0,s.jsx)(n.code,{children:"vim"}),", press ",(0,s.jsx)("kbd",{children:"Shift"})," + ",(0,s.jsx)("kbd",{children:"p"}),"."]})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='tom.pro'",children:"QT -= gui\n\nTEMPLATE = app\nTARGET = tom\n\nCONFIG *= cmdline\n\nDEFINES *= PROJECT_TOM\n\nSOURCES += $$PWD/main.cpp\n\n# Database migrations\ninclude($$PWD/database/migrations.pri)\n# Database seeders\ninclude($$PWD/database/seeders.pri)\n\n# Auto-configure TinyORM library for the migrations purposes \ud83d\udd25\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/tom.pri)\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["The exact ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"})," is crucial in this example because the paths to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," source and build folders are relative."]})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsx)(n.p,{children:"Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!"})}),"\n",(0,s.jsxs)(n.h4,{id:"auto-configure-using-qmakeconf-and-env",children:[(0,s.jsx)(n.code,{children:"Auto-configure"})," using ",(0,s.jsx)(n.code,{children:".qmake.conf"})," and ",(0,s.jsx)(n.code,{children:".env"})]}),"\n",(0,s.jsxs)(n.p,{children:["If you want to have properly configured ",(0,s.jsx)(n.code,{children:"DEFINES"})," (C preprocessor macros), have Qt headers marked as system headers, or eg. have properly set properties of an executable file such as version and description, then you need to specify a path to the ",(0,s.jsx)(n.code,{children:"TinyORM"})," qmake features (",(0,s.jsx)(n.code,{children:".prf"})," files) which handle this correctly; this path is provided by the ",(0,s.jsx)(n.code,{children:"QMAKEFEATURES"})," variable and can only be set in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Read the ",(0,s.jsx)(n.a,{href:"/building/tinyorm#consume-tinyorm-library-qmake",children:"Consume TinyOrm library (qmake)"})," section, as everything that is described in that section applies here as well."]})}),"\n",(0,s.jsxs)(n.p,{children:["Create the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file in the ",(0,s.jsx)(n.code,{children:"tom"})," application root folder with the following content."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='.qmake.conf'",children:"# Path to the PARENT folder of the TinyORM source folder\nTINY_MAIN_DIR = $$clean_path($$PWD/../../TinyORM/)\n# To find .env and .env.$$QMAKE_PLATFORM files\nTINY_DOTENV_ROOT = $$PWD\n# Path to the current build tree (used to guess the TinyORM build tree)\n#TINY_BUILD_TREE = $$shadowed($$PWD)\n\n# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants\nQMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Then, create a ",(0,s.jsx)("code",{children:".env.(win32|unix|mingw)"})," file in the ",(0,s.jsx)(n.code,{children:"tom"})," application root folder with the following content."]}),"\n",(0,s.jsxs)(o.A,{groupId:d.vf,children:[(0,s.jsx)(l.A,{value:d.b,label:".env.win32",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in the tom.pro\n# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!\n\n# Path to the TinyORM build folder\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSVC2022_64bit-Debug/)\n\n# Path to the vcpkg - range-v3 and tabulate\n# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty\nTINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)\nTINY_VCPKG_TRIPLET = x64-windows\n\n# Enable ccache wrapper\n#CONFIG *= ccache\n"})})}),(0,s.jsx)(l.A,{value:d.xj,label:".env.unix",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in the tom.pro\n# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!\n\n# Path to the TinyORM build folder\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_clang16_64bit_ccache-Debug/)\n\n# Path to the vcpkg - range-v3 and tabulate\n# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty\nTINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)\nTINY_VCPKG_TRIPLET = x64-linux\n\n# Use faster linker\nclang: CONFIG *= use_lld_linker\nelse: CONFIG *= use_gold_linker\n\n# Or use the mold linker\n#QMAKE_LFLAGS *= -fuse-ld=mold\n"})})}),(0,s.jsx)(l.A,{value:"mingw",label:".env.mingw",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in the tom.pro\n# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!\n\n# Path to the TinyORM build folder\nTINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_2_MSYS2_UCRT64_clang_64bit-Debug/)\n\n# Path to the vcpkg - range-v3 and tabulate\n# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty\nTINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)\nTINY_VCPKG_TRIPLET = x64-mingw-dynamic\n\n# Enable ccache wrapper\n#CONFIG *= ccache\n\n# Use faster linker (for both GCC and Clang)\n# CONFIG *= use_lld_linker does not work on MinGW\nQMAKE_LFLAGS *= -fuse-ld=lld\n"})})})]}),"\n",(0,s.jsxs)(n.p,{children:["Don't forget to update the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," and ",(0,s.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})," folder paths to your needs if you are not using the recommended ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:(0,s.jsx)(n.code,{children:"Folders structure"})}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["You can use the ",(0,s.jsxs)(n.a,{href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," if you don't like to specify it manually. Just comment out the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," and uncomment the ",(0,s.jsx)(n.code,{children:"TINY_BUILD_TREE = $$shadowed($$PWD)"})," in the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," file."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can entirely avoid the ",(0,s.jsx)(n.code,{children:".env"})," files, just move the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," to the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," or remove it by help of ",(0,s.jsxs)(n.a,{href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,s.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," and set the ",(0,s.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable at system level as is described in ",(0,s.jsx)(n.a,{href:"/building/tinyorm#set-up-vcpkg-environment",children:(0,s.jsx)(n.code,{children:"Set up vcpkg environment"})}),"."]})}),"\n",(0,s.jsx)(n.admonition,{type:"info",children:(0,s.jsxs)(n.p,{children:["Configuring by the ",(0,s.jsx)(n.code,{children:".qmake.conf"})," and ",(0,s.jsx)(n.code,{children:".env"})," files has one big advantage, which is that you don't have to modify the project files."]})}),"\n",(0,s.jsx)(n.h4,{id:"migrations-source-files",children:"Migrations source files"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"database/migrations.pri"})," file and paste the following code."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='database/migrations.pri'",children:"INCLUDEPATH *= $$PWD\n\nHEADERS += \\\n $$PWD/migrations/2014_10_12_000000_create_posts_table.hpp \\\n"})}),"\n",(0,s.jsx)(n.h4,{id:"seeders-source-files",children:"Seeders source files"}),"\n",(0,s.jsxs)(n.p,{children:["Create ",(0,s.jsx)(n.code,{children:"database/seeders.pri"})," file and paste the following code."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-qmake",metastring:"title='database/seeders.pri'",children:"INCLUDEPATH *= $$PWD\n\nHEADERS += \\\n $$PWD/seeders/databaseseeder.hpp \\\n"})}),"\n",(0,s.jsx)(n.h3,{id:"build-migrations-qmake",children:"Build migrations"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["I recommend creating a new ",(0,s.jsx)(n.code,{children:"Session"})," in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"})," as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#open-qtcreator-ide",children:"here"}),"."]})}),"\n",(0,s.jsxs)(n.p,{children:["Now you can open the ",(0,s.jsx)(n.code,{children:"tom.pro"})," project in the ",(0,s.jsx)(n.code,{children:"QtCreator IDE"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["This will open the ",(0,s.jsx)(n.code,{children:"Configure Project"})," tab, select some kit and update build folder paths to meet our ",(0,s.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"})," or like you want."]}),"\n",(0,s.jsx)("img",{src:i(2394).A,alt:"tom - QtCreator - Configure Project",width:"760"}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can force the ",(0,s.jsx)(n.code,{children:"QtCreator"})," to generate a build folders structure as is described ",(0,s.jsx)(n.a,{href:"/building/tinyorm#qtcreator-default-build-directory",children:"here"}),"."]})}),"\n",(0,s.jsxs)(n.p,{children:["You are ready to configure build options, hit ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"5"})," to open ",(0,s.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,s.jsx)(n.code,{children:"Build"})," in the left sidebar to open the ",(0,s.jsx)(n.code,{children:"Build Settings"}),", it should look similar to the following picture."]}),"\n",(0,s.jsx)("img",{src:i(6106).A,className:"no-blurry",alt:"tom - QtCreator - Build Settings",width:"760"}),"\n",(0,s.jsxs)(n.p,{children:["Disable ",(0,s.jsx)(n.code,{children:"QML debugging and profiling"})," and ",(0,s.jsx)(n.code,{children:"Qt Quick Compiler"}),", they are not used."]}),"\n",(0,s.jsxs)(n.p,{children:["In the left sidebar open ",(0,s.jsx)(n.code,{children:"Dependencies"})," and check ",(0,s.jsx)(n.code,{children:"TinyORM"})," project and ",(0,s.jsx)(n.code,{children:"Synchronize configuration"}),", this setting ensures that the current project will be rebuilt correctly when the ",(0,s.jsx)(n.code,{children:"TinyORM"})," library source code changes."]}),"\n",(0,s.jsxs)(n.p,{children:["Everything is ready to build, you can press ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"b"})," to build the project."]}),"\n",(0,s.jsx)(n.h3,{id:"execute-migrations-qmake",children:"Execute migrations"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"QtCreator"})," takes care of all the necessary configurations, sets up the build environment correctly, and also prepends dependency libraries on the system path on Windows and on the ",(0,s.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux."]}),"\n",(0,s.jsxs)(n.p,{children:["The only thing you might want to change is to run the ",(0,s.jsx)(n.code,{children:"tom"})," application in the new terminal window. To do so, hit ",(0,s.jsx)("kbd",{children:"Ctrl"}),"+",(0,s.jsx)("kbd",{children:"5"})," to open the ",(0,s.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,s.jsx)(n.code,{children:"Run"})," in the left sidebar to open the ",(0,s.jsx)(n.code,{children:"Run Settings"}),", then in the ",(0,s.jsx)(n.code,{children:"Run"})," section select the ",(0,s.jsx)(n.code,{children:"Run in terminal"})," checkbox."]}),"\n",(0,s.jsxs)(n.p,{children:["You can also set the ",(0,s.jsx)(n.code,{children:"Command line arguments"})," in this ",(0,s.jsx)(n.code,{children:"Run"})," section, eg. the ",(0,s.jsx)(n.code,{children:"migrate:status"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["To execute the ",(0,s.jsx)(n.code,{children:"tom"})," application press ",(0,s.jsx)("kbd",{children:"Ctrl"})," + ",(0,s.jsx)("kbd",{children:"r"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The output will look ",(0,s.jsx)(n.strong,{children:"very similar"})," to this if you add more migrations."]}),"\n",(0,s.jsx)("img",{src:i(53).A,alt:"Tom migrations - migrate:status command output",width:"660"}),"\n",(0,s.jsx)(n.p,{children:"Happy migrating \ud83c\udf89\ud83d\udc4c"}),"\n",(0,s.jsx)(n.h2,{id:"finish",children:"Finish"}),"\n",(0,s.jsxs)(n.p,{children:["As the last thing, you can check that all the file properties were correctly set by the ",(0,s.jsx)(n.a,{href:"https://docs.microsoft.com/en-us/windows/win32/menurc/resource-compiler",children:(0,s.jsx)(n.code,{children:"rc"})})," compiler."]}),"\n",(0,s.jsxs)(n.p,{children:["Find the ",(0,s.jsx)(n.code,{children:"tom.exe"})," file and press ",(0,s.jsx)("kbd",{children:"Alt"})," + ",(0,s.jsx)("kbd",{children:"Enter"})," to open the file properties. To check the executable manifest you can use eg. the ",(0,s.jsx)(n.a,{href:"http://www.angusj.com/resourcehacker/",children:"Resource Hacker"}),"."]}),"\n",(0,s.jsx)("img",{src:i(4679).A,alt:"tom.exe file properties detail",width:"440"})]})}function j(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(x,{...e})}):x(e)}},9365:(e,n,i)=>{i.d(n,{A:()=>r});i(6540);var s=i(4164);const t={tabItem:"tabItem_Ymn6"};var a=i(4848);function r(e){let{children:n,hidden:i,className:r}=e;return(0,a.jsx)("div",{role:"tabpanel",className:(0,s.A)(t.tabItem,r),hidden:i,children:n})}},1470:(e,n,i)=>{i.d(n,{A:()=>v});var s=i(6540),t=i(4164),a=i(3104),r=i(6347),l=i(205),o=i(7485),d=i(1682),c=i(679);function h(e){return s.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,s.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function u(e){const{values:n,children:i}=e;return(0,s.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:i,attributes:s,default:t}}=e;return{value:n,label:i,attributes:s,default:t}}))}(i);return function(e){const n=(0,d.X)(e,((e,n)=>e.value===n.value));if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[n,i])}function m(e){let{value:n,tabValues:i}=e;return i.some((e=>e.value===n))}function p(e){let{queryString:n=!1,groupId:i}=e;const t=(0,r.W6)(),a=function(e){let{queryString:n=!1,groupId:i}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!i)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return i??null}({queryString:n,groupId:i});return[(0,o.aZ)(a),(0,s.useCallback)((e=>{if(!a)return;const n=new URLSearchParams(t.location.search);n.set(a,e),t.replace({...t.location,search:n.toString()})}),[a,t])]}function g(e){const{defaultValue:n,queryString:i=!1,groupId:t}=e,a=u(e),[r,o]=(0,s.useState)((()=>function(e){let{defaultValue:n,tabValues:i}=e;if(0===i.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:i}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${i.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const s=i.find((e=>e.default))??i[0];if(!s)throw new Error("Unexpected error: 0 tabValues");return s.value}({defaultValue:n,tabValues:a}))),[d,h]=p({queryString:i,groupId:t}),[g,x]=function(e){let{groupId:n}=e;const i=function(e){return e?`docusaurus.tab.${e}`:null}(n),[t,a]=(0,c.Dv)(i);return[t,(0,s.useCallback)((e=>{i&&a.set(e)}),[i,a])]}({groupId:t}),j=(()=>{const e=d??g;return m({value:e,tabValues:a})?e:null})();(0,l.A)((()=>{j&&o(j)}),[j]);return{selectedValue:r,selectValue:(0,s.useCallback)((e=>{if(!m({value:e,tabValues:a}))throw new Error(`Can't select invalid tab value=${e}`);o(e),h(e),x(e)}),[h,x,a]),tabValues:a}}var x=i(2303);const j={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var b=i(4848);function f(e){let{className:n,block:i,selectedValue:s,selectValue:r,tabValues:l}=e;const o=[],{blockElementScrollPositionUntilNextRender:d}=(0,a.a_)(),c=e=>{const n=e.currentTarget,i=o.indexOf(n),t=l[i].value;t!==s&&(d(n),r(t))},h=e=>{let n=null;switch(e.key){case"Enter":c(e);break;case"ArrowRight":{const i=o.indexOf(e.currentTarget)+1;n=o[i]??o[0];break}case"ArrowLeft":{const i=o.indexOf(e.currentTarget)-1;n=o[i]??o[o.length-1];break}}n?.focus()};return(0,b.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,t.A)("tabs",{"tabs--block":i},n),children:l.map((e=>{let{value:n,label:i,attributes:a}=e;return(0,b.jsx)("li",{role:"tab",tabIndex:s===n?0:-1,"aria-selected":s===n,ref:e=>o.push(e),onKeyDown:h,onClick:c,...a,className:(0,t.A)("tabs__item",j.tabItem,a?.className,{"tabs__item--active":s===n}),children:i??n},n)}))})}function _(e){let{lazy:n,children:i,selectedValue:t}=e;const a=(Array.isArray(i)?i:[i]).filter(Boolean);if(n){const e=a.find((e=>e.props.value===t));return e?(0,s.cloneElement)(e,{className:"margin-top--md"}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:a.map(((e,n)=>(0,s.cloneElement)(e,{key:n,hidden:e.props.value!==t})))})}function T(e){const n=g(e);return(0,b.jsxs)("div",{className:(0,t.A)("tabs-container",j.tabList),children:[(0,b.jsx)(f,{...n,...e}),(0,b.jsx)(_,{...n,...e})]})}function v(e){const n=(0,x.A)();return(0,b.jsx)(T,{...e,children:h(e.children)},String(n))}},7324:(e,n,i)=>{i.d(n,{$E:()=>x,A3:()=>b,CW:()=>j,Dx:()=>c,F4:()=>u,Fi:()=>d,J_:()=>v,LQ:()=>f,Lf:()=>y,OO:()=>t,Q7:()=>_,b:()=>l,cy:()=>o,gg:()=>p,kl:()=>m,os:()=>h,pW:()=>a,ux:()=>g,vf:()=>s,xj:()=>r,xt:()=>T});const s="shell",t="database",a="application",r="bash",l="pwsh",o="zsh",d="maria",c="mysql",h="postgres",u="sqlite",m="application",p="bash",g="pwsh",x="zsh",j="MariaDB",b="MySQL",f="PostgreSQL",_="SQLite",T="tinyorm.org",v="$HOME/Code/c/",y="$env:USERPROFILE\\Code\\c\\"},6362:(e,n,i)=>{i.d(n,{A:()=>a});var s=i(6540),t=i(1838);function a(){const e=(0,s.useContext)(t.A);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6694:(e,n,i)=>{i.d(n,{OZ:()=>o,Sn:()=>r,T3:()=>c,bw:()=>d,nC:()=>h,np:()=>l});var s=i(6362),t=i(2303),a=i(7324);const r=function(e,n){return void 0===n&&(n=!0),u((0,s.A)().rootFolder[e]??d(e),e,n)},l=()=>(0,s.A)().rootFolder[a.pW]??d(a.pW),o=function(e,n){if(void 0===n&&(n=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const i=n||e!==a.b?"/":"\\";return u(r(e)+i+l(),e,n)};function d(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,t.A)())return"";switch(e){case a.b:return a.Lf;case a.xj:return a.J_;case a.pW:return a.xt;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function c(e){return e===a.pW}function h(e,n){if(null==n||""===n)return n;const i="$ENV{$1}$2";switch(e){case a.b:return p(n).replace(/\$env:(.+?)(\/.*)/,i);case a.xj:return n.replace(/\$(.+?)(\/.*)/,i);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function u(e,n,i){if(void 0===i&&(i=!0),null==e||""===e)return e;if(n!==a.b)return m(e);const s=m(e);return i?p(s):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(s)}function m(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function p(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},6106:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-build_settings-e10927d1c4ed852620f9eb7564198940.png"},2394:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/qmake-configure_project-4721257090370204b0272d166512adef.png"},4679:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/tom_file_properties-0df513c47ceadd5c09165e41c6b53086.png"},53:(e,n,i)=>{i.d(n,{A:()=>s});const s=i.p+"assets/images/tom_migrate_status-63c129a10bfe6bffe8d2d5ea280860e5.png"}}]); \ No newline at end of file diff --git a/assets/js/d459b1c4.ec86ff3b.js b/assets/js/d459b1c4.0427f3e3.js similarity index 98% rename from assets/js/d459b1c4.ec86ff3b.js rename to assets/js/d459b1c4.0427f3e3.js index d52679d1f..50c079084 100644 --- a/assets/js/d459b1c4.ec86ff3b.js +++ b/assets/js/d459b1c4.0427f3e3.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[27],{9120:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>t,contentTitle:()=>d,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var s=n(4848),r=n(8453);const l={sidebar_position:2,sidebar_label:"\ud83d\ude80 Supported Compilers",hide_table_of_contents:!0,description:"Platform requirements, supported compilers and build systems for TinyORM C++ library.",keywords:["c++ orm","supported compilers","supported build systems","tinyorm"]},d="Supported Compilers",o={id:"supported-compilers",title:"Supported Compilers",description:"Platform requirements, supported compilers and build systems for TinyORM C++ library.",source:"@site/docs/supported-compilers.mdx",sourceDirName:".",slug:"/supported-compilers",permalink:"/supported-compilers",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"\ud83d\ude80 Supported Compilers",hide_table_of_contents:!0,description:"Platform requirements, supported compilers and build systems for TinyORM C++ library.",keywords:["c++ orm","supported compilers","supported build systems","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\udd27 Dependencies",permalink:"/dependencies"},next:{title:"Getting Started",permalink:"/database/getting-started"}},t={},c=[{value:"Windows >=10",id:"windows-10",level:4},{value:"Linux",id:"linux",level:4},{value:"Supported build systems",id:"supported-build-systems",level:2},{value:"Make tools",id:"make-tools",level:5},{value:"Parallel building",id:"parallel-building",level:5}];function a(e){const i={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h4:"h4",h5:"h5",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"supported-compilers",children:"Supported Compilers"}),"\n",(0,s.jsxs)(i.p,{children:["Following compilers are backed up by the GitHub Action ",(0,s.jsx)(i.a,{href:"https://github.com/silverqx/TinyORM/tree/main/.github/workflows",children:"workflows"})," (CI pipelines), these workflows also include more then ",(0,s.jsx)(i.strong,{children:"3366 unit tests"})," \ud83d\ude2e\ud83d\udca5."]}),"\n",(0,s.jsxs)("div",{id:"supported-compilers",children:[(0,s.jsx)(i.h4,{id:"windows-10",children:(0,s.jsx)(i.code,{children:"Windows >=10"})}),(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:["MSVC 2019 ",(0,s.jsx)(i.code,{children:">=16.9"})]}),"\n",(0,s.jsxs)(i.li,{children:["MSVC 2022 ",(0,s.jsx)(i.code,{children:">=17"})]}),"\n",(0,s.jsxs)(i.li,{children:["MSYS2 UCRT64 GCC ",(0,s.jsx)(i.code,{children:"10.2"})," - ",(0,s.jsx)(i.code,{children:"14.1"})]}),"\n",(0,s.jsxs)(i.li,{children:["MSYS2 UCRT64 Clang ",(0,s.jsx)(i.code,{children:">=15"})]}),"\n",(0,s.jsxs)(i.li,{children:["clang-cl ",(0,s.jsx)(i.code,{children:">=15"})," with MSVC 2019/2022"]}),"\n"]}),(0,s.jsx)(i.h4,{id:"linux",children:(0,s.jsx)(i.code,{children:"Linux"})}),(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:["GCC ",(0,s.jsx)(i.code,{children:"10.2"})," - ",(0,s.jsx)(i.code,{children:"14.1"})]}),"\n",(0,s.jsxs)(i.li,{children:["Clang ",(0,s.jsx)(i.code,{children:">=15"})," ",(0,s.jsx)("small",{className:"darker",children:"(libstdc++ only)"})]}),"\n"]})]}),"\n",(0,s.jsx)(i.admonition,{type:"tip",children:(0,s.jsx)(i.p,{children:"You can compile TinyORM with the MSVC 2022 even if Qt doesn't provide binaries for the MSVC 2022, you can link against Qt MSVC 2019 binaries without any limitations."})}),"\n",(0,s.jsx)(i.admonition,{type:"warning",children:(0,s.jsxs)(i.p,{children:["The ",(0,s.jsx)(i.code,{children:"macOS"})," and Clang with ",(0,s.jsx)(i.code,{children:"libc++"})," are not supported."]})}),"\n",(0,s.jsx)(i.h2,{id:"supported-build-systems",children:"Supported build systems"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"CMake"})," ",(0,s.jsx)(i.code,{children:">=3.22"})," ",(0,s.jsx)("small",{className:"darker",children:"(policies <= CMP0128 default to NEW)"})]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"qmake"})," distributed by the Qt Framework"]}),"\n"]}),"\n",(0,s.jsx)(i.h5,{id:"make-tools",children:"Make tools"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"jom"})," - highly recommended with the ",(0,s.jsx)(i.code,{children:"qmake"})," build system on Windows ",(0,s.jsx)("small",{className:"darker",children:"(replacement for nmake)"})]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"ninja"})," - recommended for ",(0,s.jsx)(i.code,{children:"CMake"})," as the make file generator"]}),"\n"]}),"\n",(0,s.jsx)(i.h5,{id:"parallel-building",children:"Parallel building"}),"\n",(0,s.jsx)(i.p,{children:"You can control parallel building using the following environment variables."}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:["CMake - ",(0,s.jsx)(i.code,{children:"CMAKE_BUILD_PARALLEL_LEVEL"})," eg. to ",(0,s.jsx)(i.code,{children:"10"})]}),"\n",(0,s.jsxs)(i.li,{children:["jom - ",(0,s.jsx)(i.code,{children:"JOMFLAGS"})," eg. to ",(0,s.jsx)(i.code,{children:"j11"})]}),"\n",(0,s.jsxs)(i.li,{children:["make - ",(0,s.jsx)(i.code,{children:"MAKEFLAGS"})," eg. to ",(0,s.jsx)(i.code,{children:"-j10"})]}),"\n",(0,s.jsxs)(i.li,{children:["vcpkg - ",(0,s.jsx)(i.code,{children:"VCPKG_MAX_CONCURRENCY"})," eg. to ",(0,s.jsx)(i.code,{children:"10"})]}),"\n"]})]})}function h(e={}){const{wrapper:i}={...(0,r.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>d,x:()=>o});var s=n(6540);const r={},l=s.createContext(r);function d(e){const i=s.useContext(l);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function o(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:d(e.components),s.createElement(l.Provider,{value:i},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[27],{9120:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>t,contentTitle:()=>d,default:()=>h,frontMatter:()=>l,metadata:()=>o,toc:()=>c});var s=n(4848),r=n(8453);const l={sidebar_position:2,sidebar_label:"\ud83d\ude80 Supported Compilers",hide_table_of_contents:!0,description:"Platform requirements, supported compilers and build systems for TinyORM C++ library.",keywords:["c++ orm","supported compilers","supported build systems","tinyorm"]},d="Supported Compilers",o={id:"supported-compilers",title:"Supported Compilers",description:"Platform requirements, supported compilers and build systems for TinyORM C++ library.",source:"@site/docs/supported-compilers.mdx",sourceDirName:".",slug:"/supported-compilers",permalink:"/supported-compilers",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"\ud83d\ude80 Supported Compilers",hide_table_of_contents:!0,description:"Platform requirements, supported compilers and build systems for TinyORM C++ library.",keywords:["c++ orm","supported compilers","supported build systems","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\udd27 Dependencies",permalink:"/dependencies"},next:{title:"Getting Started",permalink:"/database/getting-started"}},t={},c=[{value:"Windows >=10",id:"windows-10",level:4},{value:"Linux",id:"linux",level:4},{value:"Supported build systems",id:"supported-build-systems",level:2},{value:"Make tools",id:"make-tools",level:5},{value:"Parallel building",id:"parallel-building",level:5}];function a(e){const i={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h4:"h4",h5:"h5",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(i.h1,{id:"supported-compilers",children:"Supported Compilers"}),"\n",(0,s.jsxs)(i.p,{children:["Following compilers are backed up by the GitHub Action ",(0,s.jsx)(i.a,{href:"https://github.com/silverqx/TinyORM/tree/main/.github/workflows",children:"workflows"})," (CI pipelines), these workflows also include more then ",(0,s.jsx)(i.strong,{children:"3366 unit tests"})," \ud83d\ude2e\ud83d\udca5."]}),"\n",(0,s.jsxs)("div",{id:"supported-compilers",children:[(0,s.jsx)(i.h4,{id:"windows-10",children:(0,s.jsx)(i.code,{children:"Windows >=10"})}),(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:["MSVC 2019 ",(0,s.jsx)(i.code,{children:">=16.9"})]}),"\n",(0,s.jsxs)(i.li,{children:["MSVC 2022 ",(0,s.jsx)(i.code,{children:">=17"})]}),"\n",(0,s.jsxs)(i.li,{children:["MSYS2 UCRT64 GCC ",(0,s.jsx)(i.code,{children:"10.2"})," - ",(0,s.jsx)(i.code,{children:"14.1"})]}),"\n",(0,s.jsxs)(i.li,{children:["MSYS2 UCRT64 Clang ",(0,s.jsx)(i.code,{children:">=15"})]}),"\n",(0,s.jsxs)(i.li,{children:["Clang-cl ",(0,s.jsx)(i.code,{children:">=15"})," with MSVC 2019/2022"]}),"\n"]}),(0,s.jsx)(i.h4,{id:"linux",children:(0,s.jsx)(i.code,{children:"Linux"})}),(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:["GCC ",(0,s.jsx)(i.code,{children:"10.2"})," - ",(0,s.jsx)(i.code,{children:"14.1"})]}),"\n",(0,s.jsxs)(i.li,{children:["Clang ",(0,s.jsx)(i.code,{children:">=15"})," ",(0,s.jsx)("small",{className:"darker",children:"(libstdc++ only)"})]}),"\n"]})]}),"\n",(0,s.jsx)(i.admonition,{type:"tip",children:(0,s.jsx)(i.p,{children:"You can compile TinyORM with the MSVC 2022 even if Qt doesn't provide binaries for the MSVC 2022, you can link against Qt MSVC 2019 binaries without any limitations."})}),"\n",(0,s.jsx)(i.admonition,{type:"warning",children:(0,s.jsxs)(i.p,{children:["The ",(0,s.jsx)(i.code,{children:"macOS"})," and Clang with ",(0,s.jsx)(i.code,{children:"libc++"})," are not supported."]})}),"\n",(0,s.jsx)(i.h2,{id:"supported-build-systems",children:"Supported build systems"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"CMake"})," ",(0,s.jsx)(i.code,{children:">=3.22"})," ",(0,s.jsx)("small",{className:"darker",children:"(policies <= CMP0128 default to NEW)"})]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"qmake"})," distributed by the Qt Framework"]}),"\n"]}),"\n",(0,s.jsx)(i.h5,{id:"make-tools",children:"Make tools"}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"jom"})," - highly recommended with the ",(0,s.jsx)(i.code,{children:"qmake"})," build system on Windows ",(0,s.jsx)("small",{className:"darker",children:"(replacement for nmake)"})]}),"\n",(0,s.jsxs)(i.li,{children:[(0,s.jsx)(i.code,{children:"ninja"})," - recommended for ",(0,s.jsx)(i.code,{children:"CMake"})," as the make file generator"]}),"\n"]}),"\n",(0,s.jsx)(i.h5,{id:"parallel-building",children:"Parallel building"}),"\n",(0,s.jsx)(i.p,{children:"You can control parallel building using the following environment variables."}),"\n",(0,s.jsxs)(i.ul,{children:["\n",(0,s.jsxs)(i.li,{children:["CMake - ",(0,s.jsx)(i.code,{children:"CMAKE_BUILD_PARALLEL_LEVEL"})," eg. to ",(0,s.jsx)(i.code,{children:"10"})]}),"\n",(0,s.jsxs)(i.li,{children:["jom - ",(0,s.jsx)(i.code,{children:"JOMFLAGS"})," eg. to ",(0,s.jsx)(i.code,{children:"j11"})]}),"\n",(0,s.jsxs)(i.li,{children:["make - ",(0,s.jsx)(i.code,{children:"MAKEFLAGS"})," eg. to ",(0,s.jsx)(i.code,{children:"-j10"})]}),"\n",(0,s.jsxs)(i.li,{children:["vcpkg - ",(0,s.jsx)(i.code,{children:"VCPKG_MAX_CONCURRENCY"})," eg. to ",(0,s.jsx)(i.code,{children:"10"})]}),"\n"]})]})}function h(e={}){const{wrapper:i}={...(0,r.R)(),...e.components};return i?(0,s.jsx)(i,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>d,x:()=>o});var s=n(6540);const r={},l=s.createContext(r);function d(e){const i=s.useContext(l);return s.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function o(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:d(e.components),s.createElement(l.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.a9753bc0.js b/assets/js/runtime~main.0072e5b9.js similarity index 92% rename from assets/js/runtime~main.a9753bc0.js rename to assets/js/runtime~main.0072e5b9.js index ec58a6be0..10d3cb915 100644 --- a/assets/js/runtime~main.a9753bc0.js +++ b/assets/js/runtime~main.0072e5b9.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,t,r,o,n={},c={};function f(e){var a=c[e];if(void 0!==a)return a.exports;var t=c[e]={exports:{}};return n[e].call(t.exports,t,t.exports,f),t.exports}f.m=n,e=[],f.O=(a,t,r,o)=>{if(!t){var n=1/0;for(i=0;i=o)&&Object.keys(f.O).every((e=>f.O[e](t[d])))?t.splice(d--,1):(c=!1,o0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,r,o]},f.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return f.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,f.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);f.r(o);var n={};a=a||[null,t({}),t([]),t(t)];for(var c=2&r&&e;"object"==typeof c&&!~a.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((a=>n[a]=()=>e[a]));return n.default=()=>e,f.d(o,n),o},f.d=(e,a)=>{for(var t in a)f.o(a,t)&&!f.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},f.f={},f.e=e=>Promise.all(Object.keys(f.f).reduce(((a,t)=>(f.f[t](e,a),a)),[])),f.u=e=>"assets/js/"+({27:"d459b1c4",48:"a94703ab",69:"e19c288b",82:"5b254f70",98:"a7bd4aaa",117:"3dd307b5",129:"8a8faf8d",138:"1a4e3797",153:"1222ea4e",170:"ba3d4959",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:"ec86ff3b",48:"2ad1c777",69:"810e57ca",82:"48fa5efd",98:"80cc43c0",117:"0ac9dd32",129:"2bc4a88b",138:"1fc0de54",153:"85a6075d",170:"73f88dfd",237:"d109f2ba",258:"d5c02736",295:"83f6540a",304:"40d6303a",395:"d34f93c5",401:"7e577731",416:"a3ad28f7",446:"d7af1da2",462:"0011555c",467:"31fe5c57",485:"712dff19",567:"732ea904",638:"f1deefd4",647:"7024aad0",742:"cb1d9d7d",755:"74ed2104",871:"07531018",913:"3fa60236",957:"2356f0d5",983:"05b1279c",995:"201ad298"}[e]+".js",f.miniCssF=e=>{},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},o="tinyorm.org:",f.l=(e,a,t,n)=>{if(r[e])r[e].push(a);else{var c,d;if(void 0!==t)for(var b=document.getElementsByTagName("script"),i=0;i{c.onerror=c.onload=null,clearTimeout(s);var o=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),o&&o.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=l.bind(null,c.onerror),c.onload=l.bind(null,c.onload),d&&document.head.appendChild(c)}},f.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.p="/",f.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",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,f.p+f.u(e)},(()=>{var e={354:0,869:0};f.f.j=(a,t)=>{var r=f.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 n=f.p+f.u(a),c=new Error;f.l(n,(t=>{if(f.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var o=t&&("load"===t.type?"missing":t.type),n=t&&t.target&&t.target.src;c.message="Loading chunk "+a+" failed.\n("+o+": "+n+")",c.name="ChunkLoadError",c.type=o,c.request=n,r[1](c)}}),"chunk-"+a,a)}},f.O.j=a=>0===e[a];var a=(a,t)=>{var r,o,n=t[0],c=t[1],d=t[2],b=0;if(n.some((a=>0!==e[a]))){for(r in c)f.o(c,r)&&(f.m[r]=c[r]);if(d)var i=d(f)}for(a&&a(t);b{"use strict";var e,a,t,r,o,n={},c={};function f(e){var a=c[e];if(void 0!==a)return a.exports;var t=c[e]={exports:{}};return n[e].call(t.exports,t,t.exports,f),t.exports}f.m=n,e=[],f.O=(a,t,r,o)=>{if(!t){var n=1/0;for(i=0;i=o)&&Object.keys(f.O).every((e=>f.O[e](t[d])))?t.splice(d--,1):(c=!1,o0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,r,o]},f.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return f.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,f.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);f.r(o);var n={};a=a||[null,t({}),t([]),t(t)];for(var c=2&r&&e;"object"==typeof c&&!~a.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((a=>n[a]=()=>e[a]));return n.default=()=>e,f.d(o,n),o},f.d=(e,a)=>{for(var t in a)f.o(a,t)&&!f.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},f.f={},f.e=e=>Promise.all(Object.keys(f.f).reduce(((a,t)=>(f.f[t](e,a),a)),[])),f.u=e=>"assets/js/"+({27:"d459b1c4",48:"a94703ab",69:"e19c288b",82:"5b254f70",98:"a7bd4aaa",117:"3dd307b5",129:"8a8faf8d",138:"1a4e3797",153:"1222ea4e",170:"ba3d4959",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:"0427f3e3",48:"2ad1c777",69:"810e57ca",82:"45cd6b2c",98:"80cc43c0",117:"0ac9dd32",129:"1738552f",138:"1fc0de54",153:"85a6075d",170:"73f88dfd",237:"d109f2ba",258:"d5c02736",295:"83f6540a",304:"5965aaeb",395:"5134d01b",401:"7e577731",416:"a3ad28f7",446:"d7af1da2",462:"0011555c",467:"31fe5c57",485:"712dff19",567:"732ea904",638:"f1deefd4",647:"7024aad0",742:"cb1d9d7d",755:"74ed2104",871:"07531018",913:"3fa60236",957:"2356f0d5",983:"05b1279c",995:"201ad298"}[e]+".js",f.miniCssF=e=>{},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},o="tinyorm.org:",f.l=(e,a,t,n)=>{if(r[e])r[e].push(a);else{var c,d;if(void 0!==t)for(var b=document.getElementsByTagName("script"),i=0;i{c.onerror=c.onload=null,clearTimeout(s);var o=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),o&&o.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=l.bind(null,c.onerror),c.onload=l.bind(null,c.onload),d&&document.head.appendChild(c)}},f.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.p="/",f.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",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,f.p+f.u(e)},(()=>{var e={354:0,869:0};f.f.j=(a,t)=>{var r=f.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 n=f.p+f.u(a),c=new Error;f.l(n,(t=>{if(f.o(e,a)&&(0!==(r=e[a])&&(e[a]=void 0),r)){var o=t&&("load"===t.type?"missing":t.type),n=t&&t.target&&t.target.src;c.message="Loading chunk "+a+" failed.\n("+o+": "+n+")",c.name="ChunkLoadError",c.type=o,c.request=n,r[1](c)}}),"chunk-"+a,a)}},f.O.j=a=>0===e[a];var a=(a,t)=>{var r,o,n=t[0],c=t[1],d=t[2],b=0;if(n.some((a=>0!==e[a]))){for(r in c)f.o(c,r)&&(f.m[r]=c[r]);if(d)var i=d(f)}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 6e1df26bd..82870b8c4 100644 --- a/building/migrations.html +++ b/building/migrations.html @@ -14,7 +14,7 @@ - + @@ -111,7 +111,7 @@

CMake pr

Create CMakeLists.txt file with the following content. I leave the comments in the CMakeLists.txt file because it's not as simple as the Hello world example; to make it clear what's going on.

CMakeLists.txt
cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)

# Specify the C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Initialize variables
# ---

set(Tom_ns tom)
set(Tom_target tom)

file(REAL_PATH "../../TinyORM" TinyMainDir)

set(TinyOrmSourceDir "${TinyMainDir}/TinyORM")
set(TinyOrmBuildDir "${TinyMainDir}/TinyORM-builds-cmake/build-debug")

# TinyORM CMake modules (needed to set the executable version and RC file on Windows)
list(APPEND CMAKE_MODULE_PATH "${TinyOrmSourceDir}/cmake/CommonModules")

# build tree
list(APPEND CMAKE_PREFIX_PATH "${TinyOrmBuildDir}")

# Initialize Project Version
# ---

include(TinyHelpers)
tiny_read_version(TINY_VERSION
TINY_VERSION_MAJOR TINY_VERSION_MINOR TINY_VERSION_PATCH TINY_VERSION_TWEAK
VERSION_HEADER "${TinyOrmSourceDir}/tom/include/tom/version.hpp"
PREFIX TINYTOM
HEADER_FOR "${Tom_ns}"
)

# Basic project
# ---

project(${Tom_ns}
DESCRIPTION "Tom console application for TinyORM C++ library"
HOMEPAGE_URL "https://www.tinyorm.org"
LANGUAGES CXX
VERSION ${TINY_VERSION}
)

# Tom command-line application
# ---

add_executable(${Tom_target}
main.cpp
)
add_executable(${Tom_ns}::${Tom_target} ALIAS ${Tom_target})

# Tom command-line application specific configuration
# ---

set_target_properties(${Tom_target}
PROPERTIES
C_VISIBILITY_PRESET "hidden"
CXX_VISIBILITY_PRESET "hidden"
VISIBILITY_INLINES_HIDDEN YES
VERSION ${PROJECT_VERSION}
)

target_include_directories(${Tom_target}
PRIVATE "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/database>"
)

# Tom command-line application defines
# ---

target_compile_definitions(${Tom_target}
PRIVATE
PROJECT_TOM
)

# Windows resource and manifest files
# ---

# Find icons, tom/version.hpp, and Windows manifest file for MinGW
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
tiny_set_rc_flags("-I \"${TinyOrmSourceDir}/tom/resources\"")
endif()

include(TinyResourceAndManifest)
tiny_resource_and_manifest(${Tom_target}
OUTPUT_DIR "${TINY_BUILD_GENDIR}/tmp/"
RESOURCES_DIR "${TinyOrmSourceDir}/tom/resources"
)

# Resolve and link dependencies
# ---

find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED)
find_package(TinyOrm 0.37.3 CONFIG REQUIRED)

# Unconditional dependencies
target_link_libraries(${Tom_target}
PRIVATE
Qt${QT_VERSION_MAJOR}::Core
TinyOrm::TinyOrm
)

Build migrations

-

Now you are ready to configure tom CMake application. Don't forget to prepare the build environment with the qtenv6.ps1 command if you are building with the msvc.

+

Now you are ready to configure tom CMake application. Don't forget to prepare the build environment with the qtenv6.ps1 command if you are building with the MSVC.

cd ../tom-builds-cmake/build-debug
cmake.exe `
-S "/tom/tom" `
-B "/tom/tom-builds-cmake/build-debug" `
-G 'Ninja' `
-D CMAKE_BUILD_TYPE:STRING='Debug' `
-D CMAKE_TOOLCHAIN_FILE:FILEPATH="/vcpkg/scripts/buildsystems/vcpkg.cmake" `
-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF `
-D CMAKE_INSTALL_PREFIX:PATH="/tmp/tom"

And build.

diff --git a/building/tinyorm.html b/building/tinyorm.html index 530779fc1..97b4a4d0f 100644 --- a/building/tinyorm.html +++ b/building/tinyorm.html @@ -14,7 +14,7 @@ - + @@ -216,7 +216,7 @@
# vcpkg - range-v3 and tabulate
# ---
load(tiny_system_includepath)
tiny_add_system_includepath(<your_path>/vcpkg/installed/x64-linux/include/)

Do not forget to add TinyOrm0.dll on the path on Windows and on the LD_LIBRARY_PATH on Linux, so your application can find it during execution.

$env:Path = "\TinyORM\TinyORM-builds-qmake\build-debug;" + $env:Path
-
tip

On Linux -isystem marks the directory as a system directory, it prevents warnings.

On Windows you can use QMAKE_CXXFLAGS_WARN_ON = -external:anglebrackets -external:W0, it applies a warning level 0 to the angel bracket includes; #include <file>.

With the clang-cl with MSVC you can use -imsvc.

+
tip

On Linux -isystem marks the directory as a system directory, it prevents warnings.

On Windows you can use QMAKE_CXXFLAGS_WARN_ON = -external:anglebrackets -external:W0, it applies a warning level 0 to the angel bracket includes; #include <file>.

With the Clang-cl with MSVC you can use -imsvc.

Auto-configuration internals

The qmake build system does not support auto-configuration of dependencies out of the box but TinyORM from v0.34.0 added its own Auto-configuration feature along with the tiny_dotenv qmake feature. These new features allow us to auto-configure TinyORM project, and with their help, the conf.pri files can be skipped entirely.

While it adds additional complexity to the qmake configuration process, the benefits are significant.

diff --git a/database/getting-started.html b/database/getting-started.html index d89e5efa2..b3ab7c7f3 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 270510a72..7c515878a 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 042ed3f9a..af1d11256 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 b63156ac8..38bbdc123 100644 --- a/database/seeding.html +++ b/database/seeding.html @@ -14,7 +14,7 @@ - + diff --git a/dependencies.html b/dependencies.html index 080ff11d4..ab3842932 100644 --- a/dependencies.html +++ b/dependencies.html @@ -14,7 +14,7 @@ - + diff --git a/features-summary.html b/features-summary.html index 77265958b..4764ab0e5 100644 --- a/features-summary.html +++ b/features-summary.html @@ -14,7 +14,7 @@ - + diff --git a/index.html b/index.html index 81b7a0b5f..30c9fb91a 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@ - + diff --git a/search.html b/search.html index 41624e9e8..ad0678aa1 100644 --- a/search.html +++ b/search.html @@ -14,7 +14,7 @@ - + diff --git a/sponsors.html b/sponsors.html index 1648a02d2..0dd179467 100644 --- a/sponsors.html +++ b/sponsors.html @@ -14,7 +14,7 @@ - + diff --git a/supported-compilers.html b/supported-compilers.html index 780fdab6f..281de8eed 100644 --- a/supported-compilers.html +++ b/supported-compilers.html @@ -14,7 +14,7 @@ - + @@ -25,7 +25,7 @@
  • MSVC 2022 >=17
  • MSYS2 UCRT64 GCC 10.2 - 14.1
  • MSYS2 UCRT64 Clang >=15
  • -
  • clang-cl >=15 with MSVC 2019/2022
  • +
  • Clang-cl >=15 with MSVC 2019/2022
  • Linux

    • GCC 10.2 - 14.1
    • Clang >=15 (libstdc++ only)
    • diff --git a/tinydrivers/getting-started.html b/tinydrivers/getting-started.html index 3bb921449..c90420533 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 d818da71c..8af519f6e 100644 --- a/tinyorm/casts.html +++ b/tinyorm/casts.html @@ -14,7 +14,7 @@ - + @@ -91,8 +91,8 @@

      Attr
      info

      Attributes that are null will also be cast so that the QVariant's internal type will have the correct type.

      Date Casting

      By default, TinyORM will cast the created_at and updated_at columns to instances of QDateTime. You may cast additional date attributes by defining additional date casts within your model's u_casts static data member unordered map. Typically, dates should be cast using the CastType::QDateTime, CastType::QDate, or CastType::Timestamp cast types.

      -

      When a database column is of the date type, you may set the corresponding model attribute value to a UNIX timestamp, date string (Y-m-d), date-time string, QDate, or QDateTime instance. The date's value will be correctly converted and stored in your database.
      -The same is true for the datetime or timestamp database column types, you can set the corresponding model attribute value to a UNIX timestamp, date-time string, or a QDateTime instance.

      +

      When a database column is of the date type, you may set the corresponding model attribute value to a Unix timestamp, date string (Y-m-d), date-time string, QDate, or QDateTime instance. The date's value will be correctly converted and stored in your database.
      +The same is true for the datetime or timestamp database column types, you can set the corresponding model attribute value to a Unix timestamp, date-time string, or a QDateTime instance.

      When defining the CastType::QDate or CastType::QDateTime cast, you may also specify the date's format. In this case you must use the CastType::CustomQDate or CastType::CustomQDateTime cast types. This format will be used when the model is serialized to a vector, map, or JSON:

      /*! The attributes that should be cast. */
      inline static std::unordered_map<QString, CastItem> u_casts {
      {"created_at", {CastType::CustomQDateTime, "yyyy-MM-dd"}},
      };
      note

      The CastType::CustomQDate and CastType::CustomQDateTime cast types behave exactly like the CastType::QDate and CastType::QDateTime cast types with the additional date's format functionality during serialization.

      @@ -100,7 +100,7 @@

      Date Cast
      /*! Prepare a date for vector, map, or JSON serialization. */
      QString serializeDate(const QDate date)
      {
      return date.toString("yyyy-MM-dd");
      }

      /*! Prepare a datetime for vector, map, or JSON serialization. */
      QString serializeDateTime(const QDateTime &datetime)
      {
      return datetime.toUTC().toString("yyyy-MM-ddTHH:mm:ssZ");
      }

      To specify the format that should be used when actually storing a model's dates within your database, you should define a u_dateFormat data member on your model:

      /*! The storage format of the model's date columns. */
      inline static QString u_dateFormat {QLatin1Char('U')};
      -

      This format can be any format that the QDateTime's fromString or toString methods accept or the special U format that represents the UNIX timestamp (this U format is TinyORM-specific and isn't supported by QDateTime).

      +

      This format can be any format that the QDateTime's fromString or toString methods accept or the special U format that represents the Unix timestamp (this U format is TinyORM-specific and isn't supported by QDateTime).

      Define a u_timeFormat data member on your model to specify the format that should be used when storing a model's times within your database:

      /*! The storage format of the model's time columns. */
      inline static QString u_timeFormat {"HH:mm:ss.zzz"};

      Date Casting, Serialization & Timezones

      diff --git a/tinyorm/collections.html b/tinyorm/collections.html index b36d3c86d..bfb34e375 100644 --- a/tinyorm/collections.html +++ b/tinyorm/collections.html @@ -14,7 +14,7 @@ - + diff --git a/tinyorm/getting-started.html b/tinyorm/getting-started.html index 4ebaaf719..6fc8a498f 100644 --- a/tinyorm/getting-started.html +++ b/tinyorm/getting-started.html @@ -14,7 +14,7 @@ - + @@ -108,10 +108,10 @@

      Timestamps<
      /*! The storage format of the model's time columns. */
      QString u_timeFormat {"HH:mm:ss.zzz"};

      The default value for datetime or timestamp columns is yyyy-MM-dd HH:mm:ss and for time columns is HH:mm:ss.

      Unix timestamps
      -

      You can set the u_dateFormat to U if you want to store dates in the database as unix timestamps:

      +

      You can set the u_dateFormat to U if you want to store dates in the database as Unix timestamps:

      QString u_dateFormat {QLatin1Char('U')};
      -

      In this case all date attributes set in the u_dates will be handled as unix timestamps, so also the created_at and updated_at timestamp attributes.

      -

      To create unix timestamp columns using the tom migrations you should use integer types:

      +

      In this case all date attributes set in the u_dates will be handled as Unix timestamps, so also the created_at and updated_at timestamp attributes.

      +

      To create Unix timestamp columns using the tom migrations you should use integer types:

      Schema::table("flights", [](Blueprint &table)
      {
      table.bigInteger("created_at").nullable();
      table.bigInteger("updated_at").nullable();
      });
      Custom timestamp column names

      If you need to customize the names of the columns used to store the timestamps, you may define CREATED_AT and UPDATED_AT private static getter methods on your model:

      diff --git a/tinyorm/relationships.html b/tinyorm/relationships.html index aa861493a..39b0b45f3 100644 --- a/tinyorm/relationships.html +++ b/tinyorm/relationships.html @@ -14,7 +14,7 @@ - + diff --git a/tinyorm/serialization.html b/tinyorm/serialization.html index 01df9e29a..1d234ce8b 100644 --- a/tinyorm/serialization.html +++ b/tinyorm/serialization.html @@ -14,7 +14,7 @@ - +