diff --git a/404.html b/404.html index 3621bc37b..fa6180487 100644 --- a/404.html +++ b/404.html @@ -1,9 +1,9 @@ - + - -Page Not Found - TinyORM + +TinyORM @@ -13,14 +13,11 @@ - - - + + + -
-
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

\ No newline at end of file diff --git a/assets/css/styles.21a15f53.css b/assets/css/styles.21a15f53.css new file mode 100644 index 000000000..bb90f8d36 --- /dev/null +++ b/assets/css/styles.21a15f53.css @@ -0,0 +1 @@ +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}#apitable-sponsors table,pre code{font-size:100%}#tinyorm-configuration input,.button,code{vertical-align:middle}*,.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#25c2a0;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#46cbae;--ifm-color-primary-lighter:#66d4bd;--ifm-color-primary-lightest:#92e0d0;--ifm-font-size-base:1.1rem;--ifm-code-font-size:86%;--ifm-pre-line-height:var(--ifm-line-height-base);--doc-sidebar-width:14rem!important;--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*1.4);--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 1px 0 #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base);--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading));--ifm-h2-font-size:1.8rem}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){-webkit-text-decoration:none;text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.apitable-build-options td:nth-child(2),.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}#tinyorm-configuration .tinyorm-configuration-row,.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.badge,.markdown h1+ul li li li a:before{font-size:75%}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);-webkit-text-decoration:none;text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}#apitable-c-macros td:first-child,.apitable-build-options td:nth-child(-n+2),.dropdown{vertical-align:top}.button,.button:hover{color:var(--ifm-button-color)}#casts-types-list li>code,#supported-compilers>h4>code,.button--link,.collection-methods>h4>code,.tom-column-types>h4>code{color:var(--ifm-link-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.DocSearch-Container a,.dropdown__link--active,.dropdown__link:hover,.hash-link:active,.hash-link:hover,.menu__link:hover,.navbar__brand:hover,.navbar__link--active,.navbar__link:hover,.pagination-nav__link:hover,.pagination__link:hover,.tag_zVej:hover{-webkit-text-decoration:none;text-decoration:none}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}#databases-supported-versions ul ul,.dropdown__link{margin-top:.2rem}.table-of-contents{margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);-webkit-text-decoration:none;text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color)}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_BuS1>:last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items,.markdown h1+ul li li:last-child ul,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color)}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color)}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color)}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.hash-link:link,.hash-link:visited,.markdown h1+ul li a:before{color:var(--ifm-color-info-darker)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover)}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-key-pressed-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 1px 1px 0 rgba(3,4,9,.302);--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]:root{--ifm-background-color:#0d1117;--ifm-background-surface-color:#161b22;--ifm-toc-border-color:#30363d;--ifm-code-background:#ffffff26;--docusaurus-highlighted-code-line-bg:#30323f;--ifm-footer-background-color:var(--ifm-background-color);--docsearch-key-gradient:linear-gradient(-26.5deg,var(--ifm-color-emphasis-200) 0%,var(--ifm-color-emphasis-100) 100%);--docsearch-text-color:var(--ifm-color-emphasis-700);--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.darker{color:#888}[data-theme=dark] ::-webkit-scrollbar{background-color:#222526;height:14px;width:14px}[data-theme=dark] ::-webkit-scrollbar-thumb{background-color:#555;border-radius:2px}[data-theme=dark] ::-webkit-scrollbar-thumb:hover{background-color:#777}[data-theme=dark] body{scrollbar-color:#777 #222526!important;scrollbar-width:14px}h1{--ifm-h1-font-size:2.1rem!important;font-size:var(--ifm-h1-font-size)}.header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat;content:"";display:flex;height:24px;width:24px}[data-theme=dark] .header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.menu__link{font-size:.9rem}.menu__list-item .menu__list-item{padding-left:1.3rem}.markdown h1+ul,.markdown h1+ul ul{list-style-type:none}.markdown h1+ul li a{font-weight:700}.markdown h1+ul li li a{font-weight:400}.markdown h1+ul li a:before{content:"# ";font-size:90%}.markdown h1+ul li li a:before{font-size:80%}.markdown h1+ul ul ul{margin-bottom:-.25rem;padding-left:1rem}#databases-supported-versions ul ul li a,.markdown h1+ul li li li a{font-size:95%}.footer{padding-bottom:.8rem;padding-top:.4rem}#databases-supported-versions ul ul li{font-size:90%;line-height:1.35}.docusaurus-highlight-code-line{background-color:#0000001a;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}html[data-theme=dark] .docusaurus-highlight-code-line{background-color:#0000004d}html[data-theme=dark] .prism-code{background-color:#20222b!important}img.no-blurry{will-change:transform}.prism-code .token{font-style:inherit!important}.table-of-contents{font-size:.7rem}main>.container>.row>.col:last-child>div[class^=tableOfContents_]{transition:top .2s}nav[class*=navbarHidden_]~.main-wrapper main>.container>.row>.col:last-child>div[class^=tableOfContents_]{top:1rem}#apitable-dropping-indexes th:last-child{width:50%}#apitable-dropping-indexes td:first-child{font-size:90%;overflow-wrap:anywhere}#tinyorm-configuration,.tiny-tree{position:relative}.tiny-root-folder-info-wrapper{left:15px;position:absolute;top:13px;z-index:10}.tiny-root-folder-info-wrapper .tiny-root-folder-info-prefix{color:var(--ifm-color-warning-lighter)}html[data-theme=dark] .tiny-root-folder-info-wrapper .tiny-root-folder-info-prefix{color:var(--ifm-color-warning-lightest)}.collection-methods-list>p,.tom-column-types-list>p{column-count:3;column-gap:2em}.collection-methods-list a,.tom-column-types-list a{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#supported-compilers>h4,.collection-methods>h4,.loader_vvXV,.tom-column-types>h4{margin-top:2rem}#supported-compilers{margin-bottom:2rem}#casts-types-list{font-size:92%}#tinyorm-configuration form{position:absolute;right:0;top:1em}#tinyorm-configuration label{color:#bbb;font-family:var(--ifm-font-family-base);font-size:.7rem;vertical-align:text-bottom}#tinyorm-configuration>div:last-child{display:none}.apiTable_flxF{font-size:94%}.apiTable_flxF tbody tr{transition:box-shadow .2s}.apiTable_flxF tbody tr:focus,.apiTable_flxF tbody tr:hover{box-shadow:0 0 4.5px 0 inset var(--ifm-color-warning);cursor:pointer;outline:0;transition:box-shadow .1s}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.lastUpdated_JAkA{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.DocSearch-Button,.DocSearch-Button-Container{align-items:center;display:flex}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}.DocSearch-Button{background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch-Button-Key--pressed{box-shadow:var(--docsearch-key-pressed-shadow);transform:translate3d(0,1px,0)}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Hit[aria-selected=true] mark,.DocSearch-Prefill:focus,.DocSearch-Prefill:hover,.content_knG7 a{-webkit-text-decoration:underline;text-decoration:underline}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards a;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}#__docusaurus-base-url-issue-banner-container,.docSidebarContainer_YfHR,.navbarSearchContainer_Bca1:empty,.sidebarLogo_isFc,.themedComponent_mlkZ,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j,svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.DocSearch-VisuallyHiddenForAccessibility{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}@keyframes a{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container{z-index:calc(var(--ifm-z-index-fixed) + 1)}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.rootFolderInput_ottS{left:13px;position:absolute;top:56px;z-index:10}.rootFolderInput_ottS .input_OR7e{background-color:#ffffff1f;border-color:#303436;width:16rem}.rootFolderInput_ottS.application_fjej{left:48px;top:87px}.input_OR7e{border-color:var(--ifm-color-content-secondary);border-radius:2px;border-style:solid;border-width:var(--ifm-global-border-width);font-size:calc(var(--ifm-font-size-base)/1.1);padding:.2rem .4rem}.input_OR7e.application_fjej{width:14rem}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}.collapseSidebarButton_PEFL{display:none;margin:0}.iconExternalLink_nPIU{margin-left:.3rem}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}.dropdownNavbarItemMobile_S0Fm{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_mC6p{list-style:none}.img_ev3q{height:auto}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.searchQueryInput_u2C7,.searchVersionInput_m0Ui{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_u2C7:focus,.searchVersionInput_m0Ui:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_u2C7::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_JPFH{font-size:.9rem;font-weight:700}.algoliaLogo_rT1R{max-width:150px}.algoliaLogoPathFill_WdUC{fill:var(--ifm-font-color-base)}.searchResultItem_Tv2o{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_KbCB{font-weight:400;margin-bottom:0}.searchResultItemPath_lhe1{color:var(--ifm-color-content-secondary);font-size:.8rem;--ifm-breadcrumb-separator-size-multiplier:1}.searchResultItemSummary_AEaO{font-style:italic;margin:.5rem 0 0}.loadingSpinner_XVxU{animation:1s linear infinite b;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes b{to{transform:rotate(1turn)}}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}.lastUpdated_JAkA{text-align:right}.tocMobile_ITEo{display:none}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);-webkit-text-decoration:none!important;text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.navbarSearchContainer_Bca1{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.docItemContainer_F8PC{padding:0 .3rem}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}}@media only screen and (max-width:996px){.searchQueryColumn_RTkw,.searchResultsColumn_JPFH{max-width:60%!important}.searchLogoColumn_rJIA,.searchVersionColumn_ypXd{max-width:40%!important}.searchLogoColumn_rJIA{padding-left:0!important}}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media screen and (max-width:768px){:root{--ifm-menu-link-padding-vertical:0.5rem;--ifm-list-item-margin:0.5rem}.menu__link{font-size:1.1rem}.markdown h1+ul li:first-child{margin-top:.25rem}.markdown h1+ul ul ul{margin-bottom:0}.markdown h1+ul li li li:first-child{margin-top:.5rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media screen and (max-width:576px){.searchQueryColumn_RTkw{max-width:100%!important}.searchVersionColumn_ypXd{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@media screen and (max-width:480px){.collection-methods-list>p,.tom-column-types-list>p{column-count:2}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar,[data-theme=dark] .thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}[data-theme=dark] .thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{animation:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0;stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/css/styles.a9c8f337.css b/assets/css/styles.a9c8f337.css deleted file mode 100644 index 76e808c1d..000000000 --- a/assets/css/styles.a9c8f337.css +++ /dev/null @@ -1 +0,0 @@ -.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,.hash-link{-webkit-user-select:none}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}#tinyorm-configuration input,.button,code{vertical-align:middle}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}*,.DocSearch-Container,.DocSearch-Container *{box-sizing:border-box}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--doc-sidebar-width:14rem!important;--ifm-color-primary:#25c2a0;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#46cbae;--ifm-color-primary-lighter:#66d4bd;--ifm-color-primary-lightest:#92e0d0;--ifm-font-size-base:1.1rem;--ifm-code-font-size:86%;--ifm-pre-line-height:var(--ifm-line-height-base);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*1.4);--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docsearch-primary-color:#5468ff;--docsearch-text-color:#1c1e21;--docsearch-spacing:12px;--docsearch-icon-stroke-width:1.4;--docsearch-highlight-color:var(--docsearch-primary-color);--docsearch-muted-color:#969faf;--docsearch-container-background:#656c85cc;--docsearch-logo-color:#5468ff;--docsearch-modal-width:560px;--docsearch-modal-height:600px;--docsearch-modal-background:#f5f6f7;--docsearch-modal-shadow:inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64;--docsearch-searchbox-height:56px;--docsearch-searchbox-background:#ebedf0;--docsearch-searchbox-focus-background:#fff;--docsearch-searchbox-shadow:inset 0 0 0 2px var(--docsearch-primary-color);--docsearch-hit-height:56px;--docsearch-hit-color:#444950;--docsearch-hit-active-color:#fff;--docsearch-hit-background:#fff;--docsearch-hit-shadow:0 1px 3px 0 #d4d9e1;--docsearch-key-gradient:linear-gradient(-225deg,#d5dbe4,#f8f8f8);--docsearch-key-shadow:inset 0 -2px 0 0 #cdcde6,inset 0 0 1px 1px #fff,0 1px 2px 1px #1e235a66;--docsearch-footer-height:44px;--docsearch-footer-background:#fff;--docsearch-footer-shadow:0 -1px 0 0 #e0e3e8,0 -3px 6px 0 #45629b1f;--docsearch-primary-color:var(--ifm-color-primary);--docsearch-text-color:var(--ifm-font-color-base)}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading));--ifm-h2-font-size:1.8rem}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){-webkit-text-decoration:none;text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.apitable-build-options td:nth-child(2),.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}#tinyorm-configuration .tinyorm-configuration-row,.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_tbUL,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.badge,.markdown h1+ul li li li a:before{font-size:75%}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);-webkit-text-decoration:none;text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;user-select:none;white-space:nowrap}.apitable-build-options td:nth-child(-n+2),.dropdown{vertical-align:top}.button,.button:hover{color:var(--ifm-button-color)}#casts-types-list li>code,#supported-compilers>h4>code,.button--link,.collection-methods>h4>code,.tom-column-types>h4>code{color:var(--ifm-link-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.dropdown__link--active,.dropdown__link:hover,.hash-link:active,.hash-link:hover,.menu__link:hover,.navbar__brand:hover,.navbar__link--active,.navbar__link:hover,.pagination-nav__link:hover,.pagination__link:hover{-webkit-text-decoration:none;text-decoration:none}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}#databases-supported-versions ul ul,.dropdown__link{margin-top:.2rem}.table-of-contents{margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);-webkit-text-decoration:none;text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color)}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_S0QG>:last-child,.collapsibleContent_i85q>:last-child,.footer__items,.markdown h1+ul li li:last-child ul,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color)}.menu__caret:before,.menu__link--sublist-caret:after{height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter);content:""}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color)}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color)}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);position:fixed;transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;position:fixed;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.hash-link:link,.hash-link:visited,.markdown h1+ul li a:before{color:var(--ifm-color-info-darker)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover)}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--docsearch-text-color:#f5f6f7;--docsearch-container-background:#090a11cc;--docsearch-modal-background:#15172a;--docsearch-modal-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--docsearch-searchbox-background:#090a11;--docsearch-searchbox-focus-background:#000;--docsearch-hit-color:#bec3c9;--docsearch-hit-shadow:none;--docsearch-hit-background:#090a11;--docsearch-key-gradient:linear-gradient(-26.5deg,#565872,#31355b);--docsearch-key-shadow:inset 0 -2px 0 0 #282d55,inset 0 0 1px 1px #51577d,0 2px 2px 0 #0304094d;--docsearch-footer-background:#1e2136;--docsearch-footer-shadow:inset 0 1px 0 0 #494c6a80,0 -4px 8px 0 #0003;--docsearch-logo-color:#fff;--docsearch-muted-color:#7f8497}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]:root{--ifm-background-color:#0d1117;--ifm-background-surface-color:#161b22;--ifm-toc-border-color:#30363d;--ifm-code-background:#ffffff26;--docusaurus-highlighted-code-line-bg:#30323f;--ifm-footer-background-color:var(--ifm-background-color);--docsearch-key-gradient:linear-gradient(-26.5deg,var(--ifm-color-emphasis-200) 0%,var(--ifm-color-emphasis-100) 100%);--docsearch-text-color:var(--ifm-color-emphasis-700);--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.darker{color:#888}[data-theme=dark] ::-webkit-scrollbar{background-color:#222526;height:14px;width:14px}[data-theme=dark] ::-webkit-scrollbar-thumb{background-color:#555;border-radius:2px}[data-theme=dark] ::-webkit-scrollbar-thumb:hover{background-color:#777}[data-theme=dark] body{scrollbar-color:#777 #222526!important;scrollbar-width:14px}h1{--ifm-h1-font-size:2.1rem!important;font-size:var(--ifm-h1-font-size)}.header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat;content:"";display:flex;height:24px;width:24px}[data-theme=dark] .header-github-link:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.menu__link{font-size:.9rem}.menu__list-item .menu__list-item{padding-left:1.3rem}.markdown h1+ul,.markdown h1+ul ul{list-style-type:none}.markdown h1+ul li a{font-weight:700}.markdown h1+ul li li a{font-weight:400}.markdown h1+ul li a:before{content:"# ";font-size:90%}.markdown h1+ul li li a:before{font-size:80%}.markdown h1+ul ul ul{margin-bottom:-.25rem;padding-left:1rem}#databases-supported-versions ul ul li a,.markdown h1+ul li li li a{font-size:95%}.footer{padding-bottom:.8rem;padding-top:.4rem}#databases-supported-versions ul ul li{font-size:90%;line-height:1.35}.docusaurus-highlight-code-line{background-color:#0000001a;display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}html[data-theme=dark] .docusaurus-highlight-code-line{background-color:#0000004d}html[data-theme=dark] .prism-code{background-color:#20222b!important}img.no-blurry{will-change:transform}.prism-code .token{font-style:inherit!important}.table-of-contents{font-size:.7rem}main>.container>.row>.col:last-child>div[class^=tableOfContents_]{transition:top .2s}nav[class*=navbarHidden_]~.main-wrapper main>.container>.row>.col:last-child>div[class^=tableOfContents_]{top:1rem}#apitable-dropping-indexes,.apitable-build-options{font-size:94%}#apitable-c-macros td:first-child{font-size:94%;vertical-align:top}#apitable-dropping-indexes th:last-child{width:50%}#apitable-dropping-indexes td:first-child{word-wrap:anywhere;font-size:90%}#tinyorm-configuration,.tiny-tree{position:relative}.tiny-root-folder-info-wrapper{left:15px;position:absolute;top:13px;z-index:10}.tiny-root-folder-info-wrapper .tiny-root-folder-info-prefix{color:var(--ifm-color-warning-lighter)}html[data-theme=dark] .tiny-root-folder-info-wrapper .tiny-root-folder-info-prefix{color:var(--ifm-color-warning-lightest)}.collection-methods-list>p,.tom-column-types-list>p{column-count:3;column-gap:2em}.collection-methods-list a,.tom-column-types-list a{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#supported-compilers>h4,.collection-methods>h4,.loader_vvXV,.tom-column-types>h4{margin-top:2rem}#supported-compilers{margin-bottom:2rem}#casts-types-list{font-size:92%}#tinyorm-configuration form{position:absolute;right:0;top:1em}#tinyorm-configuration label{color:#bbb;font-family:var(--ifm-font-family-base);font-size:.7rem;vertical-align:text-bottom}#__docusaurus-base-url-issue-banner-container,#tinyorm-configuration>div:last-child,.themedImage_ToTc,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;-webkit-text-decoration:underline;text-decoration:underline}.DocSearch-Container a,.tag_zVej:hover{-webkit-text-decoration:none;text-decoration:none}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedImage--dark_i4oU,[data-theme=light] .themedImage--light_HNdA,html:not([data-theme]) .themedComponent--light_NU7w{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.apiTable_flxF tbody tr{transition:box-shadow .2s}.apiTable_flxF tbody tr:focus,.apiTable_flxF tbody tr:hover{box-shadow:0 0 4.5px 0 inset var(--ifm-color-warning);cursor:pointer;outline:0;transition:box-shadow .1s}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.DocSearch-Hit[aria-selected=true] mark,.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{-webkit-text-decoration:underline;text-decoration:underline}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);user-select:none}.hash-link:before{content:"#"}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{word-wrap:normal;background:var(--ifm-pre-background);display:table-cell;left:0;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.rootFolderInput_ottS{left:13px;position:absolute;top:56px;z-index:10}.rootFolderInput_ottS .input_OR7e{background-color:#ffffff1f;border-color:#303436;width:16rem}.rootFolderInput_ottS.application_fjej{left:48px;top:87px}.input_OR7e{border-color:var(--ifm-color-content-secondary);border-radius:2px;border-style:solid;border-width:var(--ifm-global-border-width);font-size:calc(var(--ifm-font-size-base)/1.1);padding:.2rem .4rem}.input_OR7e.application_fjej{width:14rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_mC6p{list-style:none}.img_ev3q{height:auto}.admonition_LlT9{margin-bottom:1em}.admonitionHeading_tbUL{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.3rem}.admonitionHeading_tbUL code{text-transform:none}.admonitionIcon_kALy{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_kALy svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.searchQueryInput_u2C7,.searchVersionInput_m0Ui{background:var(--docsearch-searchbox-focus-background);border:2px solid var(--ifm-toc-border-color);border-radius:var(--ifm-global-radius);color:var(--docsearch-text-color);font:var(--ifm-font-size-base) var(--ifm-font-family-base);margin-bottom:.5rem;padding:.8rem;transition:border var(--ifm-transition-fast) ease;width:100%}.searchQueryInput_u2C7:focus,.searchVersionInput_m0Ui:focus{border-color:var(--docsearch-primary-color);outline:0}.searchQueryInput_u2C7::placeholder{color:var(--docsearch-muted-color)}.searchResultsColumn_JPFH{font-size:.9rem;font-weight:700}.algoliaLogo_rT1R{max-width:150px}.algoliaLogoPathFill_WdUC{fill:var(--ifm-font-color-base)}.searchResultItem_Tv2o{border-bottom:1px solid var(--ifm-toc-border-color);padding:1rem 0}.searchResultItemHeading_KbCB{font-weight:400;margin-bottom:0}.searchResultItemPath_lhe1{--ifm-breadcrumb-separator-size-multiplier:1;color:var(--ifm-color-content-secondary);font-size:.8rem}.searchResultItemSummary_AEaO{font-style:italic;margin:.5rem 0 0}.loadingSpinner_XVxU{animation:1s linear infinite a;border:.4em solid #eee;border-radius:50%;border-top:.4em solid var(--ifm-color-primary);height:3rem;margin:0 auto;width:3rem}@keyframes a{to{transform:rotate(1turn)}}.search-result-match{background:#ffd78e40;color:var(--docsearch-hit-color);padding:.09em 0}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}.collapseSidebarButton_PEFL{display:none;margin:0}.docSidebarContainer_b6E3,.sidebarLogo_isFc{display:none}.docMainContainer_gTbr,.docPage__5DB{display:flex;width:100%}.docPage__5DB{flex:1 0}.docsWrapper_BCFX{display:flex;flex:1 0 auto}.DocSearch-Button,.DocSearch-Button-Container{align-items:center;display:flex}.DocSearch-Button{background:var(--docsearch-searchbox-background);border:0;border-radius:40px;color:var(--docsearch-muted-color);cursor:pointer;font-weight:500;height:36px;justify-content:space-between;padding:0 8px;-webkit-user-select:none;user-select:none}.DocSearch-Button:active,.DocSearch-Button:focus,.DocSearch-Button:hover{background:var(--docsearch-searchbox-focus-background);box-shadow:var(--docsearch-searchbox-shadow);color:var(--docsearch-text-color);outline:0}.DocSearch-Search-Icon{stroke-width:1.6}.DocSearch-Hit-Tree,.DocSearch-Hit-action,.DocSearch-Hit-icon,.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width)}.DocSearch-Button .DocSearch-Search-Icon{color:var(--docsearch-text-color)}.DocSearch-Button-Placeholder{font-size:1rem;padding:0 12px 0 6px}.DocSearch-Button-Keys{display:flex;min-width:calc(40px + .8em)}.DocSearch-Button-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:3px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 2px;position:relative;top:-1px;width:20px}.DocSearch--active{overflow:hidden!important}.DocSearch-Container{background-color:var(--docsearch-container-background);height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:200}.DocSearch-Link{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;font:inherit;margin:0;padding:0}.DocSearch-Modal{background:var(--docsearch-modal-background);border-radius:6px;box-shadow:var(--docsearch-modal-shadow);flex-direction:column;margin:60px auto auto;max-width:var(--docsearch-modal-width);position:relative}.DocSearch-SearchBar{display:flex;padding:var(--docsearch-spacing) var(--docsearch-spacing) 0}.DocSearch-Form{align-items:center;background:var(--docsearch-searchbox-focus-background);border-radius:4px;box-shadow:var(--docsearch-searchbox-shadow);display:flex;height:var(--docsearch-searchbox-height);margin:0;padding:0 var(--docsearch-spacing);position:relative;width:100%}.DocSearch-Input{appearance:none;background:#0000;border:0;color:var(--docsearch-text-color);flex:1;font:inherit;font-size:1.2em;height:100%;outline:0;padding:0 0 0 8px;width:80%}.DocSearch-Input::placeholder{color:var(--docsearch-muted-color);opacity:1}.DocSearch-Input::-webkit-search-cancel-button,.DocSearch-Input::-webkit-search-decoration,.DocSearch-Input::-webkit-search-results-button,.DocSearch-Input::-webkit-search-results-decoration{display:none}.DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{margin:0;padding:0}.DocSearch-Container--Stalled .DocSearch-LoadingIndicator,.DocSearch-MagnifierLabel,.DocSearch-Reset{align-items:center;color:var(--docsearch-highlight-color);display:flex;justify-content:center}.DocSearch-Cancel,.DocSearch-Container--Stalled .DocSearch-MagnifierLabel,.DocSearch-LoadingIndicator,.DocSearch-Reset[hidden]{display:none}.DocSearch-Reset{animation:.1s ease-in forwards b;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;padding:2px;right:0}.DocSearch-Help,.DocSearch-HitsFooter,.DocSearch-Label{color:var(--docsearch-muted-color)}.DocSearch-Reset:hover{color:var(--docsearch-highlight-color)}.DocSearch-LoadingIndicator svg,.DocSearch-MagnifierLabel svg{height:24px;width:24px}.DocSearch-Dropdown{max-height:calc(var(--docsearch-modal-height) - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height));min-height:var(--docsearch-spacing);overflow-y:auto;overflow-y:overlay;padding:0 var(--docsearch-spacing);scrollbar-color:var(--docsearch-muted-color) var(--docsearch-modal-background);scrollbar-width:thin}.DocSearch-Dropdown::-webkit-scrollbar{width:12px}.DocSearch-Dropdown::-webkit-scrollbar-track{background:#0000}.DocSearch-Dropdown::-webkit-scrollbar-thumb{background-color:var(--docsearch-muted-color);border:3px solid var(--docsearch-modal-background);border-radius:20px}.DocSearch-Dropdown ul{list-style:none;margin:0;padding:0}.DocSearch-Label{font-size:.75em;line-height:1.6em}.DocSearch-Help{font-size:.9em;margin:0;-webkit-user-select:none;user-select:none}.DocSearch-Title{font-size:1.2em}.DocSearch-Logo a{display:flex}.DocSearch-Logo svg{color:var(--docsearch-logo-color);margin-left:8px}.DocSearch-Hits:last-of-type{margin-bottom:24px}.DocSearch-Hits mark{background:none;color:var(--docsearch-highlight-color)}.DocSearch-HitsFooter{display:flex;font-size:.85em;justify-content:center;margin-bottom:var(--docsearch-spacing);padding:var(--docsearch-spacing)}.DocSearch-HitsFooter a{border-bottom:1px solid;color:inherit}.DocSearch-Hit{border-radius:4px;display:flex;padding-bottom:4px;position:relative}.DocSearch-Hit--deleting{opacity:0;transition:.25s linear}.DocSearch-Hit--favoriting{transform:scale(0);transform-origin:top center;transition:.25s linear .25s}.DocSearch-Hit a{background:var(--docsearch-hit-background);border-radius:4px;box-shadow:var(--docsearch-hit-shadow);display:block;padding-left:var(--docsearch-spacing);width:100%}.DocSearch-Hit-source{background:var(--docsearch-modal-background);color:var(--docsearch-highlight-color);font-size:.85em;font-weight:600;line-height:32px;margin:0 -4px;padding:8px 4px 0;position:sticky;top:0;z-index:10}.DocSearch-Hit-Tree{color:var(--docsearch-muted-color);height:var(--docsearch-hit-height);opacity:.5;width:24px}.DocSearch-Hit[aria-selected=true] a{background-color:var(--docsearch-highlight-color)}.DocSearch-Hit-Container{align-items:center;color:var(--docsearch-hit-color);display:flex;flex-direction:row;height:var(--docsearch-hit-height);padding:0 var(--docsearch-spacing) 0 0}.DocSearch-Hit-icon{height:20px;width:20px}.DocSearch-Hit-action,.DocSearch-Hit-icon{color:var(--docsearch-muted-color)}.DocSearch-Hit-action{align-items:center;display:flex;height:22px;width:22px}.DocSearch-Hit-action svg{display:block;height:18px;width:18px}.DocSearch-Hit-action+.DocSearch-Hit-action{margin-left:6px}.DocSearch-Hit-action-button{appearance:none;background:none;border:0;border-radius:50%;color:inherit;cursor:pointer;padding:2px}svg.DocSearch-Hit-Select-Icon{display:none}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Select-Icon{display:block}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:background-color .1s ease-in}.DocSearch-Hit-action-button:focus path,.DocSearch-Hit-action-button:hover path{fill:#fff}.DocSearch-Hit-content-wrapper{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;line-height:1.2em;margin:0 8px;overflow-x:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap;width:80%}.DocSearch-Hit-title{font-size:.9em}.DocSearch-Hit-path{color:var(--docsearch-muted-color);font-size:.75em}.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-Tree,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-action,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-icon,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-path,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-text,.DocSearch-Hit[aria-selected=true] .DocSearch-Hit-title,.DocSearch-Hit[aria-selected=true] mark{color:var(--docsearch-hit-active-color)!important}.DocSearch-ErrorScreen,.DocSearch-NoResults,.DocSearch-StartScreen{font-size:.9em;margin:0 auto;padding:36px 0;text-align:center;width:80%}.DocSearch-Screen-Icon{color:var(--docsearch-muted-color);padding-bottom:12px}.DocSearch-NoResults-Prefill-List{display:inline-block;padding-bottom:24px;text-align:left}.DocSearch-NoResults-Prefill-List ul{display:inline-block;padding:8px 0 0}.DocSearch-NoResults-Prefill-List li{list-style-position:inside;list-style-type:"» "}.DocSearch-Prefill{appearance:none;background:none;border:0;border-radius:1em;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;font-size:1em;font-weight:700;padding:0}.DocSearch-Prefill:focus,.DocSearch-Prefill:hover{outline:0}.DocSearch-Footer{align-items:center;background:var(--docsearch-footer-background);border-radius:0 0 8px 8px;box-shadow:var(--docsearch-footer-shadow);display:flex;flex-direction:row-reverse;flex-shrink:0;height:var(--docsearch-footer-height);justify-content:space-between;padding:0 var(--docsearch-spacing);position:relative;-webkit-user-select:none;user-select:none;width:100%;z-index:300}.DocSearch-Commands{color:var(--docsearch-muted-color);display:flex;list-style:none;margin:0;padding:0}.DocSearch-Commands li{align-items:center;display:flex}.DocSearch-Commands li:not(:last-of-type){margin-right:.8em}.DocSearch-Commands-Key{align-items:center;background:var(--docsearch-key-gradient);border:0;border-radius:2px;box-shadow:var(--docsearch-key-shadow);color:var(--docsearch-muted-color);display:flex;height:18px;justify-content:center;margin-right:.4em;padding:0 0 1px;width:20px}@keyframes b{0%{opacity:0}to{opacity:1}}.DocSearch-Button{margin:0;transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.DocSearch-Container{z-index:calc(var(--ifm-z-index-fixed) + 1)}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_m80_{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.searchBox_ZlJk{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_BlDH,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_m80_:focus,.expandButton_m80_:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);-webkit-text-decoration:none!important;text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_m80_{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_BlDH{transform:rotate(180deg)}.docSidebarContainer_b6E3{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_b3ry{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_Xe31{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_gTbr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_Uz_u{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_czyv{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.searchBox_ZlJk{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media only screen and (max-width:996px){.searchQueryColumn_RTkw,.searchResultsColumn_JPFH{max-width:60%!important}.searchLogoColumn_rJIA,.searchVersionColumn_ypXd{max-width:40%!important}.searchLogoColumn_rJIA{padding-left:0!important}}@media (max-width:768px){.DocSearch-Button-Keys,.DocSearch-Button-Placeholder,.DocSearch-Commands,.DocSearch-Hit-Tree{display:none}:root{--docsearch-spacing:10px;--docsearch-footer-height:40px}.DocSearch-Dropdown{height:100%;max-height:calc(var(--docsearch-vh,1vh)*100 - var(--docsearch-searchbox-height) - var(--docsearch-spacing) - var(--docsearch-footer-height))}.DocSearch-Container{height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);position:absolute}.DocSearch-Footer{border-radius:0;bottom:0;position:absolute}.DocSearch-Hit-content-wrapper{display:flex;position:relative;width:80%}.DocSearch-Modal{border-radius:0;box-shadow:none;height:100vh;height:-webkit-fill-available;height:calc(var(--docsearch-vh,1vh)*100);margin:0;max-width:100%;width:100%}.DocSearch-Cancel{appearance:none;background:none;border:0;color:var(--docsearch-highlight-color);cursor:pointer;display:inline-block;flex:none;font:inherit;font-size:1em;font-weight:500;margin-left:var(--docsearch-spacing);outline:0;overflow:hidden;padding:0;-webkit-user-select:none;user-select:none;white-space:nowrap}}@media screen and (max-width:768px){:root{--ifm-menu-link-padding-vertical:0.5rem;--ifm-list-item-margin:0.5rem}.menu__link{font-size:1.1rem}.markdown h1+ul li:first-child{margin-top:.25rem}.markdown h1+ul ul ul{margin-bottom:0}.markdown h1+ul li li li:first-child{margin-top:.5rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media screen and (max-width:576px){.searchQueryColumn_RTkw{max-width:100%!important}.searchVersionColumn_ypXd{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@media screen and (max-width:480px){.collection-methods-list>p,.tom-column-types-list>p{column-count:2}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar,[data-theme=dark] .thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}[data-theme=dark] .thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media screen and (prefers-reduced-motion:reduce){.DocSearch-Reset{stroke-width:var(--docsearch-icon-stroke-width);animation:none;appearance:none;background:none;border:0;border-radius:50%;color:var(--docsearch-icon-color);cursor:pointer;right:0}.DocSearch-Hit--deleting,.DocSearch-Hit--favoriting{transition:none}.DocSearch-Hit-action-button:focus,.DocSearch-Hit-action-button:hover{background:#0003;transition:none}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/js/0ab078a9.741e68ea.js b/assets/js/0ab078a9.741e68ea.js new file mode 100644 index 000000000..574acde00 --- /dev/null +++ b/assets/js/0ab078a9.741e68ea.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[395],{993:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>v,contentTitle:()=>T,default:()=>M,frontMatter:()=>y,metadata:()=>_,toc:()=>O});var s=i(4848),d=i(8453),r=i(6684),l=i(2364),c=i(9365),t=i(1470),o=i(5556),a=i.n(o),h=i(6694);function x(e){let{groupId:n}=e;return(0,s.jsx)("span",{children:(0,h.OZ)(n)})}x.propTypes={groupId:a().string.isRequired};const j=x;var u=i(4164),p=i(6362);const m={rootFolderInput:"rootFolderInput_ottS",input:"input_OR7e",application:"application_fjej"};function b(e){let{groupId:n,label:i}=e;const{rootFolder:d,setRootFolder:r}=(0,p.A)(),l=(0,h.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,u.A)(m.rootFolderInput,m[n],n),onSubmit:e=>{e.preventDefault(),e.stopPropagation()},children:(0,s.jsx)("input",{name:"tinyorm-root-folder-input",className:(0,u.A)(m.input,m[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,h.bw)(n)})})}b.propTypes={groupId:a().string.isRequired,label:a().string.isRequired};const f=b;var g=i(7324);const y={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"]},T="Building: TinyORM",_={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"}},v={},O=[{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 R(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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.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.0 usage...' -ForegroundColor Magenta\nWrite-Host\n\n$Script:QtRoot = $env:TINY_QT_ROOT ?? 'C:\\Qt'\n\n$env:Path = \"$Script:QtRoot\\6.7.0\\msvc2019_64\\bin;\" + $env:Path\n\n. vcvars64.ps1\n"})})}),(0,s.jsx)(c.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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:"qtenv6",label:"qtenv6",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'echo \'Setting up environment for Qt 6.7.0 usage...\'\n\nQtRoot="${TINY_QT_ROOT:-/opt/Qt}"\n\nexport PATH="$QtRoot/6.7.0/gcc_64/bin"${PATH:+:}$PATH\nexport LD_LIBRARY_PATH="$QtRoot/6.7.0/gcc_64/lib"${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH\n'})})}),(0,s.jsx)(c.A,{value:"qtenv5",label:"qtenv5",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'echo \'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.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)(t.A,{groupId:g.vf,children:[(0,s.jsxs)(c.A,{value:g.b,label:g.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)(j,{groupId:g.b})]})}),(0,s.jsx)(f,{groupId:g.b,label:g.ux}),(0,s.jsx)(f,{groupId:g.pW,label:g.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_0_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_0_MSVC2019_64bit-Debug/\n\u251c\u2500\u2500 tmp/\n\u2514\u2500\u2500 vcpkg/\n"})})]}),(0,s.jsxs)(c.A,{value:g.xj,label:g.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)(j,{groupId:g.xj})]})}),(0,s.jsx)(f,{groupId:g.xj,label:g.gg}),(0,s.jsx)(f,{groupId:g.pW,label:g.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_0_clang14_64bit_ccache-Debug/\n\u2502 \u2514\u2500\u2500 tom-builds-qmake/\n\u2502 \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_0_GCC_64bit-Debug/\n\u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_0_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)("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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`mkdir ${(0,h.Sn)(g.b)}\ncd ${(0,h.Sn)(g.b)}\n$env:Path = 'C:\\Qt\\6.7.0\\msvc2019_64\\bin;' + $env:Path\nvcvars64.ps1`})}),(0,s.jsx)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`mkdir -p ${(0,h.Sn)(g.xj)}\ncd ${(0,h.Sn)(g.xj)}\nexport PATH=/opt/Qt/6.7.0/gcc_64/bin\${PATH:+:}$PATH\nexport LD_LIBRARY_PATH=/opt/Qt/6.7.0/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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.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)(c.A,{value:g.xj,label:g.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)(l.A,{className:"language-bash",children:`export PATH=${(0,h.Sn)(g.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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`$env:Path = "${(0,h.Sn)(g.b,!1)}\\vcpkg;" + $env:Path`})}),(0,s.jsx)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`export PATH=${(0,h.Sn)(g.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)(r.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:"#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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`cd ${(0,h.Sn)(g.b)}\nmkdir ${(0,h.np)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,h.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})}),(0,s.jsx)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`cd ${(0,h.Sn)(g.xj)}\nmkdir -p ${(0,h.np)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,h.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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`cmake.exe \`\n-S "${(0,h.OZ)(g.b)}/TinyORM/TinyORM" \`\n-B "${(0,h.OZ)(g.b)}/TinyORM/TinyORM-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,h.Sn)(g.b)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,h.Sn)(g.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)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`cmake \\\n-S "${(0,h.OZ)(g.xj)}/TinyORM/TinyORM" \\\n-B "${(0,h.OZ)(g.xj)}/TinyORM/TinyORM-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,h.Sn)(g.xj)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,h.Sn)(g.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)(r.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)(r.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)(r.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)(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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:`cmake (${g.b})`,children:(0,s.jsx)(l.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,h.nC)(g.b,(0,h.OZ)(g.b))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,h.nC)(g.b,(0,h.Sn)(g.b))}/tmp/TinyORM")`})}),(0,s.jsx)(c.A,{value:g.xj,label:`cmake (${g.xj})`,children:(0,s.jsx)(l.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,h.nC)(g.xj,(0,h.OZ)(g.xj))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,h.nC)(g.xj,(0,h.Sn)(g.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)("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)(t.A,{groupId:g.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`$env:Path = "${(0,h.OZ)(g.b,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,h.OZ)(g.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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`cd ${(0,h.Sn)(g.b)}\nmkdir ${(0,h.np)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,h.np)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`})}),(0,s.jsx)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`cd ${(0,h.Sn)(g.xj)}\nmkdir -p ${(0,h.np)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,h.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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`cd ${(0,h.OZ)(g.b)}/TinyORM/TinyORM\n\ncp .env.win32.example .env.win32`})}),(0,s.jsx)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`cd ${(0,h.OZ)(g.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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`cd ${(0,h.OZ)(g.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)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`cd ${(0,h.OZ)(g.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)(r.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:"#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:"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 disables ",(0,s.jsx)(n.code,{children:"precompile_header"})," as they are not supported on Windows and changes the ",(0,s.jsx)(n.code,{children:"-Zi"})," compiler option to the ",(0,s.jsx)(n.code,{children:"-Z7"})," for debug builds as the ",(0,s.jsx)(n.code,{children:"-Zi"})," compiler option is not supported (",(0,s.jsx)(n.a,{href:"https://github.com/ccache/ccache/issues/1040",children:"link"})," to the issue)."]})]})]}),(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)(r.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)(r.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:"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 the ",(0,s.jsx)(n.code,{children:"g++"})," and ",(0,s.jsx)(n.code,{children:"clang++"})," and also supports precompiled headers."]})]})]}),(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_0_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_0)"}),"."]})]}),(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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.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_0_MSVC2019_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)\nLIBS += -lTinyOrm\n"})})}),(0,s.jsx)(c.A,{value:g.xj,label:g.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_0_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)(t.A,{groupId:g.vf,children:[(0,s.jsx)(c.A,{value:g.b,label:g.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)(c.A,{value:g.xj,label:g.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)(t.A,{groupId:g.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(c.A,{value:g.b,label:g.ux,children:(0,s.jsx)(l.A,{className:"language-powershell",children:`$env:Path = "${(0,h.OZ)(g.b,!1)}\\TinyORM\\TinyORM-builds-qmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(c.A,{value:g.xj,label:g.gg,children:(0,s.jsx)(l.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,h.OZ)(g.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.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.3/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.3/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_0_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_0_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 qmake you can enable it using the ",(0,s.jsx)(n.code,{children:"CONFIG+=ccache"})," on Linux or ",(0,s.jsx)(n.code,{children:"CONFIG+=tiny_ccache_win32"})," on Windows. For CMake you can set the ",(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 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 disables ",(0,s.jsx)(n.code,{children:"precompiled headers"})," and replaces the ",(0,s.jsx)(n.code,{children:"-Zi"})," compiler option 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"}),")."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can install the ccache using the ",(0,s.jsx)(n.code,{children:"scoop install ccache"})," command on Windows."]})})]})}function M(e={}){const{wrapper:n}={...(0,d.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(R,{...e})}):R(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(9466);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/0ab078a9.827159aa.js b/assets/js/0ab078a9.827159aa.js deleted file mode 100644 index 14d0e31a0..000000000 --- a/assets/js/0ab078a9.827159aa.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[969],{5162:(e,t,n)=>{n.d(t,{Z:()=>r});var a=n(7294),i=n(6010);const l={tabItem:"tabItem_Ymn6"};function r(e){let{children:t,hidden:n,className:r}=e;return a.createElement("div",{role:"tabpanel",className:(0,i.Z)(l.tabItem,r),hidden:n},t)}},4866:(e,t,n)=>{n.d(t,{Z:()=>f});var a=n(7462),i=n(7294),l=n(6010),r=n(2466),o=n(6550),d=n(1980),p=n(7392),m=n(12);function s(e){return function(e){return i.Children.map(e,(e=>{if(!e||(0,i.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(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)??[]}(e).map((e=>{let{props:{value:t,label:n,attributes:a,default:i}}=e;return{value:t,label:n,attributes:a,default:i}}))}function k(e){const{values:t,children:n}=e;return(0,i.useMemo)((()=>{const e=t??s(n);return function(e){const t=(0,p.l)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[t,n])}function u(e){let{value:t,tabValues:n}=e;return n.some((e=>e.value===t))}function N(e){let{queryString:t=!1,groupId:n}=e;const a=(0,o.k6)(),l=function(e){let{queryString:t=!1,groupId:n}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!n)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 n??null}({queryString:t,groupId:n});return[(0,d._X)(l),(0,i.useCallback)((e=>{if(!l)return;const t=new URLSearchParams(a.location.search);t.set(l,e),a.replace({...a.location,search:t.toString()})}),[l,a])]}function c(e){const{defaultValue:t,queryString:n=!1,groupId:a}=e,l=k(e),[r,o]=(0,i.useState)((()=>function(e){let{defaultValue:t,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the component requires at least one children component");if(t){if(!u({value:t,tabValues:n}))throw new Error(`Docusaurus error: The has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const a=n.find((e=>e.default))??n[0];if(!a)throw new Error("Unexpected error: 0 tabValues");return a.value}({defaultValue:t,tabValues:l}))),[d,p]=N({queryString:n,groupId:a}),[s,c]=function(e){let{groupId:t}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(t),[a,l]=(0,m.Nk)(n);return[a,(0,i.useCallback)((e=>{n&&l.set(e)}),[n,l])]}({groupId:a}),h=(()=>{const e=d??s;return u({value:e,tabValues:l})?e:null})();(0,i.useLayoutEffect)((()=>{h&&o(h)}),[h]);return{selectedValue:r,selectValue:(0,i.useCallback)((e=>{if(!u({value:e,tabValues:l}))throw new Error(`Can't select invalid tab value=${e}`);o(e),p(e),c(e)}),[p,c,l]),tabValues:l}}var h=n(2389);const b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function g(e){let{className:t,block:n,selectedValue:o,selectValue:d,tabValues:p}=e;const m=[],{blockElementScrollPositionUntilNextRender:s}=(0,r.o5)(),k=e=>{const t=e.currentTarget,n=m.indexOf(t),a=p[n].value;a!==o&&(s(t),d(a))},u=e=>{let t=null;switch(e.key){case"Enter":k(e);break;case"ArrowRight":{const n=m.indexOf(e.currentTarget)+1;t=m[n]??m[0];break}case"ArrowLeft":{const n=m.indexOf(e.currentTarget)-1;t=m[n]??m[m.length-1];break}}t?.focus()};return i.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,l.Z)("tabs",{"tabs--block":n},t)},p.map((e=>{let{value:t,label:n,attributes:r}=e;return i.createElement("li",(0,a.Z)({role:"tab",tabIndex:o===t?0:-1,"aria-selected":o===t,key:t,ref:e=>m.push(e),onKeyDown:u,onClick:k},r,{className:(0,l.Z)("tabs__item",b.tabItem,r?.className,{"tabs__item--active":o===t})}),n??t)})))}function C(e){let{lazy:t,children:n,selectedValue:a}=e;const l=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){const e=l.find((e=>e.props.value===a));return e?(0,i.cloneElement)(e,{className:"margin-top--md"}):null}return i.createElement("div",{className:"margin-top--md"},l.map(((e,t)=>(0,i.cloneElement)(e,{key:t,hidden:e.props.value!==a}))))}function y(e){const t=c(e);return i.createElement("div",{className:(0,l.Z)("tabs-container",b.tabList)},i.createElement(g,(0,a.Z)({},e,t)),i.createElement(C,(0,a.Z)({},e,t)))}function f(e){const t=(0,h.Z)();return i.createElement(y,(0,a.Z)({key:String(t)},e))}},5178:(e,t,n)=>{n.d(t,{Z:()=>d});var a=n(7294),i=n(6550);const l={apiTable:"apiTable_flxF"};function r(e,t){let{name:n,children:l}=e;const r=function(e){let t=e;for(;(0,a.isValidElement)(t);)[t]=a.Children.toArray(t.props.children);if("string"!=typeof t)throw new Error(`Could not extract APITable row name from JSX tree:\n${JSON.stringify(e,null,2)}`);return t}(l),o=n?`${n}-${r}`:r,d=`#${o}`,p=(0,i.k6)();return a.createElement("tr",{id:o,tabIndex:0,ref:p.location.hash===d?t:void 0,onClick:e=>{const t=e.target;"A"===t.tagName.toUpperCase()||"A"===t.parentElement?.tagName.toUpperCase()||p.push(d)},onKeyDown:e=>{"Enter"===e.key&&p.push(d)}},l.props.children)}const o=a.forwardRef(r);function d(e){let{children:t,name:n}=e;const[i,r]=a.Children.toArray(t.props.children),d=(0,a.useRef)(null);(0,a.useEffect)((()=>{d.current?.focus()}),[d]);const p=a.Children.map(r.props.children,(e=>a.createElement(o,{name:n,ref:d},e)));return a.createElement("table",{className:l.apiTable},i,a.createElement("tbody",null,p))}},2044:(e,t,n)=>{n.d(t,{$t:()=>s,Ae:()=>h,C:()=>N,DK:()=>b,Fo:()=>o,Fs:()=>i,IM:()=>c,IZ:()=>a,RS:()=>_,VE:()=>g,Wg:()=>y,_A:()=>p,al:()=>T,jk:()=>u,js:()=>d,of:()=>m,q5:()=>r,qb:()=>f,vk:()=>k,wU:()=>l,zg:()=>C});const a="shell",i="database",l="application",r="bash",o="pwsh",d="zsh",p="maria",m="mysql",s="postgres",k="sqlite",u="application",N="bash",c="pwsh",h="zsh",b="MariaDB",g="MySQL",C="PostgreSQL",y="SQLite",f="tinyorm.org",T="$HOME/Code/c/",_="$env:USERPROFILE\\Code\\c\\"},4355:(e,t,n)=>{n.d(t,{Z:()=>l});var a=n(7294),i=n(9482);function l(){const e=(0,a.useContext)(i.Z);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6005:(e,t,n)=>{n.d(t,{AE:()=>o,EA:()=>r,em:()=>p,go:()=>d,mT:()=>m,we:()=>s});var a=n(4355),i=n(2389),l=n(2044);const r=function(e,t){return void 0===t&&(t=!0),k((0,a.Z)().rootFolder[e]??p(e),e,t)},o=()=>(0,a.Z)().rootFolder[l.wU]??p(l.wU),d=function(e,t){if(void 0===t&&(t=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const n=t||e!==l.Fo?"/":"\\";return k(r(e)+n+o(),e,t)};function p(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,i.Z)())return"";switch(e){case l.Fo:return l.RS;case l.q5:return l.al;case l.wU:return l.qb;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function m(e){return e===l.wU}function s(e,t){if(null==t||""===t)return t;const n="$ENV{$1}$2";switch(e){case l.Fo:return N(t).replace(/\$env:(.+?)(\/.*)/,n);case l.q5:return t.replace(/\$(.+?)(\/.*)/,n);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function k(e,t,n){if(void 0===n&&(n=!0),null==e||""===e)return e;if(t!==l.Fo)return u(e);const a=u(e);return n?N(a):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(a)}function u(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function N(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},4040:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>v,contentTitle:()=>T,default:()=>M,frontMatter:()=>f,metadata:()=>_,toc:()=>O});var a=n(7462),i=n(7294),l=n(3905),r=n(5178),o=n(7693),d=n(5162),p=n(4866),m=n(5697),s=n.n(m),k=n(6005);function u(e){let{groupId:t}=e;return i.createElement("span",null,(0,k.go)(t))}u.propTypes={groupId:s().string.isRequired};const N=u;var c=n(6010),h=n(4355);const b={rootFolderInput:"rootFolderInput_ottS",input:"input_OR7e",application:"application_fjej"};function g(e){let{groupId:t,label:n}=e;const{rootFolder:a,setRootFolder:l}=(0,h.Z)(),r=(0,k.mT)(t),o=r?"application":"root",d=r?"\nThis folder name is common for all shells (eg. pwsh, bash, ...)":"";return i.createElement("form",{name:"tinyorm-root-folder-form",className:(0,c.Z)(b.rootFolderInput,b[t],t),onSubmit:e=>{e.preventDefault(),e.stopPropagation()}},i.createElement("input",{name:"tinyorm-root-folder-input",className:(0,c.Z)(b.input,b[t],t),placeholder:`Enter ${o} folder...`,title:`This ${o} folder will be used in all ${n} examples at tinyorm.org${d}`,onChange:e=>{l(t,e.target.value)},value:a[t]??(0,k.em)(t)}))}g.propTypes={groupId:s().string.isRequired,label:s().string.isRequired};const C=g;var y=n(2044);const f={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"]},T="Building: TinyORM",_={unversionedId:"building/tinyorm",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,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/building/tinyorm.mdx",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"}},v={},O=[{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}],I={toc:O},R="wrapper";function M(e){let{components:t,...i}=e;return(0,l.kt)(R,(0,a.Z)({},I,i,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"building-tinyorm"},"Building: TinyORM"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#introduction"},"Introduction"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#common-prerequisites"},"Common Prerequisites")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#windows-prerequisites"},"Windows Prerequisites")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#folders-structure"},"Folders structure")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#getting-started"},"Getting started")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#vcpkg"},"vcpkg")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#c-preprocessor-macros"},"C preprocessor macros")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#building-with-cmake"},"Building with CMake"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#configure-and-build-cmake"},"Configure & Build")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#cmake-build-options"},"CMake build options")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#consume-tinyorm-library-cmake"},"Consume TinyOrm library")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#building-with-qmake"},"Building with qmake"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#install-dependencies"},"Install dependencies")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#configure-and-build-qmake"},"Configure & Build")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#qmake-build-options"},"qmake build options")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#consume-tinyorm-library-qmake"},"Consume TinyOrm library")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#auto-configuration-internals"},"Auto-configuration internals"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#environment-files"},"Environment files")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#manual-configuration-internals"},"Manual configuration internals")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#ccache-support"},"Ccache support"))),(0,l.kt)("h2",{id:"introduction"},"Introduction"),(0,l.kt)("p",null,"The build systems supported out of the box are ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake"),"."),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"All examples below assume that ",(0,l.kt)("inlineCode",{parentName:"p"},"pwsh")," runs on ",(0,l.kt)("inlineCode",{parentName:"p"},"Windows")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"bash")," runs on ",(0,l.kt)("inlineCode",{parentName:"p"},"Linux"),".")),(0,l.kt)("h4",{id:"common-prerequisites"},"Common Prerequisites"),(0,l.kt)("p",null,"Install the required ",(0,l.kt)("a",{parentName:"p",href:"/dependencies"},"dependencies")," before starting."),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("inlineCode",{parentName:"p"},"QSqlDatabase")," depends on ",(0,l.kt)("inlineCode",{parentName:"p"},"QCoreApplication")," from ",(0,l.kt)("inlineCode",{parentName:"p"},"Qt v6.5.3")," so you must create the ",(0,l.kt)("inlineCode",{parentName:"p"},"QCoreApplication")," instance before you will call anything from the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. \ud83e\udee4 The change was made ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/qt/qtbase/commit/8d2bdc9cd5482eace12ba7e45304857bd24db0e6#diff-1d355c25c0b0eddec2be48253407780c4dc510d986739aec61e1ec892ccaf86e"},"here"),".")),(0,l.kt)("h4",{id:"windows-prerequisites"},"Windows Prerequisites"),(0,l.kt)("h5",{id:"build-environment-scripts"},"Build environment scripts"),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"Visual Studio")," does not provide ",(0,l.kt)("inlineCode",{parentName:"p"},"vcvars")," scripts for ",(0,l.kt)("inlineCode",{parentName:"p"},"pwsh"),", you can use ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/tree/main/tools/vcvars64.ps1"},(0,l.kt)("inlineCode",{parentName:"a"},"vcvars64.ps1"))," provided by ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," in the ",(0,l.kt)("inlineCode",{parentName:"p"},"tools/")," folder. Place them on the ",(0,l.kt)("inlineCode",{parentName:"p"},"$env:Path")," user/system path and they will be available system-wide."),(0,l.kt)("p",null,"The same is true for the ",(0,l.kt)("inlineCode",{parentName:"p"},"Qt Framework"),", it doesn't provide ",(0,l.kt)("inlineCode",{parentName:"p"},"qtenv")," scripts for ",(0,l.kt)("inlineCode",{parentName:"p"},"pwsh")," too. You can create your own script, place it on the ",(0,l.kt)("inlineCode",{parentName:"p"},"$env:Path")," user/system path and it will be available system-wide."),(0,l.kt)("p",null,"Here is one simple example for ",(0,l.kt)("inlineCode",{parentName:"p"},"pwsh"),"."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:"qtenv6.ps1",label:"qtenv6.ps1",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"Write-Host 'Setting up environment for Qt 6.7.0 usage...' -ForegroundColor Magenta\n$env:Path = 'C:\\Qt\\6.7.0\\msvc2019_64\\bin;' + $env:Path\n. E:\\dotfiles\\bin\\vcvars64.ps1\n"))),(0,l.kt)(d.Z,{value:"qtenv5.ps1",label:"qtenv5.ps1",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"Write-Host 'Setting up environment for Qt 5.15.2 usage...' -ForegroundColor Magenta\n$env:Path = 'C:\\Qt\\5.15.2\\msvc2019_64\\bin;' + $env:Path\n. E:\\dotfiles\\bin\\vcvars64.ps1\n")))),(0,l.kt)("p",null,"And here for ",(0,l.kt)("inlineCode",{parentName:"p"},"Linux"),"."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:"qtenv6",label:"qtenv6",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"echo 'Setting up environment for Qt 6.7.0 usage...'\n\nexport PATH=/opt/Qt/6.7.0/gcc_64/bin${PATH:+:}$PATH\nexport LD_LIBRARY_PATH=/opt/Qt/6.7.0/gcc_64/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH\n"))),(0,l.kt)(d.Z,{value:"qtenv5",label:"qtenv5",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"echo 'Setting up environment for Qt 5.15.2 usage...'\n\nexport PATH=/opt/Qt/5.15.2/gcc_64/bin${PATH:+:}$PATH\nexport LD_LIBRARY_PATH=/opt/Qt/5.15.2/gcc_64/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH\n")))),(0,l.kt)("h5",{id:"allow-symbolic-links-unprivileged"},"Allow symbolic links unprivileged"),(0,l.kt)("p",null,"Open ",(0,l.kt)("inlineCode",{parentName:"p"},"Local Security Policy"),", go to ",(0,l.kt)("inlineCode",{parentName:"p"},"Local Policies - User Rights Assignment"),", open ",(0,l.kt)("inlineCode",{parentName:"p"},"Create symbolic links")," and add your user account or user group, restart when it doesn't apply immediately."),(0,l.kt)("h2",{id:"folders-structure"},"Folders structure"),(0,l.kt)("p",null,"All ",(0,l.kt)("inlineCode",{parentName:"p"},"tinyorm.org")," examples are based on the following folders structure. The ",(0,l.kt)("inlineCode",{parentName:"p"},"tom")," folder will contain a ",(0,l.kt)("a",{parentName:"p",href:"/building/migrations"},"migrations console application"),"."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can set the root and application folder paths in the form below and they will be used across the whole ",(0,l.kt)("a",{parentName:"p",href:"http://www.tinyorm.org"},"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.")),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,className:"tiny-tree",mdxType:"TabItem"},(0,l.kt)("div",{className:"tiny-root-folder-info-wrapper"},(0,l.kt)("span",{className:"tiny-root-folder-info-prefix"},"Current pwsh path"),"\xa0",(0,l.kt)(N,{groupId:y.Fo,mdxType:"RootFolder"})),(0,l.kt)(C,{groupId:y.Fo,label:y.IM,mdxType:"RootFolderInput"}),(0,l.kt)(C,{groupId:y.wU,label:y.jk,mdxType:"RootFolderInput"}),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-text"},"\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_0_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_0_MSVC2019_64bit-Debug/\n\u251c\u2500\u2500 tmp/\n\u2514\u2500\u2500 vcpkg/\n"))),(0,l.kt)(d.Z,{value:y.q5,label:y.C,className:"tiny-tree",mdxType:"TabItem"},(0,l.kt)("div",{className:"tiny-root-folder-info-wrapper"},(0,l.kt)("span",{className:"tiny-root-folder-info-prefix"},"Current bash path"),"\xa0",(0,l.kt)(N,{groupId:y.q5,mdxType:"RootFolder"})),(0,l.kt)(C,{groupId:y.q5,label:y.C,mdxType:"RootFolderInput"}),(0,l.kt)(C,{groupId:y.wU,label:y.wU,mdxType:"RootFolderInput"}),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-text"},"\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_0_clang14_64bit_ccache-Debug/\n\u2502 \u2514\u2500\u2500 tom-builds-qmake/\n\u2502 \u251c\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_0_GCC_64bit-Debug/\n\u2502 \u2514\u2500\u2500 build-TinyORM-Desktop_Qt_6_7_0_clang14_64bit_ccache-Release/\n\u251c\u2500\u2500 tmp/\n\u2514\u2500\u2500 vcpkg/\n")))),(0,l.kt)("admonition",{type:"danger"},(0,l.kt)("p",{parentName:"admonition"},"Avoid paths with spaces with the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build system, it will not compile.")),(0,l.kt)("a",{id:"qtcreator-default-build-directory"}),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can force the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator")," to generate a build folders structure as is described above."),(0,l.kt)("p",{parentName:"admonition"},"To generate the required folders structure set the ",(0,l.kt)("inlineCode",{parentName:"p"},"Settings")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"Build & Run")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"Default Build Properties")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"Default build directory")," to:",(0,l.kt)("br",null),"\n",(0,l.kt)("inlineCode",{parentName:"p"},'../%{Project:Name}-builds-%{BuildSystem:Name}/%{JS: Util.asciify("build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}")}'))),(0,l.kt)("h2",{id:"getting-started"},"Getting started"),(0,l.kt)("p",null,"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,l.kt)("inlineCode",{parentName:"p"},"PATH")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"LD_LIBRARY_PATH")," for Qt Framework, or use our ",(0,l.kt)("inlineCode",{parentName:"p"},"qtenvX")," scripts described above."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`mkdir ${(0,k.EA)(y.Fo)}\ncd ${(0,k.EA)(y.Fo)}\n$env:Path = 'C:\\Qt\\6.7.0\\msvc2019_64\\bin;' + $env:Path\nvcvars64.ps1`)),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`mkdir -p ${(0,k.EA)(y.q5)}\ncd ${(0,k.EA)(y.q5)}\nexport PATH=/opt/Qt/6.7.0/gcc_64/bin\${PATH:+:}$PATH\nexport LD_LIBRARY_PATH=/opt/Qt/6.7.0/gcc_64/lib\${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH`))),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can also use the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/tools/Add-FolderOnPath.ps1"},(0,l.kt)("inlineCode",{parentName:"a"},"tools/Add-FolderOnPath.ps1"))," pwsh script to fastly prepend a path or ",(0,l.kt)("abbr",{title:"Current working directory"},"pwd")," on the system ",(0,l.kt)("inlineCode",{parentName:"p"},"PATH"),".")),(0,l.kt)("h2",{id:"vcpkg"},"vcpkg"),(0,l.kt)("p",null,"Installing the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," is highly recommended, it simplifies installation of the ",(0,l.kt)("inlineCode",{parentName:"p"},"range-v3")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"tabulate")," dependencies."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"git clone git@github.com:microsoft/vcpkg.git\ncd vcpkg\n.\\bootstrap-vcpkg.bat\n"))),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"git clone git@github.com:microsoft/vcpkg.git\ncd vcpkg\n./bootstrap-vcpkg.sh\n")))),(0,l.kt)("p",null,"Add ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," on the system path, add the following to the ",(0,l.kt)("inlineCode",{parentName:"p"},".bashrc")," or ",(0,l.kt)("inlineCode",{parentName:"p"},".zshrc")," on Linux."),(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`export PATH=${(0,k.EA)(y.q5)}/vcpkg\${PATH:+:}$PATH`),(0,l.kt)("p",null,"On Windows, open the ",(0,l.kt)("inlineCode",{parentName:"p"},"Environment variables")," dialog and add ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," on the user ",(0,l.kt)("inlineCode",{parentName:"p"},"PATH"),"."),(0,l.kt)("p",null,"Or you can export it for the current session only."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`$env:Path = "${(0,k.EA)(y.Fo,!1)}\\vcpkg;" + $env:Path`)),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`export PATH=${(0,k.EA)(y.q5)}/vcpkg\${PATH:+:}$PATH`))),(0,l.kt)("h4",{id:"set-up-vcpkg-environment"},"Set up ",(0,l.kt)("inlineCode",{parentName:"h4"},"vcpkg")," environment"),(0,l.kt)("p",null,"To export ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," environment variables globally, add it to the ",(0,l.kt)("inlineCode",{parentName:"p"},".bashrc")," or ",(0,l.kt)("inlineCode",{parentName:"p"},".zshrc")," on Linux, and you can use the ",(0,l.kt)("inlineCode",{parentName:"p"},"Environment variables")," dialog on Windows."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash",metastring:"title='Linux'",title:"'Linux'"},'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')),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"It is recommended to define these variables globally because the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build system are able to detect the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," installation from them so you don't have to configure them manually to detect the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," installation.")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"On Windows, it's always better to create these types of variables as user variables instead of system variables in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Environment variables")," dialog.")),(0,l.kt)("h2",{id:"c-preprocessor-macros"},"C preprocessor macros"),(0,l.kt)("p",null,"The following table summarizes all the C preprocessor macros defined in the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. These C macros are configured by ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build systems. They are not sorted alphabetically, but they are sorted by how significant they are."),(0,l.kt)("p",null,"In the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," build system, all the C macros are auto-detected / auto-configured or controlled by ",(0,l.kt)("a",{parentName:"p",href:"#cmake-build-options"},(0,l.kt)("inlineCode",{parentName:"a"},"CMake build options")),", so you don't have to care too much about them."),(0,l.kt)("p",null,"In the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build is important whether you are building ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library or you are building your application and linking against ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. When you are building the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library, all the C macros are auto-detected / auto-configured or controlled by ",(0,l.kt)("a",{parentName:"p",href:"#qmake-build-options"},(0,l.kt)("inlineCode",{parentName:"a"},"qmake build options")),", so you don't have to care too much about them."),(0,l.kt)("p",null,"But a special situation is when you are building your application / library and you are linking against ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. In this particular case, you must configure all these C macros manually! For this reason, the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/qmake/TinyOrm.pri"},(0,l.kt)("inlineCode",{parentName:"a"},"TinyOrm.pri"))," has been created, so that's not a big deal either. Little more info ",(0,l.kt)("a",{parentName:"p",href:"#consume-tinyorm-library-qmake"},"here"),"."),(0,l.kt)("div",{id:"apitable-c-macros"},(0,l.kt)(r.Z,{mdxType:"APITable"},(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"C Macro Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_LINKING_SHARED")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("u",null,(0,l.kt)("strong",{parentName:"td"},"Must"))," be defined when you are linking against ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," shared build (",(0,l.kt)("inlineCode",{parentName:"td"},"dll")," library), exported classes and functions will be tagged with ",(0,l.kt)("inlineCode",{parentName:"td"},"__declspec(dllimport)")," on ",(0,l.kt)("inlineCode",{parentName:"td"},"msvc")," and ",(0,l.kt)("inlineCode",{parentName:"td"},'visibility("default")')," on ",(0,l.kt)("inlineCode",{parentName:"td"},"GCC >= 4"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_BUILDING_SHARED")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined when ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," is built as a ",(0,l.kt)("inlineCode",{parentName:"td"},"dll")," library (shared build).")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_DEBUG")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined in the debug build.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_NO_DEBUG")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined in the release build.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_DEBUG_SQL")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined in the debug build.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_NO_DEBUG_SQL")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined in the release build.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_MYSQL_PING")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable ",(0,l.kt)("inlineCode",{parentName:"td"},"Orm::MySqlConnection::pingDatabase()")," method.",(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined when ",(0,l.kt)("a",{parentName:"td",href:"#mysql_ping"},(0,l.kt)("inlineCode",{parentName:"a"},"mysql_ping"))," ",(0,l.kt)("small",null,"(qmake)")," / ",(0,l.kt)("a",{parentName:"td",href:"#MYSQL_PING"},(0,l.kt)("inlineCode",{parentName:"a"},"MYSQL_PING"))," ",(0,l.kt)("small",null,"(cmake)")," configuration ",(0,l.kt)("inlineCode",{parentName:"td"},"build option")," is enabled."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_DISABLE_ORM")),(0,l.kt)("td",{parentName:"tr",align:null},"Controls the compilation of all ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM-related")," source code, when this macro is ",(0,l.kt)("inlineCode",{parentName:"td"},"defined"),", then only the ",(0,l.kt)("inlineCode",{parentName:"td"},"query builder")," without ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM")," is compiled. Also excludes ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM-related")," unit tests.",(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined when ",(0,l.kt)("a",{parentName:"td",href:"#disable_orm"},(0,l.kt)("inlineCode",{parentName:"a"},"disable_orm"))," ",(0,l.kt)("small",null,"(qmake)")," / ",(0,l.kt)("a",{parentName:"td",href:"#ORM"},(0,l.kt)("inlineCode",{parentName:"a"},"ORM"))," ",(0,l.kt)("small",null,"(cmake)")," configuration ",(0,l.kt)("inlineCode",{parentName:"td"},"build option")," is enabled ",(0,l.kt)("small",null,"(qmake)")," / disabled ",(0,l.kt)("small",null,"(cmake)"),"."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_EXTERN_CONSTANTS")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined when extern constants are used. Extern constants are enabled by default for shared builds and disabled for static builds.",(0,l.kt)("br",null),(0,l.kt)("small",null,"Described at ",(0,l.kt)("a",{parentName:"td",href:"#extern_constants"},(0,l.kt)("inlineCode",{parentName:"a"},"qmake"))," / ",(0,l.kt)("a",{parentName:"td",href:"#INLINE_CONSTANTS"},(0,l.kt)("inlineCode",{parentName:"a"},"CMake"))," how it works."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_INLINE_CONSTANTS")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined when global inline constants are used.",(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined when ",(0,l.kt)("a",{parentName:"td",href:"#inline_constants"},(0,l.kt)("inlineCode",{parentName:"a"},"inline_constants"))," ",(0,l.kt)("small",null,"(qmake)")," / ",(0,l.kt)("a",{parentName:"td",href:"#INLINE_CONSTANTS"},(0,l.kt)("inlineCode",{parentName:"a"},"INLINE_CONSTANTS"))," ",(0,l.kt)("small",null,"(cmake)")," configuration ",(0,l.kt)("inlineCode",{parentName:"td"},"build option")," is enabled."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_TESTS_CODE")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable code needed by unit tests, eg. connection overriding in the ",(0,l.kt)("inlineCode",{parentName:"td"},"Orm::Tiny::Model"),".",(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined when ",(0,l.kt)("a",{parentName:"td",href:"#build_tests"},(0,l.kt)("inlineCode",{parentName:"a"},"build_tests"))," ",(0,l.kt)("small",null,"(qmake)")," / ",(0,l.kt)("a",{parentName:"td",href:"#BUILD_TESTS"},(0,l.kt)("inlineCode",{parentName:"a"},"BUILD_TESTS"))," ",(0,l.kt)("small",null,"(cmake)")," configuration ",(0,l.kt)("inlineCode",{parentName:"td"},"build option")," is enabled."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_DISABLE_THREAD_LOCAL")),(0,l.kt)("td",{parentName:"tr",align:null},"Remove all ",(0,l.kt)("a",{parentName:"td",href:"https://en.cppreference.com/w/c/language/storage_duration"},(0,l.kt)("inlineCode",{parentName:"a"},"thread_local"))," storage duration specifiers, it disables multi-threading support.",(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined when ",(0,l.kt)("a",{parentName:"td",href:"#disable_thread_local"},(0,l.kt)("inlineCode",{parentName:"a"},"disable_thread_local"))," ",(0,l.kt)("small",null,"(qmake)")," / ",(0,l.kt)("a",{parentName:"td",href:"#DISABLE_THREAD_LOCAL"},(0,l.kt)("inlineCode",{parentName:"a"},"DISABLE_THREAD_LOCAL"))," ",(0,l.kt)("small",null,"(cmake)")," configuration ",(0,l.kt)("inlineCode",{parentName:"td"},"build option")," is enabled."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYTOM_MIGRATIONS_DIR")),(0,l.kt)("td",{parentName:"tr",align:null},"Default migrations path for the ",(0,l.kt)("inlineCode",{parentName:"td"},"make:migration")," command, can be an absolute or relative path (to the ",(0,l.kt)("abbr",{title:"Current working directory"},"pwd"),").",(0,l.kt)("br",null),(0,l.kt)("small",null,"Default value: ",(0,l.kt)("inlineCode",{parentName:"td"},"database/migrations")," ",(0,l.kt)("small",null,"(relative to the pwd)")),(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined by ",(0,l.kt)("a",{parentName:"td",href:"#TOM_MIGRATIONS_DIR"},(0,l.kt)("inlineCode",{parentName:"a"},"TOM_MIGRATIONS_DIR"))," ",(0,l.kt)("small",null,"(cmake)")," configuration build option.",(0,l.kt)("br",null),(0,l.kt)("small",null,"(qmake note) You can use ",(0,l.kt)("inlineCode",{parentName:"td"},'DEFINES += TINYTOM_MIGRATIONS_DIR="\\"database/migrations\\""')," on the command-line or set it in the ",(0,l.kt)("strong",{parentName:"td"},"main")," ",(0,l.kt)("a",{parentName:"td",href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L65-L70"},(0,l.kt)("inlineCode",{parentName:"a"},"conf.pri"))," file.")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYTOM_MODELS_DIR")),(0,l.kt)("td",{parentName:"tr",align:null},"Default models path for the ",(0,l.kt)("inlineCode",{parentName:"td"},"make:model")," command, can be an absolute or relative path (to the ",(0,l.kt)("abbr",{title:"Current working directory"},"pwd"),").",(0,l.kt)("br",null),(0,l.kt)("small",null,"Default value: ",(0,l.kt)("inlineCode",{parentName:"td"},"database/models")," ",(0,l.kt)("small",null,"(relative to the pwd)")),(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined by ",(0,l.kt)("a",{parentName:"td",href:"#TOM_MODELS_DIR"},(0,l.kt)("inlineCode",{parentName:"a"},"TOM_MODELS_DIR"))," ",(0,l.kt)("small",null,"(cmake)")," configuration build option.",(0,l.kt)("br",null),(0,l.kt)("small",null,"(qmake note) You can use ",(0,l.kt)("inlineCode",{parentName:"td"},'DEFINES += TINYTOM_MODELS_DIR="\\"database/models\\""')," on the command-line or set it in the ",(0,l.kt)("strong",{parentName:"td"},"main")," ",(0,l.kt)("a",{parentName:"td",href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L72-L73"},(0,l.kt)("inlineCode",{parentName:"a"},"conf.pri"))," file.")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYTOM_SEEDERS_DIR")),(0,l.kt)("td",{parentName:"tr",align:null},"Default seeders path for the ",(0,l.kt)("inlineCode",{parentName:"td"},"make:seeder")," command, can be an absolute or relative path (to the ",(0,l.kt)("abbr",{title:"Current working directory"},"pwd"),").",(0,l.kt)("br",null),(0,l.kt)("small",null,"Default value: ",(0,l.kt)("inlineCode",{parentName:"td"},"database/seeders")," ",(0,l.kt)("small",null,"(relative to the pwd)")),(0,l.kt)("br",null),(0,l.kt)("small",null,"Defined by ",(0,l.kt)("a",{parentName:"td",href:"#TOM_SEEDERS_DIR"},(0,l.kt)("inlineCode",{parentName:"a"},"TOM_SEEDERS_DIR"))," ",(0,l.kt)("small",null,"(cmake)")," configuration build option.",(0,l.kt)("br",null),(0,l.kt)("small",null,"(qmake note) You can use ",(0,l.kt)("inlineCode",{parentName:"td"},'DEFINES += TINYTOM_SEEDERS_DIR="\\"database/seeders\\""')," on the command-line or set it in the ",(0,l.kt)("strong",{parentName:"td"},"main")," ",(0,l.kt)("a",{parentName:"td",href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L75-L76"},(0,l.kt)("inlineCode",{parentName:"a"},"conf.pri"))," file.")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_USING_PCH")),(0,l.kt)("td",{parentName:"tr",align:null},"Defined if building with precompiled headers.",(0,l.kt)("br",null),(0,l.kt)("small",null,"Controlled by ",(0,l.kt)("a",{parentName:"td",href:"#precompile_header"},(0,l.kt)("inlineCode",{parentName:"a"},"qmake"))," / ",(0,l.kt)("a",{parentName:"td",href:"#CMAKE_DISABLE_PRECOMPILE_HEADERS"},(0,l.kt)("inlineCode",{parentName:"a"},"CMake")),"."))))))),(0,l.kt)("h2",{id:"building-with-cmake"},"Building with CMake"),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"If something is not clear, you can still look at GitHub Action ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/tree/main/.github/workflows"},(0,l.kt)("inlineCode",{parentName:"a"},"workflows"))," how a building is done.")),(0,l.kt)("p",null,"First, create a basic folder structure and then clone the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," project."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,k.EA)(y.Fo)}\nmkdir ${(0,k.AE)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,k.AE)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`)),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,k.EA)(y.q5)}\nmkdir -p ${(0,k.AE)()}/TinyORM/TinyORM-builds-cmake/build-debug\n\ncd ${(0,k.AE)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`))),(0,l.kt)("h3",{id:"configure-and-build-cmake"},"Configure & Build ",(0,l.kt)("small",null,"(cmake)")),(0,l.kt)("p",null,"Now you are ready to configure the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cd TinyORM-builds-cmake/build-debug\n")),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cmake.exe \`\n-S "${(0,k.go)(y.Fo)}/TinyORM/TinyORM" \`\n-B "${(0,k.go)(y.Fo)}/TinyORM/TinyORM-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,k.EA)(y.Fo)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,k.EA)(y.Fo)}/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,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cmake \\\n-S "${(0,k.go)(y.q5)}/TinyORM/TinyORM" \\\n-B "${(0,k.go)(y.q5)}/TinyORM/TinyORM-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,k.EA)(y.q5)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,k.EA)(y.q5)}/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`))),(0,l.kt)("h5",{id:"cmake-strict_mode-option"},"CMake ",(0,l.kt)("inlineCode",{parentName:"h5"},"STRICT_MODE")," option"),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"STRICT_MODE")," ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," configuration option was added in ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"p"},"v0.37.3"),". This option was added to avoid the propagation of aggressive strict warning compiler/linker options and Qt definitions from the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library to user code through the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/cmake/CommonModules/TinyCommon.cmake"},(0,l.kt)("inlineCode",{parentName:"a"},"TinyOrm::CommonConfig"))," interface library."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"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,l.kt)("inlineCode",{parentName:"p"},"ISOCPP")," ",(0,l.kt)("a",{parentName:"p",href:"https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines"},"C++ Core Guidelines")," standards."),(0,l.kt)("p",null,"If you want to enable these strict warning options in your code, you can enable the ",(0,l.kt)("inlineCode",{parentName:"p"},"STRICT_MODE")," ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," configuration option and they will be propagated to your code. You can also enabled it globally using the ",(0,l.kt)("inlineCode",{parentName:"p"},"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,l.kt)("inlineCode",{parentName:"p"},"STRICT_MODE")," ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," configuration option."),(0,l.kt)("p",null,"You can achieve the same result by manually linking against the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm::CommonConfig")," interface library when the ",(0,l.kt)("inlineCode",{parentName:"p"},"STRICT_MODE")," is set to ",(0,l.kt)("inlineCode",{parentName:"p"},"OFF"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-cmake"},"target_link_libraries( PRIVATE TinyOrm::CommonConfig)\n")),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"The recommended way is to set the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_STRICT_MODE")," environment variable to ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"ON"),".")),(0,l.kt)("h4",{id:"build-tinyorm"},"Build TinyORM"),(0,l.kt)("p",null,"And build. You don't have to install it, you can use the build tree directly if you want."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cmake --build . --target all\ncmake --install .\n")),(0,l.kt)("p",null,"Or build and install in one step."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cmake --build . --target install\n")),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"CMake multi-config generators like ",(0,l.kt)("inlineCode",{parentName:"p"},"Ninja Multi-Config")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"Visual Studio 16 2019")," are also supported.")),(0,l.kt)("h3",{id:"cmake-build-options"},"CMake build options"),(0,l.kt)("div",{className:"apitable-build-options"},(0,l.kt)(r.Z,{mdxType:"APITable"},(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Option Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Default"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_DRIVERS")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build ",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started"},"TinyDrivers")," SQL database drivers (core/common code; replaces QtSql module).")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_MYSQL_DRIVER")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyDrivers")," MySQL database driver.",(0,l.kt)("br",null),(0,l.kt)("small",null,"Available when: ",(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_DRIVERS")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_SHARED_LIBS")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ON")),(0,l.kt)("td",{parentName:"tr",align:null},"Build as a shared/static library.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_TESTS")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build TinyORM unit tests.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_TREE_DEPLOY")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ON")),(0,l.kt)("td",{parentName:"tr",align:null},"Copy ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyDrivers")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyMySql")," libraries to the root of the build tree.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"DRIVERS_TYPE")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Shared")),(0,l.kt)("td",{parentName:"tr",align:null},"How to build and link against ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyDrivers")," SQL database drivers.",(0,l.kt)("br",null),(0,l.kt)("small",null,"The ",(0,l.kt)("inlineCode",{parentName:"td"},"Static")," value will be select by default when the ",(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_SHARED_LIBS")," is ",(0,l.kt)("inlineCode",{parentName:"td"},"OFF"),".",(0,l.kt)("br",null),"Supported values: ",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started#the-shared-library-build"},(0,l.kt)("inlineCode",{parentName:"a"},"Shared")),", ",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started#the-loadable-sql-drivers-build"},(0,l.kt)("inlineCode",{parentName:"a"},"Loadable")),", and ",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started#the-static-build"},(0,l.kt)("inlineCode",{parentName:"a"},"Static")),(0,l.kt)("br",null),"Available when: ",(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_DRIVERS AND BUILD_SHARED_LIBS")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"INLINE_CONSTANTS")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Use inline constants instead of extern constants in the ",(0,l.kt)("inlineCode",{parentName:"td"},"shared build"),".",(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"OFF")," is highly recommended for the ",(0,l.kt)("inlineCode",{parentName:"td"},"shared build"),";",(0,l.kt)("br",null),"is always ",(0,l.kt)("inlineCode",{parentName:"td"},"ON")," for the ",(0,l.kt)("inlineCode",{parentName:"td"},"static build"),".",(0,l.kt)("br",null),(0,l.kt)("small",null,"Available when: ",(0,l.kt)("inlineCode",{parentName:"td"},"BUILD_SHARED_LIBS")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"MSVC_RUNTIME_DYNAMIC")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ON")),(0,l.kt)("td",{parentName:"tr",align:null},"Use MSVC dynamic runtime library (",(0,l.kt)("inlineCode",{parentName:"td"},"-MD"),") instead of static (",(0,l.kt)("inlineCode",{parentName:"td"},"-MT"),"), also considers a Debug configuration (",(0,l.kt)("inlineCode",{parentName:"td"},"-MTd"),", ",(0,l.kt)("inlineCode",{parentName:"td"},"-MDd"),").",(0,l.kt)("br",null),(0,l.kt)("small",null,"Available when: ",(0,l.kt)("inlineCode",{parentName:"td"},"MSVC AND NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"MYSQL_PING")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable ",(0,l.kt)("inlineCode",{parentName:"td"},"Orm::MySqlConnection::pingDatabase()")," method.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ORM")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ON")),(0,l.kt)("td",{parentName:"tr",align:null},"Controls the compilation of all ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM-related")," source code, when this option is ",(0,l.kt)("inlineCode",{parentName:"td"},"disabled"),", then only the ",(0,l.kt)("inlineCode",{parentName:"td"},"query builder")," without ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM")," is compiled. Also excludes ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM-related")," unit tests.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"STRICT_MODE")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Controls propagation of strict compiler/linker options and Qt definitions using the ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyOrm::CommonConfig")," interface library to the user code.",(0,l.kt)("br",null),(0,l.kt)("small",null,"(highly recommended; can also be set with the ",(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_STRICT_MODE")," environment variable; described ",(0,l.kt)("a",{parentName:"td",href:"#cmake-strict_mode-option"},"here"),")"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TOM")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ON")),(0,l.kt)("td",{parentName:"tr",align:null},"Controls the compilation of all ",(0,l.kt)("inlineCode",{parentName:"td"},"Tom-related")," source code, when this option is ",(0,l.kt)("inlineCode",{parentName:"td"},"disabled"),", then it also excludes ",(0,l.kt)("inlineCode",{parentName:"td"},"Tom-related")," unit tests.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TOM_EXAMPLE")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build the ",(0,l.kt)("abbr",{title:"TinyORM Migrations"},(0,l.kt)("inlineCode",{parentName:"td"},"tom"))," console application example.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TOM_MIGRATIONS_DIR")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"-")),(0,l.kt)("td",{parentName:"tr",align:null},"Default migrations path for the ",(0,l.kt)("inlineCode",{parentName:"td"},"make:migration")," command, can be an absolute or relative path (to the ",(0,l.kt)("abbr",{title:"Current working directory"},"pwd"),").",(0,l.kt)("br",null),(0,l.kt)("small",null,"Default value: ",(0,l.kt)("inlineCode",{parentName:"td"},"database/migrations")," ",(0,l.kt)("small",null,"(relative to the pwd)")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TOM_MODELS_DIR")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"-")),(0,l.kt)("td",{parentName:"tr",align:null},"Default models path for the ",(0,l.kt)("inlineCode",{parentName:"td"},"make:model")," command, can be an absolute or relative path (to the ",(0,l.kt)("abbr",{title:"Current working directory"},"pwd"),").",(0,l.kt)("br",null),(0,l.kt)("small",null,"Default value: ",(0,l.kt)("inlineCode",{parentName:"td"},"database/models")," ",(0,l.kt)("small",null,"(relative to the pwd)")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TOM_SEEDERS_DIR")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"-")),(0,l.kt)("td",{parentName:"tr",align:null},"Default seeders path for the ",(0,l.kt)("inlineCode",{parentName:"td"},"make:seeder")," command, can be an absolute or relative path (to the ",(0,l.kt)("abbr",{title:"Current working directory"},"pwd"),").",(0,l.kt)("br",null),(0,l.kt)("small",null,"Default value: ",(0,l.kt)("inlineCode",{parentName:"td"},"database/seeders")," ",(0,l.kt)("small",null,"(relative to the pwd)")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"VERBOSE_CONFIGURE")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Show information about ",(0,l.kt)("inlineCode",{parentName:"td"},"PACKAGES_FOUND")," / ",(0,l.kt)("inlineCode",{parentName:"td"},"PACKAGES_NOT_FOUND")," in the CMake configure output.")))))),(0,l.kt)("p",null,"Advanced ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," options."),(0,l.kt)("div",{className:"apitable-build-options"},(0,l.kt)(r.Z,{mdxType:"APITable"},(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Option Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Default"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"DISABLE_THREAD_LOCAL")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Remove all ",(0,l.kt)("a",{parentName:"td",href:"https://en.cppreference.com/w/c/language/storage_duration"},(0,l.kt)("inlineCode",{parentName:"a"},"thread_local"))," storage duration specifiers, it disables multi-threading support.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("small",null,(0,l.kt)("inlineCode",{parentName:"td"},"MATCH_EQUAL_EXPORTED_BUILDTREE"))),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Exported package configuration from the build tree is considered to match only when ",(0,l.kt)("inlineCode",{parentName:"td"},"the build type")," of application/library that is linking against the TinyORM library ",(0,l.kt)("strong",{parentName:"td"},"is equal"),".",(0,l.kt)("br",null),(0,l.kt)("small",null,"Available when:",(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"CMAKE_EXPORT_PACKAGE_REGISTRY AND NOT TINY_IS_MULTI_CONFIG")))))))),(0,l.kt)("p",null,"Important ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," options."),(0,l.kt)("div",{className:"apitable-build-options"},(0,l.kt)(r.Z,{mdxType:"APITable"},(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Option Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Default"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"CMAKE_DISABLE_PRECOMPILE_HEADERS")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Disable precompiled headers.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"CMAKE_CXX_COMPILER")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"auto")),(0,l.kt)("td",{parentName:"tr",align:null},"The full path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"C++")," compiler.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"CMAKE_CXX_COMPILER_LAUNCHER")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"-")),(0,l.kt)("td",{parentName:"tr",align:null},"Default compiler launcher to use for the ",(0,l.kt)("inlineCode",{parentName:"td"},"C++")," compiler.",(0,l.kt)("br",null),"Can be used to enable ",(0,l.kt)("inlineCode",{parentName:"td"},"ccache"),", eg. ",(0,l.kt)("inlineCode",{parentName:"td"},"ccache.exe")," on ",(0,l.kt)("inlineCode",{parentName:"td"},"MinGW")," or ",(0,l.kt)("inlineCode",{parentName:"td"},"/usr/bin/ccache")," on ",(0,l.kt)("inlineCode",{parentName:"td"},"Linux"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"CMAKE_EXPORT_PACKAGE_REGISTRY")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable the ",(0,l.kt)("inlineCode",{parentName:"td"},"export(TinyOrm)")," command.",(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," doesn't set this variable by default. Its initial value is taken from the ",(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_EXPORT_PACKAGE_REGISTRY")," environment variable if not already defined.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"CMAKE_VERBOSE_MAKEFILE")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable verbose output from Makefile builds.")))))),(0,l.kt)("h3",{id:"consume-tinyorm-library-cmake"},"Consume TinyOrm library ",(0,l.kt)("small",null,"(cmake)")),(0,l.kt)("p",null,"In your application or library ",(0,l.kt)("inlineCode",{parentName:"p"},"CMakeLists.txt")," file add following ",(0,l.kt)("inlineCode",{parentName:"p"},"find_package()")," call."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-cmake",metastring:"title='CMakeLists.txt'",title:"'CMakeLists.txt'"},"find_package(TinyOrm 0.37.3 CONFIG REQUIRED)\n")),(0,l.kt)("p",null,"If the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," build tree is not exported to the CMake's ",(0,l.kt)("a",{parentName:"p",href:"https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#user-package-registry"},(0,l.kt)("inlineCode",{parentName:"a"},"User Package Registry"))," then also add the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," build tree or ",(0,l.kt)("inlineCode",{parentName:"p"},"CMAKE_INSTALL_PREFIX")," folder to the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMAKE_PREFIX_PATH"),", so CMake can find TinyORM's package configuration file during ",(0,l.kt)("inlineCode",{parentName:"p"},"find_package(TinyOrm)")," call."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:`cmake (${y.Fo})`,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,k.we)(y.Fo,(0,k.go)(y.Fo))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,k.we)(y.Fo,(0,k.EA)(y.Fo))}/tmp/TinyORM")`)),(0,l.kt)(d.Z,{value:y.q5,label:`cmake (${y.q5})`,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,k.we)(y.q5,(0,k.go)(y.q5))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\n# installation folder - CMAKE_INSTALL_PREFIX\nlist(APPEND CMAKE_PREFIX_PATH "${(0,k.we)(y.q5,(0,k.EA)(y.q5))}/tmp/TinyORM")`))),(0,l.kt)("p",null,"Or as an alternative, you can set ",(0,l.kt)("inlineCode",{parentName:"p"},"CMAKE_PREFIX_PATH")," environment variable."),(0,l.kt)("a",{id:"tinyorm-on-path-cmake"}),(0,l.kt)("p",null,"As the last thing, do not forget to add ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm0d.dll")," on the path on Windows and on the ",(0,l.kt)("inlineCode",{parentName:"p"},"LD_LIBRARY_PATH")," on Linux, so your application can find it during execution."),(0,l.kt)(p.Z,{groupId:y.IZ,name:"tinyorm-on-path",mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`$env:Path = "${(0,k.go)(y.Fo,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`)),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`export LD_LIBRARY_PATH=${(0,k.go)(y.q5)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`))),(0,l.kt)("p",null,"Now you can try the ",(0,l.kt)("a",{parentName:"p",href:"/building/hello-world#hello-world-with-cmake"},(0,l.kt)("inlineCode",{parentName:"a"},"HelloWorld CMake"))," example."),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"You can also try the ",(0,l.kt)("a",{parentName:"p",href:"/building/hello-world#fetchcontent"},(0,l.kt)("inlineCode",{parentName:"a"},"FetchContent"))," method to fastly link against the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library.")),(0,l.kt)("h2",{id:"building-with-qmake"},"Building with qmake"),(0,l.kt)("p",null,"First, create a basic folder structure and then clone the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," project."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,k.EA)(y.Fo)}\nmkdir ${(0,k.AE)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,k.AE)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`)),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,k.EA)(y.q5)}\nmkdir -p ${(0,k.AE)()}/TinyORM/TinyORM-builds-qmake\n\ncd ${(0,k.AE)()}/TinyORM\ngit clone git@github.com:silverqx/TinyORM.git`))),(0,l.kt)("h3",{id:"install-dependencies"},"Install dependencies"),(0,l.kt)("p",null,"With the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build system, you have to install ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," dependencies manually. We will use the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," package manager."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cd ../../vcpkg\n\nvcpkg search range-v3\nvcpkg search tabulate\nvcpkg install range-v3 tabulate\nvcpkg list\n")),(0,l.kt)("p",null,"On ",(0,l.kt)("inlineCode",{parentName:"p"},"Linux"),", you can install the ",(0,l.kt)("inlineCode",{parentName:"p"},"range-v3")," library and some other ",(0,l.kt)("a",{parentName:"p",href:"/dependencies#install-dependencies"},"dependencies")," with the package manager."),(0,l.kt)("h3",{id:"configure-and-build-qmake"},"Configure & Build ",(0,l.kt)("small",null,"(qmake)")),(0,l.kt)("h4",{id:"open-qtcreator-ide"},"Open QtCreator IDE"),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"I recommend creating a new ",(0,l.kt)("a",{parentName:"p",href:"https://doc.qt.io/qtcreator/creator-project-managing-sessions.html"},(0,l.kt)("inlineCode",{parentName:"a"},"Session"))," in the ",(0,l.kt)("inlineCode",{parentName:"p"},"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,l.kt)("inlineCode",{parentName:"p"},"QtCreator IDE"),". You can name it ",(0,l.kt)("inlineCode",{parentName:"p"},"tinyorm.org")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM examples"),", it is up to you.")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"If you are using sessions, you can use a single ",(0,l.kt)("inlineCode",{parentName:"p"},"clangd")," instance for all projects in this session in the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator IDE"),". One significant advantage of this method is that the ",(0,l.kt)("inlineCode",{parentName:"p"},".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,l.kt)("inlineCode",{parentName:"p"},"Settings")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"C++")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"Clangd")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"Sessions with a single clangd instance"),".")),(0,l.kt)("h4",{id:"configure-tinyorm"},"Configure TinyORM"),(0,l.kt)("p",null,"Now you are ready to configure the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. There are two ways how to configure the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library and it's the new ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configure")," feature added in ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"p"},"v0.34.0")," using the ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," files and the old way using the ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files."),(0,l.kt)("h5",{id:"auto-configuration-and-tiny_dotenv"},"Auto-configuration and tiny_dotenv"),(0,l.kt)("p",null,"This is the new recommended method to auto-configure TinyORM's ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build system and also the dependencies, it was added in ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"p"},"v0.34.0"),". You need to copy the prepared ",(0,l.kt)("inlineCode",{parentName:"p"},".env.(win32|unix|mingw).example")," file to the ",(0,l.kt)("inlineCode",{parentName:"p"},".env.(win32|unix|mingw)"),". One ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," example file is prepared for each supported platform."),(0,l.kt)("p",null,"All prepared ",(0,l.kt)("inlineCode",{parentName:"p"},".env.(win32|unix|mingw).example")," files are simple and clear. You can also create a common ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," file that is included before the platform-specific ",(0,l.kt)("inlineCode",{parentName:"p"},".env.(win32|unix|mingw)")," files."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,k.go)(y.Fo)}/TinyORM/TinyORM\n\ncp .env.win32.example .env.win32`)),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,k.go)(y.q5)}/TinyORM/TinyORM\n\ncp .env.unix.example .env.unix`))),(0,l.kt)("p",null,"And that is all, if you have correctly set all ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," variables in this ",(0,l.kt)("inlineCode",{parentName:"p"},".env.(win32|unix|mingw)")," file or you have correctly set environment variables, then the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build system should be able to ",(0,l.kt)("inlineCode",{parentName:"p"},"auto-detect")," all dependencies . \ud83d\udd25"),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("a",{parentName:"p",href:"#auto-configuration-internals"},(0,l.kt)("inlineCode",{parentName:"a"},"Auto-configuration"))," and ",(0,l.kt)("a",{parentName:"p",href:"#environment-files"},(0,l.kt)("inlineCode",{parentName:"a"},"Environment files"))," internals are described at the end to make this section more clear.")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature can be turned off using the ",(0,l.kt)("a",{parentName:"p",href:"#disable_autoconf"},(0,l.kt)("inlineCode",{parentName:"a"},"disable_autoconf"))," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration option (eg. ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG*=disable_autoconf"),").")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("inlineCode",{parentName:"p"},"tiny_dotenv")," feature can be turned off using the ",(0,l.kt)("a",{parentName:"p",href:"#disable_dotenv"},(0,l.kt)("inlineCode",{parentName:"a"},"disable_dotenv"))," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration option (eg. ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG*=disable_dotenv"),").")),(0,l.kt)("h5",{id:"manual-configuration-confpri"},"Manual configuration (conf.pri)"),(0,l.kt)("p",null,"This is the old method used before ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"p"},"v0.34.0"),". You need to copy the ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri.example")," files to ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," (there are four, one for every project or sub-project) and manually update the ",(0,l.kt)("inlineCode",{parentName:"p"},"INCLUDEPATH")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"LIBS")," to configure TinyORM's ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build dependencies. This way you can override any ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build options or variables."),(0,l.kt)("p",null,"To disable the ",(0,l.kt)("a",{parentName:"p",href:"#auto-configuration-internals"},(0,l.kt)("inlineCode",{parentName:"a"},"Auto-configuration"))," feature you must define the ",(0,l.kt)("a",{parentName:"p",href:"#disable_autoconf"},(0,l.kt)("inlineCode",{parentName:"a"},"disable_autoconf"))," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration option (eg. ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG*=disable_autoconf"),") because from ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"p"},"v0.34.0")," is the ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature enabled by default."),(0,l.kt)("p",null,"You can also remove all ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," files or turn off the ",(0,l.kt)("inlineCode",{parentName:"p"},"tiny_dotenv")," feature using ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG*=disable_dotenv"),". You can use them all at once if you want, ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," and also ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files are nicely commented on, so you can see what needs to be modified."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,k.go)(y.Fo)}/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,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,k.go)(y.q5)}/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,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("a",{parentName:"p",href:"#manual-configuration-internals"},(0,l.kt)("inlineCode",{parentName:"a"},"Manual configuration"))," internals are described at the end to make this section more clear.")),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("inlineCode",{parentName:"p"},"Manual configuration")," is still relevant if you have any non-standard installation of the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"MySQL")," and the ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature fails.")),(0,l.kt)("h5",{id:"opening-tinyormpro-main-project-file"},"Opening TinyORM.pro (main project file)"),(0,l.kt)("p",null,"Now you can open the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM.pro")," project in the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator IDE"),"."),(0,l.kt)("p",null,"This will open the ",(0,l.kt)("inlineCode",{parentName:"p"},"Configure Project")," tab, select some kit and update build folder paths to meet our ",(0,l.kt)("a",{parentName:"p",href:"#folders-structure"},"folders structure")," or like you want."),(0,l.kt)("img",{src:n(6874).Z,alt:"TinyORM - QtCreator - Configure Project",width:"760"}),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can force the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator")," to generate a build folders structure as is described ",(0,l.kt)("a",{parentName:"p",href:"#qtcreator-default-build-directory"},"above"),".")),(0,l.kt)("p",null,"You are ready to configure build options, hit ",(0,l.kt)("kbd",null,"Ctrl"),"+",(0,l.kt)("kbd",null,"5")," to open ",(0,l.kt)("inlineCode",{parentName:"p"},"Project Settings")," tab and select ",(0,l.kt)("inlineCode",{parentName:"p"},"Build")," in the left sidebar to open the ",(0,l.kt)("inlineCode",{parentName:"p"},"Build Settings"),", it should look similar to the following picture."),(0,l.kt)("p",null,"Disable ",(0,l.kt)("inlineCode",{parentName:"p"},"QML debugging and profiling")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"Qt Quick Compiler"),", they are not used."),(0,l.kt)("img",{src:n(7066).Z,alt:"TinyORM - QtCreator - Build Settings",width:"760"}),(0,l.kt)("p",null,"If you want to change some ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," build options, you can pass them to the ",(0,l.kt)("inlineCode",{parentName:"p"},"Build Steps")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake TinyORM.pro")," - ",(0,l.kt)("inlineCode",{parentName:"p"},"Additional arguments")," input field. It can look like this."),(0,l.kt)("img",{src:n(5705).Z,alt:"TinyORM - QtCreator - Build Settings - Additional arguments",width:"660"}),(0,l.kt)("h4",{id:"build-tinyorm-1"},"Build TinyORM"),(0,l.kt)("p",null,"Everything is ready for build, you can press ",(0,l.kt)("kbd",null,"Ctrl"),"+",(0,l.kt)("kbd",null,"b")," to build the project."),(0,l.kt)("h3",{id:"qmake-build-options"},"qmake build options"),(0,l.kt)("div",{className:"apitable-build-options"},(0,l.kt)(r.Z,{mdxType:"APITable"},(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"th"},"CONFIG")," ",(0,l.kt)("small",null,"Option Name")),(0,l.kt)("th",{parentName:"tr",align:null},"Default"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"build_loadable_drivers")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build ",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started"},(0,l.kt)("inlineCode",{parentName:"a"},"TinyDrivers"))," as a shared library and SQL database drivers (eg. ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyMySql"),") as shared libraries (",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started#the-loadable-sql-drivers-build"},(0,l.kt)("inlineCode",{parentName:"a"},"Loadable"))," modules) that are loaded at runtime using ",(0,l.kt)("inlineCode",{parentName:"td"},"LoadLibrary()")," on Windows or ",(0,l.kt)("inlineCode",{parentName:"td"},"dlopen()")," on Linux.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"build_mysql_driver")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyDrivers")," MySQL database driver.",(0,l.kt)("br",null),(0,l.kt)("small",null,"It's enabled by default when ",(0,l.kt)("inlineCode",{parentName:"td"},"build_shared_drivers"),", ",(0,l.kt)("inlineCode",{parentName:"td"},"build_loadable_drivers"),", or ",(0,l.kt)("inlineCode",{parentName:"td"},"build_static_drivers")," is enabled.",(0,l.kt)("br",null),"Available when: ",(0,l.kt)("inlineCode",{parentName:"td"},"build_shared_drivers")," OR ",(0,l.kt)("inlineCode",{parentName:"td"},"build_loadable_drivers")," OR ",(0,l.kt)("inlineCode",{parentName:"td"},"build_static_drivers")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"build_shared_drivers")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyDrivers")," as a ",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started#the-shared-library-build"},(0,l.kt)("inlineCode",{parentName:"a"},"Shared"))," library.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"build_static_drivers")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyDrivers")," as a ",(0,l.kt)("a",{parentName:"td",href:"/tinydrivers/getting-started#the-static-build"},(0,l.kt)("inlineCode",{parentName:"a"},"Static"))," library archive.",(0,l.kt)("br",null),(0,l.kt)("small",null,"The ",(0,l.kt)("inlineCode",{parentName:"td"},"build_static_drivers")," ",(0,l.kt)("inlineCode",{parentName:"td"},"qmake")," configuration option will be select by default when the ",(0,l.kt)("a",{parentName:"td",href:"#static"},(0,l.kt)("inlineCode",{parentName:"a"},"CONFIG*=static"))," is enabled."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"build_tests")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build TinyORM unit tests.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"disable_autoconf")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Disable the ",(0,l.kt)("a",{parentName:"td",href:"#auto-configuration-internals"},(0,l.kt)("inlineCode",{parentName:"a"},"Auto-configuration"))," feature ",(0,l.kt)("small",null,"(auto-configuration is enabled by default from ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"td"},"v0.34.0"),")"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"disable_dotenv")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Disable the ",(0,l.kt)("a",{parentName:"td",href:"#environment-files"},(0,l.kt)("inlineCode",{parentName:"a"},"tiny_dotenv"))," feature ",(0,l.kt)("small",null,"(environment files are enabled by default from ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"td"},"v0.34.0"),")"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"disable_thread_local")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Remove all ",(0,l.kt)("a",{parentName:"td",href:"https://en.cppreference.com/w/c/language/storage_duration"},(0,l.kt)("inlineCode",{parentName:"a"},"thread_local"))," storage duration specifiers, it disables multi-threading support.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"disable_orm")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Controls the compilation of all ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM-related")," source code, when this option is ",(0,l.kt)("inlineCode",{parentName:"td"},"enabled"),", then only the ",(0,l.kt)("inlineCode",{parentName:"td"},"query builder")," without ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM")," is compiled. Also excludes ",(0,l.kt)("inlineCode",{parentName:"td"},"ORM-related")," unit tests.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"disable_tom")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Controls the compilation of all ",(0,l.kt)("inlineCode",{parentName:"td"},"Tom-related")," source code, when this option is ",(0,l.kt)("inlineCode",{parentName:"td"},"disabled"),", then it also excludes ",(0,l.kt)("inlineCode",{parentName:"td"},"Tom-related")," unit tests.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"extern_constants")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ON")),(0,l.kt)("td",{parentName:"tr",align:null},"Use ",(0,l.kt)("inlineCode",{parentName:"td"},"extern")," constants instead of ",(0,l.kt)("inlineCode",{parentName:"td"},"inline")," constants in the ",(0,l.kt)("inlineCode",{parentName:"td"},"shared build"),".",(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"ON")," is highly recommended for the ",(0,l.kt)("inlineCode",{parentName:"td"},"shared build")," ",(0,l.kt)("small",null,"(by default)"),";",(0,l.kt)("br",null),"is always ",(0,l.kt)("inlineCode",{parentName:"td"},"OFF")," for the ",(0,l.kt)("inlineCode",{parentName:"td"},"static build"),".",(0,l.kt)("br",null),(0,l.kt)("small",null,"Available when: ",(0,l.kt)("code",null,"CONFIG(shared","|","dll):!inline_constants")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"inline_constants")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Use ",(0,l.kt)("inlineCode",{parentName:"td"},"inline")," constants instead of ",(0,l.kt)("inlineCode",{parentName:"td"},"extern")," constants in the ",(0,l.kt)("inlineCode",{parentName:"td"},"shared build"),".",(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"OFF")," is highly recommended for the ",(0,l.kt)("inlineCode",{parentName:"td"},"shared build"),";",(0,l.kt)("br",null),"is always ",(0,l.kt)("inlineCode",{parentName:"td"},"ON")," for the ",(0,l.kt)("inlineCode",{parentName:"td"},"static build"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"link_pkgconfig_off")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Link against ",(0,l.kt)("inlineCode",{parentName:"td"},"mysqlclient")," or ",(0,l.kt)("inlineCode",{parentName:"td"},"libmariadb")," with ",(0,l.kt)("inlineCode",{parentName:"td"},"PKGCONFIG"),".",(0,l.kt)("br",null),"Used only in the ",(0,l.kt)("inlineCode",{parentName:"td"},"Unix")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"MinGW")," ",(0,l.kt)("strong",{parentName:"td"},"shared")," build ",(0,l.kt)("small",null,"(exactly ",(0,l.kt)("code",null,"win32-g++","|","win32-clang-g++"),")")," and when ",(0,l.kt)("inlineCode",{parentName:"td"},"mysql_ping")," is also defined to link against ",(0,l.kt)("inlineCode",{parentName:"td"},"mysqlclient")," or ",(0,l.kt)("inlineCode",{parentName:"td"},"libmariadb"),", ",(0,l.kt)("a",{parentName:"td",href:"https://github.com/silverqx/TinyORM/blob/main/conf.pri.example#L132"},"source code"),".",(0,l.kt)("br",null),(0,l.kt)("small",null,"Available when: ",(0,l.kt)("inlineCode",{parentName:"td"},"unix:mysql_ping")," or ",(0,l.kt)("code",null,"(win32-g++","|","win32-clang-g++):mysql_ping:!static:!staticlib")))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"mysql_ping")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable ",(0,l.kt)("inlineCode",{parentName:"td"},"Orm::MySqlConnection::pingDatabase()")," method.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"tiny_ccache_win32")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ON")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable compiler cache. ",(0,l.kt)("a",{parentName:"td",href:"https://ccache.dev/"},"Homepage"),(0,l.kt)("br",null),(0,l.kt)("small",null,"It works only on Windows systems. It works well with the MSYS2 ",(0,l.kt)("inlineCode",{parentName:"td"},"g++"),", ",(0,l.kt)("inlineCode",{parentName:"td"},"clang++"),", ",(0,l.kt)("inlineCode",{parentName:"td"},"msvc"),", and ",(0,l.kt)("inlineCode",{parentName:"td"},"clang-cl")," with ",(0,l.kt)("inlineCode",{parentName:"td"},"msvc"),". It disables ",(0,l.kt)("inlineCode",{parentName:"td"},"precompile_header")," as they are not supported on Windows and changes the ",(0,l.kt)("inlineCode",{parentName:"td"},"-Zi")," compiler option to the ",(0,l.kt)("inlineCode",{parentName:"td"},"-Z7")," for debug builds as the ",(0,l.kt)("inlineCode",{parentName:"td"},"-Zi")," compiler option is not supported (",(0,l.kt)("a",{parentName:"td",href:"https://github.com/ccache/ccache/issues/1040"},"link")," to the issue)."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"tom_example")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build the ",(0,l.kt)("abbr",{title:"TinyORM Migrations"},(0,l.kt)("inlineCode",{parentName:"td"},"tom"))," console application example.")))))),(0,l.kt)("p",null,"Advanced ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," options."),(0,l.kt)("div",{className:"apitable-build-options"},(0,l.kt)(r.Z,{mdxType:"APITable"},(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Option Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Default"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ubsan")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Allows to enable ",(0,l.kt)("a",{parentName:"td",href:"https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html"},"UBSan")," sanitizer (Clang only).")))))),(0,l.kt)("p",null,"Important ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," options."),(0,l.kt)("div",{className:"apitable-build-options"},(0,l.kt)(r.Z,{mdxType:"APITable"},(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"th"},"CONFIG")," ",(0,l.kt)("small",null,"Option Name")),(0,l.kt)("th",{parentName:"tr",align:null},"Default"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ccache")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable compiler cache. ",(0,l.kt)("a",{parentName:"td",href:"https://ccache.dev/"},"Homepage"),(0,l.kt)("br",null),(0,l.kt)("small",null,"It works only on the Unix systems. It works well with the ",(0,l.kt)("inlineCode",{parentName:"td"},"g++")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"clang++")," and also supports precompiled headers."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"precompile_header")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"-")),(0,l.kt)("td",{parentName:"tr",align:null},"Enable precompiled headers, you can disable them with:",(0,l.kt)("br",null)," ",(0,l.kt)("inlineCode",{parentName:"td"},"CONFIG-=precompile_header"),".",(0,l.kt)("br",null),(0,l.kt)("small",null,"The ",(0,l.kt)("inlineCode",{parentName:"td"},"precompile_header")," is enabled by default on ",(0,l.kt)("inlineCode",{parentName:"td"},"msvc"),", ",(0,l.kt)("inlineCode",{parentName:"td"},"g++"),", ",(0,l.kt)("inlineCode",{parentName:"td"},"clang++"),", ",(0,l.kt)("inlineCode",{parentName:"td"},"clang-cl")," on ",(0,l.kt)("inlineCode",{parentName:"td"},"Windows")," and disabled by default on ",(0,l.kt)("inlineCode",{parentName:"td"},"linux"),"."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"static"),(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"staticlib")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Build as a ",(0,l.kt)("inlineCode",{parentName:"td"},"static")," library (lib only).",(0,l.kt)("br",null),(0,l.kt)("small",null,"If you want to build all libraries in the ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," project as static library archives and link against static libraries use the ",(0,l.kt)("a",{parentName:"td",href:"https://doc.qt.io/qt/qmake-variable-reference.html#config"},(0,l.kt)("inlineCode",{parentName:"a"},"CONFIG += static")),". Don't use the ",(0,l.kt)("inlineCode",{parentName:"td"},"CONFIG += staticlib"),".",(0,l.kt)("br",null),"See ",(0,l.kt)("a",{parentName:"td",href:"https://github.com/silverqx/TinyORM/blob/main/NOTES.txt"},"NOTES.txt")," for more information (search ",(0,l.kt)("inlineCode",{parentName:"td"},"static vs staticlib"),")."))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"static_runtime")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"OFF")),(0,l.kt)("td",{parentName:"tr",align:null},"Link against the ",(0,l.kt)("inlineCode",{parentName:"td"},"shared")," (dynamic) or ",(0,l.kt)("inlineCode",{parentName:"td"},"static")," run-time library.",(0,l.kt)("br",null),(0,l.kt)("small",null,"The ",(0,l.kt)("inlineCode",{parentName:"td"},"-MD")," becomes ",(0,l.kt)("inlineCode",{parentName:"td"},"-MT")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"-MDd")," becomes ",(0,l.kt)("inlineCode",{parentName:"td"},"-MTd"),". It works only on ",(0,l.kt)("inlineCode",{parentName:"td"},"MSVC")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"MinGW")," or ",(0,l.kt)("inlineCode",{parentName:"td"},"MSYS2"),".",(0,l.kt)("br",null),"Please ",(0,l.kt)("u",null,"don't use")," this option.",(0,l.kt)("br",null),"Available when: ",(0,l.kt)("inlineCode",{parentName:"td"},"msvc")," or ",(0,l.kt)("inlineCode",{parentName:"td"},"mingw")))))))),(0,l.kt)("h3",{id:"consume-tinyorm-library-qmake"},"Consume TinyOrm library ",(0,l.kt)("small",null,"(qmake)")),(0,l.kt)("p",null,"The ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/qmake/TinyOrm.pri"},(0,l.kt)("inlineCode",{parentName:"a"},"TinyOrm.pri"))," file is available to simplify the integration of the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library into your application. It sets up and configures the ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"DEFINES")," qmake variables, adds the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM"),", ",(0,l.kt)("abbr",{title:"TinyORM Migrations"},(0,l.kt)("inlineCode",{parentName:"p"},"tom")),", and ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," header files on the system ",(0,l.kt)("inlineCode",{parentName:"p"},"INCLUDEPATH")," (cross-platform using the ",(0,l.kt)("inlineCode",{parentName:"p"},"-isystem")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"-imsvc"),"), links against the TinyORM ",(0,l.kt)("inlineCode",{parentName:"p"},"shared")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"static")," library using the ",(0,l.kt)("inlineCode",{parentName:"p"},"LIBS"),"."),(0,l.kt)("p",null,"You can use it to configure the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library when you are linking against it. It does a very similar thing like the CMake's ",(0,l.kt)("inlineCode",{parentName:"p"},"Find Modules")," feature."),(0,l.kt)("h4",{id:"requirements"},"Requirements"),(0,l.kt)("p",null,"It has a few requirements, you need to:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"specify path to the ",(0,l.kt)("inlineCode",{parentName:"li"},"TinyORM")," qmake features (",(0,l.kt)("inlineCode",{parentName:"li"},".prf")," files) using the ",(0,l.kt)("inlineCode",{parentName:"li"},"QMAKEFEATURES")," variable that can only be set in the ",(0,l.kt)("inlineCode",{parentName:"li"},".qmake.conf")," file"),(0,l.kt)("li",{parentName:"ul"},"specify ",(0,l.kt)("inlineCode",{parentName:"li"},"qmake")," or ",(0,l.kt)("inlineCode",{parentName:"li"},"environment")," variables to find the ",(0,l.kt)("inlineCode",{parentName:"li"},"vcpkg")," installation ",(0,l.kt)("small",null,"(",(0,l.kt)("inlineCode",{parentName:"li"},"TINY_VCPKG_ROOT")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"TINY_VCPKG_TRIPLET"),")")),(0,l.kt)("li",{parentName:"ul"},"specify path to the ",(0,l.kt)("inlineCode",{parentName:"li"},"TinyORM")," build folder ",(0,l.kt)("small",null,"(",(0,l.kt)("inlineCode",{parentName:"li"},"TINYORM_BUILD_TREE"),")"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},"you can specify it ",(0,l.kt)("strong",{parentName:"li"},"manually")),(0,l.kt)("li",{parentName:"ul"},"or you can use ",(0,l.kt)("a",{parentName:"li",href:"#partial-guessing-of-the-tinyorm_build_tree"},"Partial guessing of the ",(0,l.kt)("inlineCode",{parentName:"a"},"TINYORM_BUILD_TREE"))))),(0,l.kt)("li",{parentName:"ul"},"build your application with the same ",(0,l.kt)("inlineCode",{parentName:"li"},"CONFIG")," ",(0,l.kt)("inlineCode",{parentName:"li"},"qmake")," variables that were used when building the ",(0,l.kt)("inlineCode",{parentName:"li"},"TinyORM")," library")),(0,l.kt)("p",null,"Let's explain one by one."),(0,l.kt)("h5",{id:"qmakefeatures"},(0,l.kt)("inlineCode",{parentName:"h5"},"QMAKEFEATURES")),(0,l.kt)("p",null,"Create the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file in your application root folder with the following content."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='.qmake.conf'",title:"'.qmake.conf'"},"# 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_0_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")),(0,l.kt)("p",null,"You can move all ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," variables that are part of the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration process to the ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," file if you want (recommended), this is possible because the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm.pri")," enables the ",(0,l.kt)("a",{parentName:"p",href:"#environment-files"},(0,l.kt)("inlineCode",{parentName:"a"},"Environment files"))," feature by default."),(0,l.kt)("p",null,"You can look at the ",(0,l.kt)("a",{parentName:"p",href:"/building/hello-world#auto-configure-using-qmake_conf-and-env"},"Auto-configure using .qmake.conf and .env")," example for ",(0,l.kt)("inlineCode",{parentName:"p"},"Hello world")," project of what must stay in the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake.conf")," file and what can be moved to the ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," files."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can use the ",(0,l.kt)("a",{parentName:"p",href:"#partial-guessing-of-the-tinyorm_build_tree"},"Partial guessing of the ",(0,l.kt)("inlineCode",{parentName:"a"},"TINYORM_BUILD_TREE"))," if you don't like to specify it manually.")),(0,l.kt)("h5",{id:"variables-affecting-tinyormpri"},"Variables affecting ",(0,l.kt)("inlineCode",{parentName:"h5"},"TinyOrm.pri")),(0,l.kt)("p",null,"You must define the following variables before the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm.pri")," is included:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Variable Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINYORM_BUILD_TREE")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," build folder.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_VCPKG_ROOT")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," installation folder.",(0,l.kt)("br",null),"If not defined, then it tries to use the ",(0,l.kt)("inlineCode",{parentName:"td"},"VCPKG_ROOT")," environment variable.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_VCPKG_TRIPLET")),(0,l.kt)("td",{parentName:"tr",align:null},"The ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," ",(0,l.kt)("inlineCode",{parentName:"td"},"triplet")," to use ",(0,l.kt)("small",null,"(vcpkg/installed/$$TINY_VCPKG_TRIPLET/)"),".",(0,l.kt)("br",null),"If not defined, then it tries to guess the ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," ",(0,l.kt)("inlineCode",{parentName:"td"},"triplet")," based on the current compiler and OS (based on the ",(0,l.kt)("inlineCode",{parentName:"td"},"QMAKESPEC"),"), and as the last thing, it tries to use the ",(0,l.kt)("inlineCode",{parentName:"td"},"VCPKG_DEFAULT_TRIPLET")," environment variable.")))),(0,l.kt)("p",null,"These variables will be set after the configuration is done:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Variable Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_BUILD_SUBFOLDER")),(0,l.kt)("td",{parentName:"tr",align:null},"Folder by release type if ",(0,l.kt)("inlineCode",{parentName:"td"},"CONFIG+=debug_and_release")," is defined ",(0,l.kt)("small",null,"(/debug, /release, or an empty string)"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_CCACHE_BUILD")),(0,l.kt)("td",{parentName:"tr",align:null},"To correctly link ",(0,l.kt)("inlineCode",{parentName:"td"},"ccache")," build against a ",(0,l.kt)("inlineCode",{parentName:"td"},"ccache")," build ",(0,l.kt)("small",null,"(_ccache or an empty string)"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_MSVC_VERSION")),(0,l.kt)("td",{parentName:"tr",align:null},"The ",(0,l.kt)("inlineCode",{parentName:"td"},"msvc")," compiler string ",(0,l.kt)("small",null,"(MSVC2022 or MSVC2019)"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_QT_VERSION_UNDERSCORED")),(0,l.kt)("td",{parentName:"tr",align:null},"Underscored ",(0,l.kt)("inlineCode",{parentName:"td"},"Qt")," version ",(0,l.kt)("small",null,"(eg. 6_7_0)"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_RELEASE_TYPE_CAMEL")),(0,l.kt)("td",{parentName:"tr",align:null},"Build type string ",(0,l.kt)("small",null,"(Debug, Profile, or Release)"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_VCPKG_INCLUDE")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," ",(0,l.kt)("inlineCode",{parentName:"td"},"include")," folder ",(0,l.kt)("small",null,"(vcpkg/installed/","<","triplet",">","/include/)"),".")))),(0,l.kt)("p",null,"Then you simply include the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm.pri")," in your project file."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='AnyProject.pro'",title:"'AnyProject.pro'"},"include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n")),(0,l.kt)("p",null,"And that is all, now you should be able to link against the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. \ud83d\udc4c"),(0,l.kt)("h5",{id:"manual-configuration-examples"},"Manual configuration examples"),(0,l.kt)("p",null,"Frankly, there is no reason to use the Manual configuration (define the variables described below before the ",(0,l.kt)("inlineCode",{parentName:"p"},"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."),(0,l.kt)("p",null,"You will have to link against the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library manually if you don't set the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," variable before the inclusion of the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm.pri")," file. The ",(0,l.kt)("inlineCode",{parentName:"p"},"INCLUDEPATH")," is auto-detected every time."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"{9}","{9}":!0},"# 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_0_MSVC2019_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)\nLIBS += -lTinyOrm\n"))),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"{9}","{9}":!0},"# 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_0_GCC_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)\nLIBS += -lTinyOrm\n")))),(0,l.kt)("p",null,"The same is true for the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," include path. If you don't set the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINY_VCPKG_ROOT")," or have not defined the ",(0,l.kt)("inlineCode",{parentName:"p"},"VCPKG_ROOT")," environment variable, then you need to set up the ",(0,l.kt)("inlineCode",{parentName:"p"},"INCLUDEPATH")," for the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," that provides the ",(0,l.kt)("inlineCode",{parentName:"p"},"range-v3")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"tabulate")," header files."),(0,l.kt)(p.Z,{groupId:y.IZ,mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake"},"# vcpkg - range-v3 and tabulate\n# ---\nINCLUDEPATH += $$quote(/vcpkg/installed/x64-windows/include/)\n"))),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake"},"# vcpkg - range-v3 and tabulate\n# ---\nQMAKE_CXXFLAGS += -isystem $$shell_quote(/vcpkg/installed/x64-linux/include/)\n")))),(0,l.kt)("p",null,"You can also use TinyORM's ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," function ",(0,l.kt)("inlineCode",{parentName:"p"},"tiny_add_system_includepath()")," which handles ",(0,l.kt)("inlineCode",{parentName:"p"},"INCLUDEPATH")," in a cross-platform way."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake"},"# vcpkg - range-v3 and tabulate\n# ---\nload(tiny_system_includepath)\ntiny_add_system_includepath(/vcpkg/installed/x64-linux/include/)\n")),(0,l.kt)("p",null,"Do not forget to add ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm0.dll")," on the path on Windows and on the ",(0,l.kt)("inlineCode",{parentName:"p"},"LD_LIBRARY_PATH")," on Linux, so your application can find it during execution."),(0,l.kt)(p.Z,{groupId:y.IZ,name:"tinyorm-on-path",mdxType:"Tabs"},(0,l.kt)(d.Z,{value:y.Fo,label:y.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`$env:Path = "${(0,k.go)(y.Fo,!1)}\\TinyORM\\TinyORM-builds-qmake\\build-debug;" + $env:Path`)),(0,l.kt)(d.Z,{value:y.q5,label:y.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`export LD_LIBRARY_PATH=${(0,k.go)(y.q5)}/TinyORM/TinyORM-builds-qmake/build-debug\${PATH:+:}$PATH`))),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"On Linux ",(0,l.kt)("inlineCode",{parentName:"p"},"-isystem")," marks the directory as a system directory, it prevents warnings."),(0,l.kt)("p",{parentName:"admonition"},"On Windows you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"QMAKE_CXXFLAGS_WARN_ON = -external:anglebrackets -external:W0"),", it applies a warning level 0 to the angel bracket includes; ",(0,l.kt)("inlineCode",{parentName:"p"},"#include "),"."),(0,l.kt)("p",{parentName:"admonition"},"With the ",(0,l.kt)("inlineCode",{parentName:"p"},"clang-cl")," with ",(0,l.kt)("inlineCode",{parentName:"p"},"MSVC")," you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"-imsvc"),".")),(0,l.kt)("h3",{id:"auto-configuration-internals"},"Auto-configuration internals"),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build system does not support ",(0,l.kt)("inlineCode",{parentName:"p"},"auto-configuration")," of dependencies out of the box but ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," from ",(0,l.kt)("inlineCode",{parentName:"p"},"v0.34.0")," added its own ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature along with the ",(0,l.kt)("inlineCode",{parentName:"p"},"tiny_dotenv")," qmake feature. These new features allow us to ",(0,l.kt)("inlineCode",{parentName:"p"},"auto-configure")," ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," project, and with their help, the ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files can be ",(0,l.kt)("u",null,"skipped entirely"),"."),(0,l.kt)("p",null,"While it adds additional complexity to the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration process, the benefits are significant."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature is designed to find the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"MySQL")," installations, and ",(0,l.kt)("inlineCode",{parentName:"p"},"tiny_dotenv")," to include the ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," and ",(0,l.kt)("inlineCode",{parentName:"p"},".env.(win32|unix|mingw)")," files in the project's root folder. These new features can be configured using ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"environment")," variables, and they also contain some guessing logic if these variables are not defined."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature can be turned off using the ",(0,l.kt)("a",{parentName:"p",href:"#disable_autoconf"},(0,l.kt)("inlineCode",{parentName:"a"},"disable_autoconf"))," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration option (eg. ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG*=disable_autoconf"),")."),(0,l.kt)("p",null,"These are ",(0,l.kt)("u",null,(0,l.kt)("inlineCode",{parentName:"p"},"qmake"))," and ",(0,l.kt)("u",null,(0,l.kt)("inlineCode",{parentName:"p"},"environment"))," variables that affect the ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Variable Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_VCPKG_ROOT")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," installation folder.",(0,l.kt)("br",null),"If not defined, then it tries to use the ",(0,l.kt)("inlineCode",{parentName:"td"},"VCPKG_ROOT")," environment variable.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_VCPKG_TRIPLET")),(0,l.kt)("td",{parentName:"tr",align:null},"The ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," ",(0,l.kt)("inlineCode",{parentName:"td"},"triplet")," to use ",(0,l.kt)("small",null,"(vcpkg/installed/$$TINY_VCPKG_TRIPLET/)"),".",(0,l.kt)("br",null),"If not defined, then it tries to guess the ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," ",(0,l.kt)("inlineCode",{parentName:"td"},"triplet")," based on the current compiler and OS (based on the ",(0,l.kt)("inlineCode",{parentName:"td"},"QMAKESPEC"),"), and as the last thing, it tries to use the ",(0,l.kt)("inlineCode",{parentName:"td"},"VCPKG_DEFAULT_TRIPLET")," environment variable.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_MYSQL_ROOT")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"MySQL")," installation folder.",(0,l.kt)("br",null),"If not defined, then it tries to guess the ",(0,l.kt)("inlineCode",{parentName:"td"},"MySQL")," installation folder (",(0,l.kt)("inlineCode",{parentName:"td"},"win32")," only): ",(0,l.kt)("code",null,"$$(ProgramFiles)/MySQL/MySQL Server (8.3","|","8.2","|","8.1","|","8.0","|","5.7)/"))))),(0,l.kt)("p",null,"You can set these variables in the ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," (recommended) or ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files, in the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file (or wherever you want), or as environment variables."),(0,l.kt)("p",null,"These variables will be set after ",(0,l.kt)("inlineCode",{parentName:"p"},"auto-configuration")," is done:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Variable Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_VCPKG_INCLUDE")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"vcpkg")," ",(0,l.kt)("inlineCode",{parentName:"td"},"include")," folder ",(0,l.kt)("small",null,"(vcpkg/installed/","<","triplet",">","/include/)"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_MYSQL_INCLUDE")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"MySQL")," ",(0,l.kt)("inlineCode",{parentName:"td"},"include")," folder ",(0,l.kt)("small",null,"(MySQL Server 8.3/include/)"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_MYSQL_LIB")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("inlineCode",{parentName:"td"},"MySQL")," ",(0,l.kt)("inlineCode",{parentName:"td"},"lib")," folder ",(0,l.kt)("small",null,"(MySQL Server 8.3/lib/)"),".")))),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"TINY_MYSQL_INCLUDE")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"TINY_MYSQL_LIB")," are only set on ",(0,l.kt)("inlineCode",{parentName:"p"},"win32")," platform except ",(0,l.kt)("inlineCode",{parentName:"p"},"mingw"),"."),(0,l.kt)("h4",{id:"environment-files"},"Environment files"),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"tiny_dotenv")," feature allows us to define the ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," and ",(0,l.kt)("inlineCode",{parentName:"p"},".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,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration process. On the other hand, the ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files are loaded as late as possible, and they can be used to override the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," file is included ",(0,l.kt)("u",null,"first")," and is included on all platforms."),(0,l.kt)("p",null,"There is only one requirement for this feature to work correctly, and that is to set the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINY_DOTENV_ROOT")," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," variable to the project's root folder. This variable is ",(0,l.kt)("strong",{parentName:"p"},"already")," set in the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file for the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," project."),(0,l.kt)("p",null,"Then the following names are taken into account: .env, .env.win32, .env.unix, .env.mingw"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='.qmake.conf'",title:"'.qmake.conf'"},"# To find .env and .env.$$QMAKE_PLATFORM files\nTINY_DOTENV_ROOT = $$PWD\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"tiny_dotenv")," feature can be turned off using the ",(0,l.kt)("a",{parentName:"p",href:"#disable_dotenv"},(0,l.kt)("inlineCode",{parentName:"a"},"disable_dotenv"))," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration option (eg. ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG*=disable_dotenv"),")."),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},(0,l.kt)("inlineCode",{parentName:"p"},"Environment files")," don't work in the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," builds.")),(0,l.kt)("h4",{id:"partial-guessing-of-the-tinyorm_build_tree"},"Partial guessing of the ",(0,l.kt)("inlineCode",{parentName:"h4"},"TINYORM_BUILD_TREE")),(0,l.kt)("p",null,"You don't have to manually define the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," in ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," or ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," files. The ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," absolute path can be put together for you (this is happening inside the ",(0,l.kt)("inlineCode",{parentName:"p"},"variables.pri")," file) and ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," build folder name can be guessed for you too."),(0,l.kt)("p",null,"You must define the following variables before the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm.pri")," will be included to make this real (set them in the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf"),"):"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Variable Name"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_MAIN_DIR")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("strong",{parentName:"td"},"PARENT")," folder of the ",(0,l.kt)("inlineCode",{parentName:"td"},"TinyORM")," source folder.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"TINY_BUILD_TREE")),(0,l.kt)("td",{parentName:"tr",align:null},"Path to the ",(0,l.kt)("strong",{parentName:"td"},"current")," build tree - ",(0,l.kt)("inlineCode",{parentName:"td"},"TINY_BUILD_TREE = $$shadowed($$PWD)"),".")))),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"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,l.kt)("inlineCode",{parentName:"p"},"TINY_BUILD_TREE"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='.qmake.conf'",title:"'.qmake.conf'"},"# Path to the current build tree (used to guess the TinyORM build tree)\nTINY_BUILD_TREE = $$shadowed($$PWD)\n")),(0,l.kt)("p",null,"If you will follow this pattern or logic then you can switch ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator Kits")," and the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," will be ",(0,l.kt)("strong",{parentName:"p"},"auto-generated")," correctly and will always point to the correct ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," build tree."),(0,l.kt)("p",null,"It works this way, all is happening inside the ",(0,l.kt)("inlineCode",{parentName:"p"},"variables.pri"),", it takes a build folder name for the ",(0,l.kt)("strong",{parentName:"p"},"current")," project eg. ",(0,l.kt)("inlineCode",{parentName:"p"},"build-HelloWorld-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug"),", replaces the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," with the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," and as we already know the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," build folder location we can simply concatenate these paths like ",(0,l.kt)("inlineCode",{parentName:"p"},"$$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug"),"."),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"This will only work if you follow the recommended ",(0,l.kt)("a",{parentName:"p",href:"#folders-structure"},(0,l.kt)("inlineCode",{parentName:"a"},"Folders structure")),".")),(0,l.kt)("h3",{id:"manual-configuration-internals"},"Manual configuration internals"),(0,l.kt)("p",null,"There is not much to say about the ",(0,l.kt)("inlineCode",{parentName:"p"},"Manual configuration")," feature. It uses ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files (there are four, one for every project or sub-project), and every project has prepared its own ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri.example")," file for faster initial configuration."),(0,l.kt)("p",null,"These ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri.example")," files are nicely commented on, so you can see what needs to be modified. The ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files are loaded as late as possible, and they can be used to override the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration."),(0,l.kt)("p",null,"If the ",(0,l.kt)("inlineCode",{parentName:"p"},"Auto-configuration")," feature is disabled and there are no ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files, then the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," configuration or build will fail at 100%."),(0,l.kt)("p",null,"These ",(0,l.kt)("inlineCode",{parentName:"p"},"conf.pri")," files are intended for configuring qmake's ",(0,l.kt)("inlineCode",{parentName:"p"},"INCLUDEPATH")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"LIBS"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG")," or eg. ",(0,l.kt)("inlineCode",{parentName:"p"},"QMAKE_LFLAGS"),", or any other ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," options or variables."),(0,l.kt)("h2",{id:"ccache-support"},"Ccache support"),(0,l.kt)("p",null,"The TinyORM supports the ",(0,l.kt)("a",{parentName:"p",href:"https://ccache.dev/"},(0,l.kt)("inlineCode",{parentName:"a"},"ccache"))," out of the box for all ",(0,l.kt)("a",{parentName:"p",href:"/supported-compilers"},"supported compilers"),". For qmake you can enable it using the ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG+=ccache")," on Linux or ",(0,l.kt)("inlineCode",{parentName:"p"},"CONFIG+=tiny_ccache_win32")," on Windows. For CMake you can set the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMAKE_CXX_COMPILER_LAUNCHER=ccache"),"."),(0,l.kt)("p",null,"On ",(0,l.kt)("inlineCode",{parentName:"p"},"Linux")," it's clear, the ccache is fully supported and works also with the ",(0,l.kt)("inlineCode",{parentName:"p"},"precompiled headers"),". But was necessary to add some workarounds to the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake"),"/",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," build systems to make out of the box support on ",(0,l.kt)("inlineCode",{parentName:"p"},"Windows"),". When you enable the ",(0,l.kt)("inlineCode",{parentName:"p"},"ccache")," on ",(0,l.kt)("inlineCode",{parentName:"p"},"Windows")," then the build system disables ",(0,l.kt)("inlineCode",{parentName:"p"},"precompiled headers")," and replaces the ",(0,l.kt)("inlineCode",{parentName:"p"},"-Zi")," compiler option with the ",(0,l.kt)("inlineCode",{parentName:"p"},"-Z7")," (link to the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/ccache/ccache/issues/1040"},"issue"),")."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can install the ccache using the ",(0,l.kt)("inlineCode",{parentName:"p"},"scoop install ccache")," command on Windows.")))}M.isMDXComponent=!0},5705:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/qmake-additional_arguments-14d3b6b82ad6d28db5b999a462500a6a.png"},7066:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/qmake-build_settings-7caa6d7c86232484b82acb24b5a3a6a7.png"},6874:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/qmake-configure_project-0b6821ea0523567dab9f21b3215055a3.png"}}]); \ No newline at end of file diff --git a/assets/js/1222ea4e.2cd8af81.js b/assets/js/1222ea4e.2cd8af81.js new file mode 100644 index 000000000..6c85be8b5 --- /dev/null +++ b/assets/js/1222ea4e.2cd8af81.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[153],{5897:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>d});var t=i(4848),s=i(8453);const o={sidebar_position:4,sidebar_label:"Serialization",description:"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.",keywords:["c++ orm","orm","serialization","json","toJson","serializing models","serializing relations","serializing collections","converting","toVector","toMap"]},r="TinyORM: Serialization",a={id:"tinyorm/serialization",title:"TinyORM: Serialization",description:"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.",source:"@site/docs/tinyorm/serialization.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/serialization",permalink:"/tinyorm/serialization",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,sidebar_label:"Serialization",description:"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.",keywords:["c++ orm","orm","serialization","json","toJson","serializing models","serializing relations","serializing collections","converting","toVector","toMap"]},sidebar:"tinyormSidebar",previous:{title:"Casts",permalink:"/tinyorm/casts"},next:{title:"Getting Started",permalink:"/tinydrivers/getting-started"}},l={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Serializing Models & Collections",id:"serializing-models-and-collections",level:2},{value:"Serializing To Vectors & Maps",id:"serializing-to-vectors-and-maps",level:3},{value:"Serializing To JSON",id:"serializing-to-json",level:3},{value:"Relationships",id:"relationships",level:4},{value:"Hiding Attributes From JSON",id:"hiding-attributes-from-json",level:2},{value:"Temporarily Modifying Attribute Visibility",id:"temporarily-modifying-attribute-visibility",level:4},{value:"Appending Values To JSON",id:"appending-values-to-json",level:2},{value:"Appending At Run Time",id:"appending-at-run-time",level:4},{value:"Date Serialization",id:"date-serialization",level:2},{value:"Customizing The Default Date Format",id:"customizing-the-default-date-format",level:4},{value:"Customizing The Date Format Per Attribute",id:"customizing-the-date-format-per-attribute",level:4}];function c(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,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"tinyorm-serialization",children:"TinyORM: Serialization"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"#serializing-models-and-collections",children:"Serializing Models & Collections"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#serializing-to-vectors-and-maps",children:"Serializing To Vectors & Maps"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#serializing-to-json",children:"Serializing To JSON"})}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#hiding-attributes-from-json",children:"Hiding Attributes From JSON"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#appending-values-to-json",children:"Appending Values To JSON"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"#date-serialization",children:"Date Serialization"})}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,t.jsx)(n.p,{children:"When building APIs using TinyORM, you will often need to convert your models and relationships to vectors, maps, or JSON. TinyORM includes convenient methods for making these conversions, as well as controlling which attributes are included in the serialized representation of your models."}),"\n",(0,t.jsx)(n.h2,{id:"serializing-models-and-collections",children:"Serializing Models & Collections"}),"\n",(0,t.jsx)(n.h3,{id:"serializing-to-vectors-and-maps",children:"Serializing To Vectors & Maps"}),"\n",(0,t.jsxs)(n.p,{children:["To convert a model and its loaded ",(0,t.jsx)(n.a,{href:"/tinyorm/relationships",children:"relationships"})," to a vector, you should use the ",(0,t.jsx)(n.code,{children:"toVector"})," or ",(0,t.jsx)(n.code,{children:"toMap"})," methods. This methods are recursive, so all attributes and all relations (including the relations of relations) will be converted to vectors:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nauto user = User::with("roles")->first();\n\nreturn user->toVector();\n\nreturn user->toMap();\n'})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"attributesToVector"})," or ",(0,t.jsx)(n.code,{children:"attributesToMap"})," methods may be used to convert a model's attributes to a vector or map but not its relationships:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:"auto user = User::first();\n\nreturn user->attributesToVector();\n\nreturn user->attributesToMap();\n"})}),"\n",(0,t.jsxs)(n.p,{children:["You may also convert entire ",(0,t.jsx)(n.a,{href:"/tinyorm/collections",children:"collections"})," of models to vectors or maps by calling the ",(0,t.jsx)(n.a,{href:"/tinyorm/collections#method-tovector",children:(0,t.jsx)(n.code,{children:"toVector"})})," or ",(0,t.jsx)(n.a,{href:"/tinyorm/collections#method-tomap",children:(0,t.jsx)(n.code,{children:"toMap"})})," methods on the collection instance:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users = User::with("roles")->all();\n\nreturn users.toVector();\n\nreturn users.toMap();\n'})}),"\n",(0,t.jsx)(n.h3,{id:"serializing-to-json",children:"Serializing To JSON"}),"\n",(0,t.jsxs)(n.p,{children:["To convert a model to JSON, you should use the ",(0,t.jsx)(n.code,{children:"toJson"})," method. Like ",(0,t.jsx)(n.code,{children:"toVector"})," or ",(0,t.jsx)(n.code,{children:"toMap"}),", the ",(0,t.jsx)(n.code,{children:"toJson"})," method is recursive, so all attributes and relations will be converted to JSON. You may also specify any JSON encoding options that are supported by ",(0,t.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html#toJson",children:"QJsonDocument::toJson"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nauto user = User::with("roles")->find(1);\n\nreturn user->toJson();\n\nreturn user->toJson(QJsonDocument::Indented);\n'})}),"\n",(0,t.jsxs)(n.p,{children:["You may also convert entire ",(0,t.jsx)(n.a,{href:"/tinyorm/collections",children:"collections"})," of models to JSON by calling the ",(0,t.jsx)(n.a,{href:"/tinyorm/collections#method-tojson",children:(0,t.jsx)(n.code,{children:"toJson"})})," method on the collection instance:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection users = User::with("roles")->findMany({1, 2});\n\nreturn users.toJson();\n'})}),"\n",(0,t.jsxs)(n.p,{children:["You can also convert models to the ",(0,t.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsonobject.html",children:(0,t.jsx)(n.code,{children:"QJsonObject"})})," and ",(0,t.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html",children:(0,t.jsx)(n.code,{children:"QJsonDocument"})})," using the ",(0,t.jsx)(n.code,{children:"toJsonArray"})," and ",(0,t.jsx)(n.code,{children:"toJsonDocument"})," methods and collection of models to ",(0,t.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsonarray.html",children:(0,t.jsx)(n.code,{children:"QJsonArray"})})," and ",(0,t.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html",children:(0,t.jsx)(n.code,{children:"QJsonDocument"})})," using the ",(0,t.jsx)(n.a,{href:"/tinyorm/collections#method-tojsonarray",children:(0,t.jsx)(n.code,{children:"toJsonArray"})})," and ",(0,t.jsx)(n.a,{href:"/tinyorm/collections#method-tojsondocument",children:(0,t.jsx)(n.code,{children:"toJsonDocument"})})," methods."]}),"\n",(0,t.jsx)(n.h4,{id:"relationships",children:"Relationships"}),"\n",(0,t.jsx)(n.p,{children:'When a TinyORM model is converted to JSON, its loaded relationships will automatically be included as attributes on the JSON object. Also, though TinyORM relationship methods are defined using "camelCase" method names, a relationship\'s JSON attributes will be "snake_case".'}),"\n",(0,t.jsxs)(n.p,{children:["This behavior is affected and can be overridden by the ",(0,t.jsx)(n.code,{children:"u_snakeAttributes"})," static data member:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:"#include \n\nusing Orm::Tiny::Model;\n\nclass Album final : public Model\n{\n friend Model;\n using Model::Model;\n\n /*! Indicates whether attributes are snake_cased during serialization. */\n inline static const bool u_snakeAttributes = false;\n};\n"})}),"\n",(0,t.jsx)(n.h2,{id:"hiding-attributes-from-json",children:"Hiding Attributes From JSON"}),"\n",(0,t.jsxs)(n.p,{children:["Sometimes you may wish to limit the attributes, such as passwords, that are included in your model's vector, map, or JSON representation. To do so, add a ",(0,t.jsx)(n.code,{children:"u_hidden"})," static data member to your model. Attributes that are listed in the ",(0,t.jsx)(n.code,{children:"u_hidden"})," data member set will not be included in the serialized representation of your model:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.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\n /*! The attributes that should be hidden during serialization. */\n inline static std::set u_hidden {"password"};\n};\n'})}),"\n",(0,t.jsx)(n.admonition,{type:"note",children:(0,t.jsxs)(n.p,{children:["To hide relationships, add the relationship's method name to your TinyORM model's ",(0,t.jsx)(n.code,{children:"u_hidden"})," static data member."]})}),"\n",(0,t.jsxs)(n.p,{children:["Alternatively, you may use the ",(0,t.jsx)(n.code,{children:"u_visible"}),' static data member to define an "allow list" of attributes that should be included in your model\'s vector, map, and JSON representation. All attributes that are not present in the ',(0,t.jsx)(n.code,{children:"u_visible"})," set will be hidden during serialization:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.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\n /*! The attributes that should be visible during serialization. */\n inline static std::set u_visible {\n "first_name", "last_name",\n };\n};\n'})}),"\n",(0,t.jsx)(n.h4,{id:"temporarily-modifying-attribute-visibility",children:"Temporarily Modifying Attribute Visibility"}),"\n",(0,t.jsxs)(n.p,{children:["If you would like to make some typically hidden attributes visible on a given model instance, you may use the ",(0,t.jsx)(n.code,{children:"makeVisible"})," method. The ",(0,t.jsx)(n.code,{children:"makeVisible"})," method returns a model reference:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'return user.makeVisible("attribute").toMap();\n\nreturn user.makeVisible({"id", "name"}).toMap();\n'})}),"\n",(0,t.jsxs)(n.p,{children:["Likewise, if you would like to hide some attributes that are typically visible, you may use the ",(0,t.jsx)(n.code,{children:"makeHidden"})," method."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'return user.makeHidden("attribute").toVector();\n\nreturn user.makeHidden({"id", "name"}).toVector();\n'})}),"\n",(0,t.jsxs)(n.p,{children:["If you wish to temporarily override all of the visible or hidden attributes, you may use the ",(0,t.jsx)(n.code,{children:"setVisible"})," and ",(0,t.jsx)(n.code,{children:"setHidden"})," methods respectively:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'return user.setVisible({"id", "name"}).toMap();\n\nreturn user.setHidden({"email", "password", "note"}).toJson();\n'})}),"\n",(0,t.jsx)(n.p,{children:"You can also clear all visible and hidden attributes or determine whether a visible / hidden attribute is defined:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'user.clearVisible();\n\nuser.clearHidden();\n\nreturn user.hasVisible("name");\n\nreturn user.hasHidden("password");\n'})}),"\n",(0,t.jsx)(n.h2,{id:"appending-values-to-json",children:"Appending Values To JSON"}),"\n",(0,t.jsxs)(n.p,{children:["Occasionally, when converting models to vector, map, or JSON, you may wish to add attributes that do not have a corresponding column in your database. To do so, first define an ",(0,t.jsx)(n.a,{href:"/tinyorm/casts#accessors",children:"accessor"})," for the value:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.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 /*! Accessor to determine if the user is an administrator. */\n Attribute isAdmin() const noexcept\n {\n return Attribute::make(/* get */ []() -> QVariant\n {\n return QStringLiteral("yes");\n });\n }\n};\n'})}),"\n",(0,t.jsxs)(n.p,{children:["If you would like the accessor to always be appended to your model's vector, map, and JSON representations, you may add the attribute name to the ",(0,t.jsx)(n.code,{children:"u_appends"}),' data member set of your model. Note that attribute names are typically referenced using their "snake_case" serialized representation, even though the accessor\'s method name is defined using "camelCase":']}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.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\n /*! Map of mutator names to methods. */\n inline static const QHash u_mutators {\n {"is_admin", &User::isAdmin},\n };\n\n /*! The attributes that should be appended during serialization. */\n std::set u_appends {"is_admin"};\n};\n'})}),"\n",(0,t.jsxs)(n.p,{children:["Once the attribute has been added to the ",(0,t.jsx)(n.code,{children:"u_appends"})," set, it will be included in both the model's vector, map, and JSON representations. Attributes in the ",(0,t.jsx)(n.code,{children:"u_appends"})," set will also respect the ",(0,t.jsx)(n.code,{children:"u_visible"})," and ",(0,t.jsx)(n.code,{children:"u_hidden"})," attribute settings configured on the model."]}),"\n",(0,t.jsxs)(n.p,{children:["Special note should be given to the ",(0,t.jsx)(n.code,{children:"u_mutators"})," static data member map, which maps accessors' attribute names to its methods. This data member is ",(0,t.jsx)(n.strong,{children:"required"})," because C++ does not currently support reflection."]}),"\n",(0,t.jsx)(n.h4,{id:"appending-at-run-time",children:"Appending At Run Time"}),"\n",(0,t.jsxs)(n.p,{children:["At runtime, you may instruct a model instance to append additional attributes using the ",(0,t.jsx)(n.code,{children:"append"})," method. Or, you may use the ",(0,t.jsx)(n.code,{children:"setAppends"})," method to override the entire set of appended attributes for a given model instance:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'return user.append("is_admin").toVector();\n\nreturn user.append({"is_admin", "is_banned"}).toMap();\n\nreturn user.setAppends({"is_admin"}).toJson();\n'})}),"\n",(0,t.jsx)(n.p,{children:"And you can also clear all appends or determine whether an append is defined:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'user.clearAppends();\n\nreturn user.hasAppend("is_admin");\n'})}),"\n",(0,t.jsx)(n.h2,{id:"date-serialization",children:"Date Serialization"}),"\n",(0,t.jsx)(n.h4,{id:"customizing-the-default-date-format",children:"Customizing The Default Date Format"}),"\n",(0,t.jsxs)(n.p,{children:["You may customize the default serialization format by overriding the ",(0,t.jsx)(n.code,{children:"serializeDate"})," and ",(0,t.jsx)(n.code,{children:"serializeDateTime"})," methods. These methods do not affect how your dates are formatted for storage in the database:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.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,t.jsx)(n.h4,{id:"customizing-the-date-format-per-attribute",children:"Customizing The Date Format Per Attribute"}),"\n",(0,t.jsxs)(n.p,{children:["You may customize the serialization format of individual TinyORM date attributes by specifying the date format in the model's ",(0,t.jsx)(n.a,{href:"/tinyorm/casts#attribute-casting",children:"cast declarations"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cpp",children:'/*! The attributes that should be cast. */\ninline static std::unordered_map u_casts {\n {"birthday", {CastType::CustomQDate, "yyyy-MM-dd"}},\n {"joined_at", {CastType::CustomQDateTime, "yyyy-MM-dd HH:00"}},\n};\n'})})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(c,{...e})}):c(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>r,x:()=>a});var t=i(6540);const s={},o=t.createContext(s);function r(e){const n=t.useContext(o);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(o.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/1222ea4e.93c74363.js b/assets/js/1222ea4e.93c74363.js deleted file mode 100644 index d26f87380..000000000 --- a/assets/js/1222ea4e.93c74363.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[535],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=i.createContext({}),d=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=d(e.components);return i.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},c=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=d(n),c=a,h=u["".concat(l,".").concat(c)]||u[c]||m[c]||o;return n?i.createElement(h,r(r({ref:t},p),{},{components:n})):i.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=c;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var d=2;d{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>d});var i=n(7462),a=(n(7294),n(3905));const o={sidebar_position:4,sidebar_label:"Serialization",description:"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.",keywords:["c++ orm","orm","serialization","json","toJson","serializing models","serializing relations","serializing collections","converting","toVector","toMap"]},r="TinyORM: Serialization",s={unversionedId:"tinyorm/serialization",id:"tinyorm/serialization",title:"TinyORM: Serialization",description:"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.",source:"@site/docs/tinyorm/serialization.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/serialization",permalink:"/tinyorm/serialization",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/tinyorm/serialization.mdx",tags:[],version:"current",sidebarPosition:4,frontMatter:{sidebar_position:4,sidebar_label:"Serialization",description:"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.",keywords:["c++ orm","orm","serialization","json","toJson","serializing models","serializing relations","serializing collections","converting","toVector","toMap"]},sidebar:"tinyormSidebar",previous:{title:"Casts",permalink:"/tinyorm/casts"},next:{title:"Getting Started",permalink:"/tinydrivers/getting-started"}},l={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Serializing Models & Collections",id:"serializing-models-and-collections",level:2},{value:"Serializing To Vectors & Maps",id:"serializing-to-vectors-and-maps",level:3},{value:"Serializing To JSON",id:"serializing-to-json",level:3},{value:"Relationships",id:"relationships",level:4},{value:"Hiding Attributes From JSON",id:"hiding-attributes-from-json",level:2},{value:"Temporarily Modifying Attribute Visibility",id:"temporarily-modifying-attribute-visibility",level:4},{value:"Appending Values To JSON",id:"appending-values-to-json",level:2},{value:"Appending At Run Time",id:"appending-at-run-time",level:4},{value:"Date Serialization",id:"date-serialization",level:2},{value:"Customizing The Default Date Format",id:"customizing-the-default-date-format",level:4},{value:"Customizing The Date Format Per Attribute",id:"customizing-the-date-format-per-attribute",level:4}],p={toc:d},u="wrapper";function m(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,i.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"tinyorm-serialization"},"TinyORM: Serialization"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#serializing-models-and-collections"},"Serializing Models & Collections"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#serializing-to-vectors-and-maps"},"Serializing To Vectors & Maps")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#serializing-to-json"},"Serializing To JSON")))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#hiding-attributes-from-json"},"Hiding Attributes From JSON")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#appending-values-to-json"},"Appending Values To JSON")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#date-serialization"},"Date Serialization"))),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"When building APIs using TinyORM, you will often need to convert your models and relationships to vectors, maps, or JSON. TinyORM includes convenient methods for making these conversions, as well as controlling which attributes are included in the serialized representation of your models."),(0,a.kt)("h2",{id:"serializing-models-and-collections"},"Serializing Models & Collections"),(0,a.kt)("h3",{id:"serializing-to-vectors-and-maps"},"Serializing To Vectors & Maps"),(0,a.kt)("p",null,"To convert a model and its loaded ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/relationships"},"relationships")," to a vector, you should use the ",(0,a.kt)("inlineCode",{parentName:"p"},"toVector")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"toMap")," methods. This methods are recursive, so all attributes and all relations (including the relations of relations) will be converted to vectors:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using Models::User;\n\nauto user = User::with("roles")->first();\n\nreturn user->toVector();\n\nreturn user->toMap();\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"attributesToVector")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"attributesToMap")," methods may be used to convert a model's attributes to a vector or map but not its relationships:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"auto user = User::first();\n\nreturn user->attributesToVector();\n\nreturn user->attributesToMap();\n")),(0,a.kt)("p",null,"You may also convert entire ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/collections"},"collections")," of models to vectors or maps by calling the ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/collections#method-tovector"},(0,a.kt)("inlineCode",{parentName:"a"},"toVector"))," or ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/collections#method-tomap"},(0,a.kt)("inlineCode",{parentName:"a"},"toMap"))," methods on the collection instance:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection users = User::with("roles")->all();\n\nreturn users.toVector();\n\nreturn users.toMap();\n')),(0,a.kt)("h3",{id:"serializing-to-json"},"Serializing To JSON"),(0,a.kt)("p",null,"To convert a model to JSON, you should use the ",(0,a.kt)("inlineCode",{parentName:"p"},"toJson")," method. Like ",(0,a.kt)("inlineCode",{parentName:"p"},"toVector")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"toMap"),", the ",(0,a.kt)("inlineCode",{parentName:"p"},"toJson")," method is recursive, so all attributes and relations will be converted to JSON. You may also specify any JSON encoding options that are supported by ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsondocument.html#toJson"},"QJsonDocument::toJson"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using Models::User;\n\nauto user = User::with("roles")->find(1);\n\nreturn user->toJson();\n\nreturn user->toJson(QJsonDocument::Indented);\n')),(0,a.kt)("p",null,"You may also convert entire ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/collections"},"collections")," of models to JSON by calling the ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/collections#method-tojson"},(0,a.kt)("inlineCode",{parentName:"a"},"toJson"))," method on the collection instance:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection users = User::with("roles")->findMany({1, 2});\n\nreturn users.toJson();\n')),(0,a.kt)("p",null,"You can also convert models to the ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsonobject.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QJsonObject"))," and ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsondocument.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QJsonDocument"))," using the ",(0,a.kt)("inlineCode",{parentName:"p"},"toJsonArray")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"toJsonDocument")," methods and collection of models to ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsonarray.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QJsonArray"))," and ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsondocument.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QJsonDocument"))," using the ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/collections#method-tojsonarray"},(0,a.kt)("inlineCode",{parentName:"a"},"toJsonArray"))," and ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/collections#method-tojsondocument"},(0,a.kt)("inlineCode",{parentName:"a"},"toJsonDocument"))," methods."),(0,a.kt)("h4",{id:"relationships"},"Relationships"),(0,a.kt)("p",null,'When a TinyORM model is converted to JSON, its loaded relationships will automatically be included as attributes on the JSON object. Also, though TinyORM relationship methods are defined using "camelCase" method names, a relationship\'s JSON attributes will be "snake_case".'),(0,a.kt)("p",null,"This behavior is affected and can be overridden by the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_snakeAttributes")," static data member:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"#include \n\nusing Orm::Tiny::Model;\n\nclass Album final : public Model\n{\n friend Model;\n using Model::Model;\n\n /*! Indicates whether attributes are snake_cased during serialization. */\n inline static const bool u_snakeAttributes = false;\n};\n")),(0,a.kt)("h2",{id:"hiding-attributes-from-json"},"Hiding Attributes From JSON"),(0,a.kt)("p",null,"Sometimes you may wish to limit the attributes, such as passwords, that are included in your model's vector, map, or JSON representation. To do so, add a ",(0,a.kt)("inlineCode",{parentName:"p"},"u_hidden")," static data member to your model. Attributes that are listed in the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_hidden")," data member set will not be included in the serialized representation of your model:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'#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 hidden during serialization. */\n inline static std::set u_hidden {"password"};\n};\n')),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"To hide relationships, add the relationship's method name to your TinyORM model's ",(0,a.kt)("inlineCode",{parentName:"p"},"u_hidden")," static data member.")),(0,a.kt)("p",null,"Alternatively, you may use the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_visible"),' static data member to define an "allow list" of attributes that should be included in your model\'s vector, map, and JSON representation. All attributes that are not present in the ',(0,a.kt)("inlineCode",{parentName:"p"},"u_visible")," set will be hidden during serialization:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'#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 visible during serialization. */\n inline static std::set u_visible {\n "first_name", "last_name",\n };\n};\n')),(0,a.kt)("h4",{id:"temporarily-modifying-attribute-visibility"},"Temporarily Modifying Attribute Visibility"),(0,a.kt)("p",null,"If you would like to make some typically hidden attributes visible on a given model instance, you may use the ",(0,a.kt)("inlineCode",{parentName:"p"},"makeVisible")," method. The ",(0,a.kt)("inlineCode",{parentName:"p"},"makeVisible")," method returns a model reference:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'return user.makeVisible("attribute").toMap();\n\nreturn user.makeVisible({"id", "name"}).toMap();\n')),(0,a.kt)("p",null,"Likewise, if you would like to hide some attributes that are typically visible, you may use the ",(0,a.kt)("inlineCode",{parentName:"p"},"makeHidden")," method."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'return user.makeHidden("attribute").toVector();\n\nreturn user.makeHidden({"id", "name"}).toVector();\n')),(0,a.kt)("p",null,"If you wish to temporarily override all of the visible or hidden attributes, you may use the ",(0,a.kt)("inlineCode",{parentName:"p"},"setVisible")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"setHidden")," methods respectively:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'return user.setVisible({"id", "name"}).toMap();\n\nreturn user.setHidden({"email", "password", "note"}).toJson();\n')),(0,a.kt)("p",null,"You can also clear all visible and hidden attributes or determine whether a visible / hidden attribute is defined:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'user.clearVisible();\n\nuser.clearHidden();\n\nreturn user.hasVisible("name");\n\nreturn user.hasHidden("password");\n')),(0,a.kt)("h2",{id:"appending-values-to-json"},"Appending Values To JSON"),(0,a.kt)("p",null,"Occasionally, when converting models to vector, map, or JSON, you may wish to add attributes that do not have a corresponding column in your database. To do so, first define an ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/casts#accessors"},"accessor")," for the value:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'#include \n\nusing Orm::Tiny::Model;\n\nclass User final : public Model\n{\n friend Model;\n using Model::Model;\n\nprotected:\n /*! Accessor to determine if the user is an administrator. */\n Attribute isAdmin() const noexcept\n {\n return Attribute::make(/* get */ []() -> QVariant\n {\n return QStringLiteral("yes");\n });\n }\n};\n')),(0,a.kt)("p",null,"If you would like the accessor to always be appended to your model's vector, map, and JSON representations, you may add the attribute name to the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_appends"),' data member set of your model. Note that attribute names are typically referenced using their "snake_case" serialized representation, even though the accessor\'s method name is defined using "camelCase":'),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'#include \n\nusing Orm::Tiny::Model;\n\nclass User final : public Model\n{\n friend Model;\n using Model::Model;\n\n /*! Map of mutator names to methods. */\n inline static const QHash u_mutators {\n {"is_admin", &User::isAdmin},\n };\n\n /*! The attributes that should be appended during serialization. */\n std::set u_appends {"is_admin"};\n};\n')),(0,a.kt)("p",null,"Once the attribute has been added to the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_appends")," set, it will be included in both the model's vector, map, and JSON representations. Attributes in the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_appends")," set will also respect the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_visible")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"u_hidden")," attribute settings configured on the model."),(0,a.kt)("p",null,"Special note should be given to the ",(0,a.kt)("inlineCode",{parentName:"p"},"u_mutators")," static data member map, which maps accessors' attribute names to its methods. This data member is ",(0,a.kt)("strong",{parentName:"p"},"required")," because C++ does not currently support reflection."),(0,a.kt)("h4",{id:"appending-at-run-time"},"Appending At Run Time"),(0,a.kt)("p",null,"At runtime, you may instruct a model instance to append additional attributes using the ",(0,a.kt)("inlineCode",{parentName:"p"},"append")," method. Or, you may use the ",(0,a.kt)("inlineCode",{parentName:"p"},"setAppends")," method to override the entire set of appended attributes for a given model instance:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'return user.append("is_admin").toVector();\n\nreturn user.append({"is_admin", "is_banned"}).toMap();\n\nreturn user.setAppends({"is_admin"}).toJson();\n')),(0,a.kt)("p",null,"And you can also clear all appends or determine whether an append is defined:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'user.clearAppends();\n\nreturn user.hasAppend("is_admin");\n')),(0,a.kt)("h2",{id:"date-serialization"},"Date Serialization"),(0,a.kt)("h4",{id:"customizing-the-default-date-format"},"Customizing The Default Date Format"),(0,a.kt)("p",null,"You may customize the default serialization format by overriding the ",(0,a.kt)("inlineCode",{parentName:"p"},"serializeDate")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"serializeDateTime")," methods. These methods do not affect how your dates are formatted for storage in the database:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'/*! 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')),(0,a.kt)("h4",{id:"customizing-the-date-format-per-attribute"},"Customizing The Date Format Per Attribute"),(0,a.kt)("p",null,"You may customize the serialization format of individual TinyORM date attributes by specifying the date format in the model's ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/casts#attribute-casting"},"cast declarations"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'/*! The attributes that should be cast. */\ninline static std::unordered_map u_casts {\n {"birthday", {CastType::CustomQDate, "yyyy-MM-dd"}},\n {"joined_at", {CastType::CustomQDateTime, "yyyy-MM-dd HH:00"}},\n};\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/176.1f8f2d9b.js b/assets/js/176.1f8f2d9b.js deleted file mode 100644 index 76a18dd35..000000000 --- a/assets/js/176.1f8f2d9b.js +++ /dev/null @@ -1 +0,0 @@ -(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[176],{3905:(e,t,n)=>{"use strict";n.d(t,{Zo:()=>u,kt:()=>f});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=o.createContext({}),i=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=i(e.components);return o.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=i(n),m=r,f=p["".concat(l,".").concat(m)]||p[m]||d[m]||c;return n?o.createElement(f,a(a({ref:t},u),{},{components:n})):o.createElement(f,a({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,a=new Array(c);a[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,a[1]=s;for(var i=2;i{"use strict";n.d(t,{Z:()=>q});var o=n(7462),r=n(7294),c=n(2389),a=n(6010),s=n(2949),l=n(6668);function i(){const{prism:e}=(0,l.L)(),{colorMode:t}=(0,s.I)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var u=n(5281),p=n(7594),d=n.n(p);const m=/title=(?["'])(?.*?)\1/,f=/\{(?<range>[\d,-]+)\}/,y={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}};function g(e,t){const n=e.map((e=>{const{start:n,end:o}=y[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function b(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:r,metastring:c}=t;if(c&&f.test(c)){const e=c.match(f).groups.range;if(0===r.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${c}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=r[0].className,o=d()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const a=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return g(["js","jsBlock"],t);case"jsx":case"tsx":return g(["js","jsBlock","jsx"],t);case"html":return g(["js","jsBlock","html"],t);case"python":case"py":case"bash":return g(["bash"],t);case"markdown":case"md":return g(["html","jsx","bash"],t);default:return g(Object.keys(y),t)}}(o,r),s=n.split("\n"),l=Object.fromEntries(r.map((e=>[e.className,{start:0,range:""}]))),i=Object.fromEntries(r.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(r.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),p=Object.fromEntries(r.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let d=0;d<s.length;){const e=s[d].match(a);if(!e){d+=1;continue}const t=e.slice(1).find((e=>void 0!==e));i[t]?l[i[t]].range+=`${d},`:u[t]?l[u[t]].start=d:p[t]&&(l[p[t]].range+=`${l[p[t]].start}-${d-1},`),s.splice(d,1)}n=s.join("\n");const m={};return Object.entries(l).forEach((e=>{let[t,{range:n}]=e;d()(n).forEach((e=>{m[e]??=[],m[e].push(t)}))})),{lineClassNames:m,code:n}}const h={codeBlockContainer:"codeBlockContainer_Ckt0"};function v(e){let{as:t,...n}=e;const c=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,r]=e;const c=t[o];c&&"string"==typeof r&&(n[c]=r)})),n}(i());return r.createElement(t,(0,o.Z)({},n,{style:c,className:(0,a.Z)(n.className,h.codeBlockContainer,u.k.common.codeBlock)}))}const k={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function E(e){let{children:t,className:n}=e;return r.createElement(v,{as:"pre",tabIndex:0,className:(0,a.Z)(k.codeBlockStandalone,"thin-scrollbar",n)},r.createElement("code",{className:k.codeBlockLines},t))}var N=n(902);const B={attributes:!0,characterData:!0,childList:!0,subtree:!0};function w(e,t){const[n,o]=(0,r.useState)(),c=(0,r.useCallback)((()=>{o(e.current?.closest("[role=tabpanel][hidden]"))}),[e,o]);(0,r.useEffect)((()=>{c()}),[c]),function(e,t,n){void 0===n&&(n=B);const o=(0,N.zX)(t),c=(0,N.Ql)(n);(0,r.useEffect)((()=>{const t=new MutationObserver(o);return e&&t.observe(e,c),()=>t.disconnect()}),[e,o,c])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),c())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}const C={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]};var j={Prism:n(7410).Z,theme:C};function O(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function L(){return L=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])}return e},L.apply(this,arguments)}var T=/\r\n|\r|\n/,x=function(e){0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},P=function(e,t){var n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)};function S(e,t){var n={};for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&-1===t.indexOf(o)&&(n[o]=e[o]);return n}var _=function(e){function t(){for(var t=this,n=[],o=arguments.length;o--;)n[o]=arguments[o];e.apply(this,n),O(this,"getThemeDict",(function(e){if(void 0!==t.themeDict&&e.theme===t.prevTheme&&e.language===t.prevLanguage)return t.themeDict;t.prevTheme=e.theme,t.prevLanguage=e.language;var n=e.theme?function(e,t){var n=e.plain,o=Object.create(null),r=e.styles.reduce((function(e,n){var o=n.languages,r=n.style;return o&&!o.includes(t)||n.types.forEach((function(t){var n=L({},e[t],r);e[t]=n})),e}),o);return r.root=n,r.plain=L({},n,{backgroundColor:null}),r}(e.theme,e.language):void 0;return t.themeDict=n})),O(this,"getLineProps",(function(e){var n=e.key,o=e.className,r=e.style,c=L({},S(e,["key","className","style","line"]),{className:"token-line",style:void 0,key:void 0}),a=t.getThemeDict(t.props);return void 0!==a&&(c.style=a.plain),void 0!==r&&(c.style=void 0!==c.style?L({},c.style,r):r),void 0!==n&&(c.key=n),o&&(c.className+=" "+o),c})),O(this,"getStyleForToken",(function(e){var n=e.types,o=e.empty,r=n.length,c=t.getThemeDict(t.props);if(void 0!==c){if(1===r&&"plain"===n[0])return o?{display:"inline-block"}:void 0;if(1===r&&!o)return c[n[0]];var a=o?{display:"inline-block"}:{},s=n.map((function(e){return c[e]}));return Object.assign.apply(Object,[a].concat(s))}})),O(this,"getTokenProps",(function(e){var n=e.key,o=e.className,r=e.style,c=e.token,a=L({},S(e,["key","className","style","token"]),{className:"token "+c.types.join(" "),children:c.content,style:t.getStyleForToken(c),key:void 0});return void 0!==r&&(a.style=void 0!==a.style?L({},a.style,r):r),void 0!==n&&(a.key=n),o&&(a.className+=" "+o),a})),O(this,"tokenize",(function(e,t,n,o){var r={code:t,grammar:n,language:o,tokens:[]};e.hooks.run("before-tokenize",r);var c=r.tokens=e.tokenize(r.code,r.grammar,r.language);return e.hooks.run("after-tokenize",r),c}))}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.render=function(){var e=this.props,t=e.Prism,n=e.language,o=e.code,r=e.children,c=this.getThemeDict(this.props),a=t.languages[n];return r({tokens:function(e){for(var t=[[]],n=[e],o=[0],r=[e.length],c=0,a=0,s=[],l=[s];a>-1;){for(;(c=o[a]++)<r[a];){var i=void 0,u=t[a],p=n[a][c];if("string"==typeof p?(u=a>0?u:["plain"],i=p):(u=P(u,p.type),p.alias&&(u=P(u,p.alias)),i=p.content),"string"==typeof i){var d=i.split(T),m=d.length;s.push({types:u,content:d[0]});for(var f=1;f<m;f++)x(s),l.push(s=[]),s.push({types:u,content:d[f]})}else a++,t.push(u),n.push(i),o.push(0),r.push(i.length)}a--,t.pop(),n.pop(),o.pop(),r.pop()}return x(s),l}(void 0!==a?this.tokenize(t,o,a,n):[o]),className:"prism-code language-"+n,style:void 0!==c?c.root:{},getLineProps:this.getLineProps,getTokenProps:this.getTokenProps})},t}(r.Component);const I=_,Z={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function A(e){let{line:t,classNames:n,showLineNumbers:c,getLineProps:s,getTokenProps:l}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const i=s({line:t,className:(0,a.Z)(n,c&&Z.codeLine)}),u=t.map(((e,t)=>r.createElement("span",(0,o.Z)({key:t},l({token:e,key:t})))));return r.createElement("span",i,c?r.createElement(r.Fragment,null,r.createElement("span",{className:Z.codeLineNumber}),r.createElement("span",{className:Z.codeLineContent},u)):u,r.createElement("br",null))}var D=n(5999);function W(e){return r.createElement("svg",(0,o.Z)({viewBox:"0 0 24 24"},e),r.createElement("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"}))}function $(e){return r.createElement("svg",(0,o.Z)({viewBox:"0 0 24 24"},e),r.createElement("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"}))}const z={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function H(e){let{code:t,className:n}=e;const[o,c]=(0,r.useState)(!1),s=(0,r.useRef)(void 0),l=(0,r.useCallback)((()=>{!function(e,{target:t=document.body}={}){if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const n=document.createElement("textarea"),o=document.activeElement;n.value=e,n.setAttribute("readonly",""),n.style.contain="strict",n.style.position="absolute",n.style.left="-9999px",n.style.fontSize="12pt";const r=document.getSelection(),c=r.rangeCount>0&&r.getRangeAt(0);t.append(n),n.select(),n.selectionStart=0,n.selectionEnd=e.length;let a=!1;try{a=document.execCommand("copy")}catch{}n.remove(),c&&(r.removeAllRanges(),r.addRange(c)),o&&o.focus()}(t),c(!0),s.current=window.setTimeout((()=>{c(!1)}),1e3)}),[t]);return(0,r.useEffect)((()=>()=>window.clearTimeout(s.current)),[]),r.createElement("button",{type:"button","aria-label":o?(0,D.I)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,D.I)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,D.I)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,a.Z)("clean-btn",n,z.copyButton,o&&z.copyButtonCopied),onClick:l},r.createElement("span",{className:z.copyButtonIcons,"aria-hidden":"true"},r.createElement(W,{className:z.copyButtonIcon}),r.createElement($,{className:z.copyButtonSuccessIcon})))}function M(e){return r.createElement("svg",(0,o.Z)({viewBox:"0 0 24 24"},e),r.createElement("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"}))}const V={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function R(e){let{className:t,onClick:n,isEnabled:o}=e;const c=(0,D.I)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return r.createElement("button",{type:"button",onClick:n,className:(0,a.Z)("clean-btn",t,o&&V.wordWrapButtonEnabled),"aria-label":c,title:c},r.createElement(M,{className:V.wordWrapButtonIcon,"aria-hidden":"true"}))}function F(e){let{children:t,className:n="",metastring:c,title:s,showLineNumbers:u,language:p}=e;const{prism:{defaultLanguage:d,magicComments:f}}=(0,l.L)(),y=p??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d,g=i(),h=function(){const[e,t]=(0,r.useState)(!1),[n,o]=(0,r.useState)(!1),c=(0,r.useRef)(null),a=(0,r.useCallback)((()=>{const n=c.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[c,e]),s=(0,r.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=c.current,n=e>t||c.current.querySelector("code").hasAttribute("style");o(n)}),[c]);return w(c,s),(0,r.useEffect)((()=>{s()}),[e,s]),(0,r.useEffect)((()=>(window.addEventListener("resize",s,{passive:!0}),()=>{window.removeEventListener("resize",s)})),[s]),{codeBlockRef:c,isEnabled:e,isCodeScrollable:n,toggle:a}}(),E=function(e){return e?.match(m)?.groups.title??""}(c)||s,{lineClassNames:N,code:B}=b(t,{metastring:c,language:y,magicComments:f}),C=u??function(e){return Boolean(e?.includes("showLineNumbers"))}(c);return r.createElement(v,{as:"div",className:(0,a.Z)(n,y&&!n.includes(`language-${y}`)&&`language-${y}`)},E&&r.createElement("div",{className:k.codeBlockTitle},E),r.createElement("div",{className:k.codeBlockContent},r.createElement(I,(0,o.Z)({},j,{theme:g,code:B,language:y??"text"}),(e=>{let{className:t,tokens:n,getLineProps:o,getTokenProps:c}=e;return r.createElement("pre",{tabIndex:0,ref:h.codeBlockRef,className:(0,a.Z)(t,k.codeBlock,"thin-scrollbar")},r.createElement("code",{className:(0,a.Z)(k.codeBlockLines,C&&k.codeBlockLinesWithNumbering)},n.map(((e,t)=>r.createElement(A,{key:t,line:e,getLineProps:o,getTokenProps:c,classNames:N[t],showLineNumbers:C})))))})),r.createElement("div",{className:k.buttonGroup},(h.isEnabled||h.isCodeScrollable)&&r.createElement(R,{className:k.codeButton,onClick:()=>h.toggle(),isEnabled:h.isEnabled}),r.createElement(H,{className:k.codeButton,code:B}))))}function q(e){let{children:t,...n}=e;const a=(0,c.Z)(),s=function(e){return r.Children.toArray(e).some((e=>(0,r.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),l="string"==typeof s?F:E;return r.createElement(l,(0,o.Z)({key:String(a)},n),s)}},7594:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,r,c]=t;if(o&&c){o=parseInt(o),c=parseInt(c);const e=o<c?1:-1;"-"!==r&&".."!==r&&"\u2025"!==r||(c+=e);for(let t=o;t!==c;t+=e)n.push(t)}}return n}t.default=n,e.exports=n}}]); \ No newline at end of file diff --git a/assets/js/17896441.35ffcf9d.js b/assets/js/17896441.35ffcf9d.js deleted file mode 100644 index ea0b3f5dd..000000000 --- a/assets/js/17896441.35ffcf9d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[918],{5836:(e,t,n)=>{n.r(t),n.d(t,{default:()=>Je});var a=n(7294),l=n(833),o=n(902);const r=a.createContext(null);function i(e){let{children:t,content:n}=e;const l=function(e){return(0,a.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(n);return a.createElement(r.Provider,{value:l},t)}function c(){const e=(0,a.useContext)(r);if(null===e)throw new o.i6("DocProvider");return e}function s(){const{metadata:e,frontMatter:t,assets:n}=c();return a.createElement(l.d,{title:e.title,description:e.description,keywords:t.keywords,image:n.image??t.image})}var d=n(6010),m=n(7524),u=n(7462),p=n(5999),h=n(9960);function f(e){const{permalink:t,title:n,subLabel:l,isNext:o}=e;return a.createElement(h.Z,{className:(0,d.Z)("pagination-nav__link",o?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},l&&a.createElement("div",{className:"pagination-nav__sublabel"},l),a.createElement("div",{className:"pagination-nav__label"},n))}function v(e){const{previous:t,next:n}=e;return a.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,p.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"})},t&&a.createElement(f,(0,u.Z)({},t,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),n&&a.createElement(f,(0,u.Z)({},n,{subLabel:a.createElement(p.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}function b(){const{metadata:e}=c();return a.createElement(v,{previous:e.previous,next:e.next})}var E=n(2263),g=n(143),N=n(5281),C=n(373),L=n(4477);const _={unreleased:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(p.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:n}=e;return a.createElement(p.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:a.createElement("b",null,n.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function k(e){const t=_[e.versionMetadata.banner];return a.createElement(t,e)}function Z(e){let{versionLabel:t,to:n,onClick:l}=e;return a.createElement(p.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:a.createElement("b",null,a.createElement(h.Z,{to:n,onClick:l},a.createElement(p.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function T(e){let{className:t,versionMetadata:n}=e;const{siteConfig:{title:l}}=(0,E.Z)(),{pluginId:o}=(0,g.gA)({failfast:!0}),{savePreferredVersionName:r}=(0,C.J)(o),{latestDocSuggestion:i,latestVersionSuggestion:c}=(0,g.Jo)(o),s=i??(m=c).docs.find((e=>e.id===m.mainDocId));var m;return a.createElement("div",{className:(0,d.Z)(t,N.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},a.createElement("div",null,a.createElement(k,{siteTitle:l,versionMetadata:n})),a.createElement("div",{className:"margin-top--md"},a.createElement(Z,{versionLabel:c.label,to:s.path,onClick:()=>r(c.name)})))}function y(e){let{className:t}=e;const n=(0,L.E)();return n.banner?a.createElement(T,{className:t,versionMetadata:n}):null}function x(e){let{className:t}=e;const n=(0,L.E)();return n.badge?a.createElement("span",{className:(0,d.Z)(t,N.k.docs.docVersionBadge,"badge badge--secondary")},a.createElement(p.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:n.label}},"Version: {versionLabel}")):null}function H(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n}=e;return a.createElement(p.Z,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:a.createElement("b",null,a.createElement("time",{dateTime:new Date(1e3*t).toISOString()},n))}}," on {date}")}function w(e){let{lastUpdatedBy:t}=e;return a.createElement(p.Z,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:a.createElement("b",null,t)}}," by {user}")}function A(e){let{lastUpdatedAt:t,formattedLastUpdatedAt:n,lastUpdatedBy:l}=e;return a.createElement("span",{className:N.k.common.lastUpdated},a.createElement(p.Z,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:t&&n?a.createElement(H,{lastUpdatedAt:t,formattedLastUpdatedAt:n}):"",byUser:l?a.createElement(w,{lastUpdatedBy:l}):""}},"Last updated{atDate}{byUser}"),!1)}const M={iconEdit:"iconEdit_Z9Sw"};function U(e){let{className:t,...n}=e;return a.createElement("svg",(0,u.Z)({fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,d.Z)(M.iconEdit,t),"aria-hidden":"true"},n),a.createElement("g",null,a.createElement("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})))}function B(e){let{editUrl:t}=e;return a.createElement("a",{href:t,target:"_blank",rel:"noreferrer noopener",className:N.k.common.editThisPage},a.createElement(U,null),a.createElement(p.Z,{id:"theme.common.editThisPage",description:"The link label to edit the current page"},"Edit this page"))}const I={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function S(e){let{permalink:t,label:n,count:l}=e;return a.createElement(h.Z,{href:t,className:(0,d.Z)(I.tag,l?I.tagWithCount:I.tagRegular)},n,l&&a.createElement("span",null,l))}const z={tags:"tags_jXut",tag:"tag_QGVx"};function V(e){let{tags:t}=e;return a.createElement(a.Fragment,null,a.createElement("b",null,a.createElement(p.Z,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list"},"Tags:")),a.createElement("ul",{className:(0,d.Z)(z.tags,"padding--none","margin-left--sm")},t.map((e=>{let{label:t,permalink:n}=e;return a.createElement("li",{key:n,className:z.tag},a.createElement(S,{label:t,permalink:n}))}))))}const O={lastUpdated:"lastUpdated_vwxv"};function R(e){return a.createElement("div",{className:(0,d.Z)(N.k.docs.docFooterTagsRow,"row margin-bottom--sm")},a.createElement("div",{className:"col"},a.createElement(V,e)))}function D(e){let{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:l,formattedLastUpdatedAt:o}=e;return a.createElement("div",{className:(0,d.Z)(N.k.docs.docFooterEditMetaRow,"row")},a.createElement("div",{className:"col"},t&&a.createElement(B,{editUrl:t})),a.createElement("div",{className:(0,d.Z)("col",O.lastUpdated)},(n||l)&&a.createElement(A,{lastUpdatedAt:n,formattedLastUpdatedAt:o,lastUpdatedBy:l})))}function P(){const{metadata:e}=c(),{editUrl:t,lastUpdatedAt:n,formattedLastUpdatedAt:l,lastUpdatedBy:o,tags:r}=e,i=r.length>0,s=!!(t||n||o);return i||s?a.createElement("footer",{className:(0,d.Z)(N.k.docs.docFooter,"docusaurus-mt-lg")},i&&a.createElement(R,{tags:r}),s&&a.createElement(D,{editUrl:t,lastUpdatedAt:n,lastUpdatedBy:o,formattedLastUpdatedAt:l})):null}var F=n(6043),W=n(6668);function q(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const a=n.slice(2,e.level);e.parentIndex=Math.max(...a),n[e.level]=t}));const a=[];return t.forEach((e=>{const{parentIndex:n,...l}=e;n>=0?t[n].children.push(l):a.push(l)})),a}function j(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return t.flatMap((e=>{const t=j({toc:e.children,minHeadingLevel:n,maxHeadingLevel:a});return function(e){return e.level>=n&&e.level<=a}(e)?[{...e,children:t}]:t}))}function $(e){const t=e.getBoundingClientRect();return t.top===t.bottom?$(e.parentNode):t}function G(e,t){let{anchorTopOffset:n}=t;const a=e.find((e=>$(e).top>=n));if(a){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}($(a))?a:e[e.indexOf(a)-1]??null}return e[e.length-1]??null}function Y(){const e=(0,a.useRef)(0),{navbar:{hideOnScroll:t}}=(0,W.L)();return(0,a.useEffect)((()=>{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function J(e){const t=(0,a.useRef)(void 0),n=Y();(0,a.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:a,linkActiveClassName:l,minHeadingLevel:o,maxHeadingLevel:r}=e;function i(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(a),i=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const a=[];for(let l=t;l<=n;l+=1)a.push(`h${l}.anchor`);return Array.from(document.querySelectorAll(a.join()))}({minHeadingLevel:o,maxHeadingLevel:r}),c=G(i,{anchorTopOffset:n.current}),s=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(l),e.classList.add(l),t.current=e):e.classList.remove(l)}(e,e===s)}))}return document.addEventListener("scroll",i),document.addEventListener("resize",i),i(),()=>{document.removeEventListener("scroll",i),document.removeEventListener("resize",i)}}),[e,n])}function Q(e){let{toc:t,className:n,linkClassName:l,isChild:o}=e;return t.length?a.createElement("ul",{className:o?void 0:n},t.map((e=>a.createElement("li",{key:e.id},a.createElement("a",{href:`#${e.id}`,className:l??void 0,dangerouslySetInnerHTML:{__html:e.value}}),a.createElement(Q,{isChild:!0,toc:e.children,className:n,linkClassName:l}))))):null}const X=a.memo(Q);function K(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:l="table-of-contents__link",linkActiveClassName:o,minHeadingLevel:r,maxHeadingLevel:i,...c}=e;const s=(0,W.L)(),d=r??s.tableOfContents.minHeadingLevel,m=i??s.tableOfContents.maxHeadingLevel,p=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:l}=e;return(0,a.useMemo)((()=>j({toc:q(t),minHeadingLevel:n,maxHeadingLevel:l})),[t,n,l])}({toc:t,minHeadingLevel:d,maxHeadingLevel:m});return J((0,a.useMemo)((()=>{if(l&&o)return{linkClassName:l,linkActiveClassName:o,minHeadingLevel:d,maxHeadingLevel:m}}),[l,o,d,m])),a.createElement(X,(0,u.Z)({toc:p,className:n,linkClassName:l},c))}const ee={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function te(e){let{collapsed:t,...n}=e;return a.createElement("button",(0,u.Z)({type:"button"},n,{className:(0,d.Z)("clean-btn",ee.tocCollapsibleButton,!t&&ee.tocCollapsibleButtonExpanded,n.className)}),a.createElement(p.Z,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component"},"On this page"))}const ne={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function ae(e){let{toc:t,className:n,minHeadingLevel:l,maxHeadingLevel:o}=e;const{collapsed:r,toggleCollapsed:i}=(0,F.u)({initialState:!0});return a.createElement("div",{className:(0,d.Z)(ne.tocCollapsible,!r&&ne.tocCollapsibleExpanded,n)},a.createElement(te,{collapsed:r,onClick:i}),a.createElement(F.z,{lazy:!0,className:ne.tocCollapsibleContent,collapsed:r},a.createElement(K,{toc:t,minHeadingLevel:l,maxHeadingLevel:o})))}const le={tocMobile:"tocMobile_ITEo"};function oe(){const{toc:e,frontMatter:t}=c();return a.createElement(ae,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:(0,d.Z)(N.k.docs.docTocMobile,le.tocMobile)})}const re={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},ie="table-of-contents__link toc-highlight",ce="table-of-contents__link--active";function se(e){let{className:t,...n}=e;return a.createElement("div",{className:(0,d.Z)(re.tableOfContents,"thin-scrollbar",t)},a.createElement(K,(0,u.Z)({},n,{linkClassName:ie,linkActiveClassName:ce})))}function de(){const{toc:e,frontMatter:t}=c();return a.createElement(se,{toc:e,minHeadingLevel:t.toc_min_heading_level,maxHeadingLevel:t.toc_max_heading_level,className:N.k.docs.docTocDesktop})}const me={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function ue(e){let{as:t,id:n,...l}=e;const{navbar:{hideOnScroll:o}}=(0,W.L)();if("h1"===t||!n)return a.createElement(t,(0,u.Z)({},l,{id:void 0}));const r=(0,p.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof l.children?l.children:n});return a.createElement(t,(0,u.Z)({},l,{className:(0,d.Z)("anchor",o?me.anchorWithHideOnScrollNavbar:me.anchorWithStickyNavbar,l.className),id:n}),l.children,a.createElement(h.Z,{className:"hash-link",to:`#${n}`,"aria-label":r,title:r},"\u200b"))}var pe=n(3905),he=n(5742);var fe=n(7693);var ve=n(2389);const be={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function Ee(e){return!!e&&("SUMMARY"===e.tagName||Ee(e.parentElement))}function ge(e,t){return!!e&&(e===t||ge(e.parentElement,t))}function Ne(e){let{summary:t,children:n,...l}=e;const o=(0,ve.Z)(),r=(0,a.useRef)(null),{collapsed:i,setCollapsed:c}=(0,F.u)({initialState:!l.open}),[s,m]=(0,a.useState)(l.open),p=a.isValidElement(t)?t:a.createElement("summary",null,t??"Details");return a.createElement("details",(0,u.Z)({},l,{ref:r,open:s,"data-collapsed":i,className:(0,d.Z)(be.details,o&&be.isBrowser,l.className),onMouseDown:e=>{Ee(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const t=e.target;Ee(t)&&ge(t,r.current)&&(e.preventDefault(),i?(c(!1),m(!0)):c(!0))}}),p,a.createElement(F.z,{lazy:!1,collapsed:i,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{c(e),m(!e)}},a.createElement("div",{className:be.collapsibleContent},n)))}const Ce={details:"details_b_Ee"},Le="alert alert--info";function _e(e){let{...t}=e;return a.createElement(Ne,(0,u.Z)({},t,{className:(0,d.Z)(Le,Ce.details,t.className)}))}function ke(e){return a.createElement(ue,e)}const Ze={containsTaskList:"containsTaskList_mC6p"};function Te(e){if(void 0!==e)return(0,d.Z)(e,e?.includes("contains-task-list")&&Ze.containsTaskList)}const ye={img:"img_ev3q"};const xe="admonition_LlT9",He="admonitionHeading_tbUL",we="admonitionIcon_kALy",Ae="admonitionContent_S0QG";const Me={note:{infimaClassName:"secondary",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))},label:a.createElement(p.Z,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)"},"note")},tip:{infimaClassName:"success",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)"},"tip")},danger:{infimaClassName:"danger",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 12 16"},a.createElement("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))},label:a.createElement(p.Z,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)"},"danger")},info:{infimaClassName:"info",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 14 16"},a.createElement("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))},label:a.createElement(p.Z,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)"},"info")},caution:{infimaClassName:"warning",iconComponent:function(){return a.createElement("svg",{viewBox:"0 0 16 16"},a.createElement("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"}))},label:a.createElement(p.Z,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)"},"caution")}},Ue={secondary:"note",important:"info",success:"tip",warning:"danger"};function Be(e){const{mdxAdmonitionTitle:t,rest:n}=function(e){const t=a.Children.toArray(e),n=t.find((e=>a.isValidElement(e)&&"mdxAdmonitionTitle"===e.props?.mdxType)),l=a.createElement(a.Fragment,null,t.filter((e=>e!==n)));return{mdxAdmonitionTitle:n,rest:l}}(e.children);return{...e,title:e.title??t,children:n}}const Ie={head:function(e){const t=a.Children.map(e.children,(e=>a.isValidElement(e)?function(e){if(e.props?.mdxType&&e.props.originalType){const{mdxType:t,originalType:n,...l}=e.props;return a.createElement(e.props.originalType,l)}return e}(e):e));return a.createElement(he.Z,e,t)},code:function(e){const t=["a","abbr","b","br","button","cite","code","del","dfn","em","i","img","input","ins","kbd","label","object","output","q","ruby","s","small","span","strong","sub","sup","time","u","var","wbr"];return a.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")||(0,a.isValidElement)(e)&&t.includes(e.props?.mdxType)))?a.createElement("code",e):a.createElement(fe.Z,e)},a:function(e){return a.createElement(h.Z,e)},pre:function(e){return a.createElement(fe.Z,(0,a.isValidElement)(e.children)&&"code"===e.children.props?.originalType?e.children.props:{...e})},details:function(e){const t=a.Children.toArray(e.children),n=t.find((e=>a.isValidElement(e)&&"summary"===e.props?.mdxType)),l=a.createElement(a.Fragment,null,t.filter((e=>e!==n)));return a.createElement(_e,(0,u.Z)({},e,{summary:n}),l)},ul:function(e){return a.createElement("ul",(0,u.Z)({},e,{className:Te(e.className)}))},img:function(e){return a.createElement("img",(0,u.Z)({loading:"lazy"},e,{className:(t=e.className,(0,d.Z)(t,ye.img))}));var t},h1:e=>a.createElement(ke,(0,u.Z)({as:"h1"},e)),h2:e=>a.createElement(ke,(0,u.Z)({as:"h2"},e)),h3:e=>a.createElement(ke,(0,u.Z)({as:"h3"},e)),h4:e=>a.createElement(ke,(0,u.Z)({as:"h4"},e)),h5:e=>a.createElement(ke,(0,u.Z)({as:"h5"},e)),h6:e=>a.createElement(ke,(0,u.Z)({as:"h6"},e)),admonition:function(e){const{children:t,type:n,title:l,icon:o}=Be(e),r=function(e){const t=Ue[e]??e,n=Me[t];return n||(console.warn(`No admonition config found for admonition type "${t}". Using Info as fallback.`),Me.info)}(n),i=l??r.label,{iconComponent:c}=r,s=o??a.createElement(c,null);return a.createElement("div",{className:(0,d.Z)(N.k.common.admonition,N.k.common.admonitionType(e.type),"alert",`alert--${r.infimaClassName}`,xe)},a.createElement("div",{className:He},a.createElement("span",{className:we},s),i),a.createElement("div",{className:Ae},t))},mermaid:()=>null};function Se(e){let{children:t}=e;return a.createElement(pe.Zo,{components:Ie},t)}function ze(e){let{children:t}=e;const n=function(){const{metadata:e,frontMatter:t,contentTitle:n}=c();return t.hide_title||void 0!==n?null:e.title}();return a.createElement("div",{className:(0,d.Z)(N.k.docs.docMarkdown,"markdown")},n&&a.createElement("header",null,a.createElement(ue,{as:"h1"},n)),a.createElement(Se,null,t))}var Ve=n(3438),Oe=n(8596),Re=n(4996);function De(e){return a.createElement("svg",(0,u.Z)({viewBox:"0 0 24 24"},e),a.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const Pe={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function Fe(){const e=(0,Re.Z)("/");return a.createElement("li",{className:"breadcrumbs__item"},a.createElement(h.Z,{"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},a.createElement(De,{className:Pe.breadcrumbHomeIcon})))}const We={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function qe(e){let{children:t,href:n,isLast:l}=e;const o="breadcrumbs__link";return l?a.createElement("span",{className:o,itemProp:"name"},t):n?a.createElement(h.Z,{className:o,href:n,itemProp:"item"},a.createElement("span",{itemProp:"name"},t)):a.createElement("span",{className:o},t)}function je(e){let{children:t,active:n,index:l,addMicrodata:o}=e;return a.createElement("li",(0,u.Z)({},o&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,d.Z)("breadcrumbs__item",{"breadcrumbs__item--active":n})}),t,a.createElement("meta",{itemProp:"position",content:String(l+1)}))}function $e(){const e=(0,Ve.s1)(),t=(0,Oe.Ns)();return e?a.createElement("nav",{className:(0,d.Z)(N.k.docs.docBreadcrumbs,We.breadcrumbsContainer),"aria-label":(0,p.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},a.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&a.createElement(Fe,null),e.map(((t,n)=>{const l=n===e.length-1;return a.createElement(je,{key:n,active:l,index:n,addMicrodata:!!t.href},a.createElement(qe,{href:t.href,isLast:l},t.label))})))):null}const Ge={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function Ye(e){let{children:t}=e;const n=function(){const{frontMatter:e,toc:t}=c(),n=(0,m.i)(),l=e.hide_table_of_contents,o=!l&&t.length>0;return{hidden:l,mobile:o?a.createElement(oe,null):void 0,desktop:!o||"desktop"!==n&&"ssr"!==n?void 0:a.createElement(de,null)}}();return a.createElement("div",{className:"row"},a.createElement("div",{className:(0,d.Z)("col",!n.hidden&&Ge.docItemCol)},a.createElement(y,null),a.createElement("div",{className:Ge.docItemContainer},a.createElement("article",null,a.createElement($e,null),a.createElement(x,null),n.mobile,a.createElement(ze,null,t),a.createElement(P,null)),a.createElement(b,null))),n.desktop&&a.createElement("div",{className:"col col--3"},n.desktop))}function Je(e){const t=`docs-doc-id-${e.content.metadata.unversionedId}`,n=e.content;return a.createElement(i,{content:e.content},a.createElement(l.FG,{className:t},a.createElement(s,null),a.createElement(Ye,null,a.createElement(n,null))))}},4477:(e,t,n)=>{n.d(t,{E:()=>i,q:()=>r});var a=n(7294),l=n(902);const o=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(o.Provider,{value:n},t)}function i(){const e=(0,a.useContext)(o);if(null===e)throw new l.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/17896441.6473f609.js b/assets/js/17896441.6473f609.js new file mode 100644 index 000000000..309b0e05f --- /dev/null +++ b/assets/js/17896441.6473f609.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[401],{4086:(e,n,t)=>{t.r(n),t.d(n,{default:()=>jn});var s=t(6540),i=t(9024),a=t(9532),l=t(4848);const o=s.createContext(null);function r(e){let{children:n,content:t}=e;const i=function(e){return(0,s.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(t);return(0,l.jsx)(o.Provider,{value:i,children:n})}function c(){const e=(0,s.useContext)(o);if(null===e)throw new a.dV("DocProvider");return e}function d(){const{metadata:e,frontMatter:n,assets:t}=c();return(0,l.jsx)(i.be,{title:e.title,description:e.description,keywords:n.keywords,image:t.image??n.image})}var u=t(4164),m=t(4581),h=t(1312),x=t(8774);function p(e){const{permalink:n,title:t,subLabel:s,isNext:i}=e;return(0,l.jsxs)(x.A,{className:(0,u.A)("pagination-nav__link",i?"pagination-nav__link--next":"pagination-nav__link--prev"),to:n,children:[s&&(0,l.jsx)("div",{className:"pagination-nav__sublabel",children:s}),(0,l.jsx)("div",{className:"pagination-nav__label",children:t})]})}function f(e){const{previous:n,next:t}=e;return(0,l.jsxs)("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,h.T)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"}),children:[n&&(0,l.jsx)(p,{...n,subLabel:(0,l.jsx)(h.A,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc",children:"Previous"})}),t&&(0,l.jsx)(p,{...t,subLabel:(0,l.jsx)(h.A,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc",children:"Next"}),isNext:!0})]})}function v(){const{metadata:e}=c();return(0,l.jsx)(f,{previous:e.previous,next:e.next})}var g=t(4586),j=t(4070),b=t(7559),A=t(5597),N=t(2252);const C={unreleased:function(e){let{siteTitle:n,versionMetadata:t}=e;return(0,l.jsx)(h.A,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:n,versionLabel:(0,l.jsx)("b",{children:t.label})},children:"This is unreleased documentation for {siteTitle} {versionLabel} version."})},unmaintained:function(e){let{siteTitle:n,versionMetadata:t}=e;return(0,l.jsx)(h.A,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:n,versionLabel:(0,l.jsx)("b",{children:t.label})},children:"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained."})}};function L(e){const n=C[e.versionMetadata.banner];return(0,l.jsx)(n,{...e})}function _(e){let{versionLabel:n,to:t,onClick:s}=e;return(0,l.jsx)(h.A,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:n,latestVersionLink:(0,l.jsx)("b",{children:(0,l.jsx)(x.A,{to:t,onClick:s,children:(0,l.jsx)(h.A,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label",children:"latest version"})})})},children:"For up-to-date documentation, see the {latestVersionLink} ({versionLabel})."})}function T(e){let{className:n,versionMetadata:t}=e;const{siteConfig:{title:s}}=(0,g.A)(),{pluginId:i}=(0,j.vT)({failfast:!0}),{savePreferredVersionName:a}=(0,A.g1)(i),{latestDocSuggestion:o,latestVersionSuggestion:r}=(0,j.HW)(i),c=o??(d=r).docs.find((e=>e.id===d.mainDocId));var d;return(0,l.jsxs)("div",{className:(0,u.A)(n,b.G.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert",children:[(0,l.jsx)("div",{children:(0,l.jsx)(L,{siteTitle:s,versionMetadata:t})}),(0,l.jsx)("div",{className:"margin-top--md",children:(0,l.jsx)(_,{versionLabel:r.label,to:c.path,onClick:()=>a(r.name)})})]})}function y(e){let{className:n}=e;const t=(0,N.r)();return t.banner?(0,l.jsx)(T,{className:n,versionMetadata:t}):null}function k(e){let{className:n}=e;const t=(0,N.r)();return t.badge?(0,l.jsx)("span",{className:(0,u.A)(n,b.G.docs.docVersionBadge,"badge badge--secondary"),children:(0,l.jsx)(h.A,{id:"theme.docs.versionBadge.label",values:{versionLabel:t.label},children:"Version: {versionLabel}"})}):null}const H={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};function w(e){let{permalink:n,label:t,count:s}=e;return(0,l.jsxs)(x.A,{href:n,className:(0,u.A)(H.tag,s?H.tagWithCount:H.tagRegular),children:[t,s&&(0,l.jsx)("span",{children:s})]})}const M={tags:"tags_jXut",tag:"tag_QGVx"};function U(e){let{tags:n}=e;return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)("b",{children:(0,l.jsx)(h.A,{id:"theme.tags.tagsListLabel",description:"The label alongside a tag list",children:"Tags:"})}),(0,l.jsx)("ul",{className:(0,u.A)(M.tags,"padding--none","margin-left--sm"),children:n.map((e=>{let{label:n,permalink:t}=e;return(0,l.jsx)("li",{className:M.tag,children:(0,l.jsx)(w,{label:n,permalink:t})},t)}))})]})}const B={iconEdit:"iconEdit_Z9Sw"};function E(e){let{className:n,...t}=e;return(0,l.jsx)("svg",{fill:"currentColor",height:"20",width:"20",viewBox:"0 0 40 40",className:(0,u.A)(B.iconEdit,n),"aria-hidden":"true",...t,children:(0,l.jsx)("g",{children:(0,l.jsx)("path",{d:"m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"})})})}function I(e){let{editUrl:n}=e;return(0,l.jsxs)(x.A,{to:n,className:b.G.common.editThisPage,children:[(0,l.jsx)(E,{}),(0,l.jsx)(h.A,{id:"theme.common.editThisPage",description:"The link label to edit the current page",children:"Edit this page"})]})}function z(e){void 0===e&&(e={});const{i18n:{currentLocale:n}}=(0,g.A)(),t=function(){const{i18n:{currentLocale:e,localeConfigs:n}}=(0,g.A)();return n[e].calendar}();return new Intl.DateTimeFormat(n,{calendar:t,...e})}function S(e){let{lastUpdatedAt:n}=e;const t=new Date(n),s=z({day:"numeric",month:"short",year:"numeric",timeZone:"UTC"}).format(t);return(0,l.jsx)(h.A,{id:"theme.lastUpdated.atDate",description:"The words used to describe on which date a page has been last updated",values:{date:(0,l.jsx)("b",{children:(0,l.jsx)("time",{dateTime:t.toISOString(),itemProp:"dateModified",children:s})})},children:" on {date}"})}function V(e){let{lastUpdatedBy:n}=e;return(0,l.jsx)(h.A,{id:"theme.lastUpdated.byUser",description:"The words used to describe by who the page has been last updated",values:{user:(0,l.jsx)("b",{children:n})},children:" by {user}"})}function R(e){let{lastUpdatedAt:n,lastUpdatedBy:t}=e;return(0,l.jsxs)("span",{className:b.G.common.lastUpdated,children:[(0,l.jsx)(h.A,{id:"theme.lastUpdated.lastUpdatedAtBy",description:"The sentence used to display when a page has been last updated, and by who",values:{atDate:n?(0,l.jsx)(S,{lastUpdatedAt:n}):"",byUser:t?(0,l.jsx)(V,{lastUpdatedBy:t}):""},children:"Last updated{atDate}{byUser}"}),!1]})}const D={lastUpdated:"lastUpdated_JAkA"};function G(e){let{className:n,editUrl:t,lastUpdatedAt:s,lastUpdatedBy:i}=e;return(0,l.jsxs)("div",{className:(0,u.A)("row",n),children:[(0,l.jsx)("div",{className:"col",children:t&&(0,l.jsx)(I,{editUrl:t})}),(0,l.jsx)("div",{className:(0,u.A)("col",D.lastUpdated),children:(s||i)&&(0,l.jsx)(R,{lastUpdatedAt:s,lastUpdatedBy:i})})]})}function O(){const{metadata:e}=c(),{editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s,tags:i}=e,a=i.length>0,o=!!(n||t||s);return a||o?(0,l.jsxs)("footer",{className:(0,u.A)(b.G.docs.docFooter,"docusaurus-mt-lg"),children:[a&&(0,l.jsx)("div",{className:(0,u.A)("row margin-top--sm",b.G.docs.docFooterTagsRow),children:(0,l.jsx)("div",{className:"col",children:(0,l.jsx)(U,{tags:i})})}),o&&(0,l.jsx)(G,{className:(0,u.A)("margin-top--sm",b.G.docs.docFooterEditMetaRow),editUrl:n,lastUpdatedAt:t,lastUpdatedBy:s})]}):null}var P=t(1422),F=t(6342);function q(e){const n=e.map((e=>({...e,parentIndex:-1,children:[]}))),t=Array(7).fill(-1);n.forEach(((e,n)=>{const s=t.slice(2,e.level);e.parentIndex=Math.max(...s),t[e.level]=n}));const s=[];return n.forEach((e=>{const{parentIndex:t,...i}=e;t>=0?n[t].children.push(i):s.push(i)})),s}function W(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:s}=e;return n.flatMap((e=>{const n=W({toc:e.children,minHeadingLevel:t,maxHeadingLevel:s});return function(e){return e.level>=t&&e.level<=s}(e)?[{...e,children:n}]:n}))}function $(e){const n=e.getBoundingClientRect();return n.top===n.bottom?$(e.parentNode):n}function Z(e,n){let{anchorTopOffset:t}=n;const s=e.find((e=>$(e).top>=t));if(s){return function(e){return e.top>0&&e.bottom<window.innerHeight/2}($(s))?s:e[e.indexOf(s)-1]??null}return e[e.length-1]??null}function J(){const e=(0,s.useRef)(0),{navbar:{hideOnScroll:n}}=(0,F.p)();return(0,s.useEffect)((()=>{e.current=n?0:document.querySelector(".navbar").clientHeight}),[n]),e}function Y(e){const n=(0,s.useRef)(void 0),t=J();(0,s.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:s,linkActiveClassName:i,minHeadingLevel:a,maxHeadingLevel:l}=e;function o(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(s),o=function(e){let{minHeadingLevel:n,maxHeadingLevel:t}=e;const s=[];for(let i=n;i<=t;i+=1)s.push(`h${i}.anchor`);return Array.from(document.querySelectorAll(s.join()))}({minHeadingLevel:a,maxHeadingLevel:l}),r=Z(o,{anchorTopOffset:t.current}),c=e.find((e=>r&&r.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,t){t?(n.current&&n.current!==e&&n.current.classList.remove(i),e.classList.add(i),n.current=e):e.classList.remove(i)}(e,e===c)}))}return document.addEventListener("scroll",o),document.addEventListener("resize",o),o(),()=>{document.removeEventListener("scroll",o),document.removeEventListener("resize",o)}}),[e,t])}function Q(e){let{toc:n,className:t,linkClassName:s,isChild:i}=e;return n.length?(0,l.jsx)("ul",{className:i?void 0:t,children:n.map((e=>(0,l.jsxs)("li",{children:[(0,l.jsx)(x.A,{to:`#${e.id}`,className:s??void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,l.jsx)(Q,{isChild:!0,toc:e.children,className:t,linkClassName:s})]},e.id)))}):null}const X=s.memo(Q);function K(e){let{toc:n,className:t="table-of-contents table-of-contents__left-border",linkClassName:i="table-of-contents__link",linkActiveClassName:a,minHeadingLevel:o,maxHeadingLevel:r,...c}=e;const d=(0,F.p)(),u=o??d.tableOfContents.minHeadingLevel,m=r??d.tableOfContents.maxHeadingLevel,h=function(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:i}=e;return(0,s.useMemo)((()=>W({toc:q(n),minHeadingLevel:t,maxHeadingLevel:i})),[n,t,i])}({toc:n,minHeadingLevel:u,maxHeadingLevel:m});return Y((0,s.useMemo)((()=>{if(i&&a)return{linkClassName:i,linkActiveClassName:a,minHeadingLevel:u,maxHeadingLevel:m}}),[i,a,u,m])),(0,l.jsx)(X,{toc:h,className:t,linkClassName:i,...c})}const ee={tocCollapsibleButton:"tocCollapsibleButton_TO0P",tocCollapsibleButtonExpanded:"tocCollapsibleButtonExpanded_MG3E"};function ne(e){let{collapsed:n,...t}=e;return(0,l.jsx)("button",{type:"button",...t,className:(0,u.A)("clean-btn",ee.tocCollapsibleButton,!n&&ee.tocCollapsibleButtonExpanded,t.className),children:(0,l.jsx)(h.A,{id:"theme.TOCCollapsible.toggleButtonLabel",description:"The label used by the button on the collapsible TOC component",children:"On this page"})})}const te={tocCollapsible:"tocCollapsible_ETCw",tocCollapsibleContent:"tocCollapsibleContent_vkbj",tocCollapsibleExpanded:"tocCollapsibleExpanded_sAul"};function se(e){let{toc:n,className:t,minHeadingLevel:s,maxHeadingLevel:i}=e;const{collapsed:a,toggleCollapsed:o}=(0,P.u)({initialState:!0});return(0,l.jsxs)("div",{className:(0,u.A)(te.tocCollapsible,!a&&te.tocCollapsibleExpanded,t),children:[(0,l.jsx)(ne,{collapsed:a,onClick:o}),(0,l.jsx)(P.N,{lazy:!0,className:te.tocCollapsibleContent,collapsed:a,children:(0,l.jsx)(K,{toc:n,minHeadingLevel:s,maxHeadingLevel:i})})]})}const ie={tocMobile:"tocMobile_ITEo"};function ae(){const{toc:e,frontMatter:n}=c();return(0,l.jsx)(se,{toc:e,minHeadingLevel:n.toc_min_heading_level,maxHeadingLevel:n.toc_max_heading_level,className:(0,u.A)(b.G.docs.docTocMobile,ie.tocMobile)})}const le={tableOfContents:"tableOfContents_bqdL",docItemContainer:"docItemContainer_F8PC"},oe="table-of-contents__link toc-highlight",re="table-of-contents__link--active";function ce(e){let{className:n,...t}=e;return(0,l.jsx)("div",{className:(0,u.A)(le.tableOfContents,"thin-scrollbar",n),children:(0,l.jsx)(K,{...t,linkClassName:oe,linkActiveClassName:re})})}function de(){const{toc:e,frontMatter:n}=c();return(0,l.jsx)(ce,{toc:e,minHeadingLevel:n.toc_min_heading_level,maxHeadingLevel:n.toc_max_heading_level,className:b.G.docs.docTocDesktop})}var ue=t(1107),me=t(8453),he=t(5260),xe=t(2364);function pe(e){return(0,l.jsx)("code",{...e})}var fe=t(3427),ve=t(2303);const ge={details:"details_lb9f",isBrowser:"isBrowser_bmU9",collapsibleContent:"collapsibleContent_i85q"};function je(e){return!!e&&("SUMMARY"===e.tagName||je(e.parentElement))}function be(e,n){return!!e&&(e===n||be(e.parentElement,n))}function Ae(e){let{summary:n,children:t,...i}=e;(0,fe.A)().collectAnchor(i.id);const a=(0,ve.A)(),o=(0,s.useRef)(null),{collapsed:r,setCollapsed:c}=(0,P.u)({initialState:!i.open}),[d,m]=(0,s.useState)(i.open),h=s.isValidElement(n)?n:(0,l.jsx)("summary",{children:n??"Details"});return(0,l.jsxs)("details",{...i,ref:o,open:d,"data-collapsed":r,className:(0,u.A)(ge.details,a&&ge.isBrowser,i.className),onMouseDown:e=>{je(e.target)&&e.detail>1&&e.preventDefault()},onClick:e=>{e.stopPropagation();const n=e.target;je(n)&&be(n,o.current)&&(e.preventDefault(),r?(c(!1),m(!0)):c(!0))},children:[h,(0,l.jsx)(P.N,{lazy:!1,collapsed:r,disableSSRStyle:!0,onCollapseTransitionEnd:e=>{c(e),m(!e)},children:(0,l.jsx)("div",{className:ge.collapsibleContent,children:t})})]})}const Ne={details:"details_b_Ee"},Ce="alert alert--info";function Le(e){let{...n}=e;return(0,l.jsx)(Ae,{...n,className:(0,u.A)(Ce,Ne.details,n.className)})}function _e(e){const n=s.Children.toArray(e.children),t=n.find((e=>s.isValidElement(e)&&"summary"===e.type)),i=(0,l.jsx)(l.Fragment,{children:n.filter((e=>e!==t))});return(0,l.jsx)(Le,{...e,summary:t,children:i})}function Te(e){return(0,l.jsx)(ue.A,{...e})}const ye={containsTaskList:"containsTaskList_mC6p"};function ke(e){if(void 0!==e)return(0,u.A)(e,e?.includes("contains-task-list")&&ye.containsTaskList)}const He={img:"img_ev3q"};function we(e){const{mdxAdmonitionTitle:n,rest:t}=function(e){const n=s.Children.toArray(e),t=n.find((e=>s.isValidElement(e)&&"mdxAdmonitionTitle"===e.type)),i=n.filter((e=>e!==t)),a=t?.props.children;return{mdxAdmonitionTitle:a,rest:i.length>0?(0,l.jsx)(l.Fragment,{children:i}):null}}(e.children),i=e.title??n;return{...e,...i&&{title:i},children:t}}const Me={admonition:"admonition_xJq3",admonitionHeading:"admonitionHeading_Gvgb",admonitionIcon:"admonitionIcon_Rf37",admonitionContent:"admonitionContent_BuS1"};function Ue(e){let{type:n,className:t,children:s}=e;return(0,l.jsx)("div",{className:(0,u.A)(b.G.common.admonition,b.G.common.admonitionType(n),Me.admonition,t),children:s})}function Be(e){let{icon:n,title:t}=e;return(0,l.jsxs)("div",{className:Me.admonitionHeading,children:[(0,l.jsx)("span",{className:Me.admonitionIcon,children:n}),t]})}function Ee(e){let{children:n}=e;return n?(0,l.jsx)("div",{className:Me.admonitionContent,children:n}):null}function Ie(e){const{type:n,icon:t,title:s,children:i,className:a}=e;return(0,l.jsxs)(Ue,{type:n,className:a,children:[s||t?(0,l.jsx)(Be,{title:s,icon:t}):null,(0,l.jsx)(Ee,{children:i})]})}function ze(e){return(0,l.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,l.jsx)("path",{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})})}const Se={icon:(0,l.jsx)(ze,{}),title:(0,l.jsx)(h.A,{id:"theme.admonition.note",description:"The default label used for the Note admonition (:::note)",children:"note"})};function Ve(e){return(0,l.jsx)(Ie,{...Se,...e,className:(0,u.A)("alert alert--secondary",e.className),children:e.children})}function Re(e){return(0,l.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,l.jsx)("path",{fillRule:"evenodd",d:"M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"})})}const De={icon:(0,l.jsx)(Re,{}),title:(0,l.jsx)(h.A,{id:"theme.admonition.tip",description:"The default label used for the Tip admonition (:::tip)",children:"tip"})};function Ge(e){return(0,l.jsx)(Ie,{...De,...e,className:(0,u.A)("alert alert--success",e.className),children:e.children})}function Oe(e){return(0,l.jsx)("svg",{viewBox:"0 0 14 16",...e,children:(0,l.jsx)("path",{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})})}const Pe={icon:(0,l.jsx)(Oe,{}),title:(0,l.jsx)(h.A,{id:"theme.admonition.info",description:"The default label used for the Info admonition (:::info)",children:"info"})};function Fe(e){return(0,l.jsx)(Ie,{...Pe,...e,className:(0,u.A)("alert alert--info",e.className),children:e.children})}function qe(e){return(0,l.jsx)("svg",{viewBox:"0 0 16 16",...e,children:(0,l.jsx)("path",{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})})}const We={icon:(0,l.jsx)(qe,{}),title:(0,l.jsx)(h.A,{id:"theme.admonition.warning",description:"The default label used for the Warning admonition (:::warning)",children:"warning"})};function $e(e){return(0,l.jsx)("svg",{viewBox:"0 0 12 16",...e,children:(0,l.jsx)("path",{fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"})})}const Ze={icon:(0,l.jsx)($e,{}),title:(0,l.jsx)(h.A,{id:"theme.admonition.danger",description:"The default label used for the Danger admonition (:::danger)",children:"danger"})};const Je={icon:(0,l.jsx)(qe,{}),title:(0,l.jsx)(h.A,{id:"theme.admonition.caution",description:"The default label used for the Caution admonition (:::caution)",children:"caution"})};const Ye={...{note:Ve,tip:Ge,info:Fe,warning:function(e){return(0,l.jsx)(Ie,{...We,...e,className:(0,u.A)("alert alert--warning",e.className),children:e.children})},danger:function(e){return(0,l.jsx)(Ie,{...Ze,...e,className:(0,u.A)("alert alert--danger",e.className),children:e.children})}},...{secondary:e=>(0,l.jsx)(Ve,{title:"secondary",...e}),important:e=>(0,l.jsx)(Fe,{title:"important",...e}),success:e=>(0,l.jsx)(Ge,{title:"success",...e}),caution:function(e){return(0,l.jsx)(Ie,{...Je,...e,className:(0,u.A)("alert alert--warning",e.className),children:e.children})}}};function Qe(e){const n=we(e),t=(s=n.type,Ye[s]||(console.warn(`No admonition component found for admonition type "${s}". Using Info as fallback.`),Ye.info));var s;return(0,l.jsx)(t,{...n})}const Xe={Head:he.A,details:_e,Details:_e,code:function(e){return function(e){return void 0!==e.children&&s.Children.toArray(e.children).every((e=>"string"==typeof e&&!e.includes("\n")))}(e)?(0,l.jsx)(pe,{...e}):(0,l.jsx)(xe.A,{...e})},a:function(e){return(0,l.jsx)(x.A,{...e})},pre:function(e){return(0,l.jsx)(l.Fragment,{children:e.children})},ul:function(e){return(0,l.jsx)("ul",{...e,className:ke(e.className)})},li:function(e){return(0,fe.A)().collectAnchor(e.id),(0,l.jsx)("li",{...e})},img:function(e){return(0,l.jsx)("img",{decoding:"async",loading:"lazy",...e,className:(n=e.className,(0,u.A)(n,He.img))});var n},h1:e=>(0,l.jsx)(Te,{as:"h1",...e}),h2:e=>(0,l.jsx)(Te,{as:"h2",...e}),h3:e=>(0,l.jsx)(Te,{as:"h3",...e}),h4:e=>(0,l.jsx)(Te,{as:"h4",...e}),h5:e=>(0,l.jsx)(Te,{as:"h5",...e}),h6:e=>(0,l.jsx)(Te,{as:"h6",...e}),admonition:Qe,mermaid:()=>null};function Ke(e){let{children:n}=e;return(0,l.jsx)(me.x,{components:Xe,children:n})}function en(e){let{children:n}=e;const t=function(){const{metadata:e,frontMatter:n,contentTitle:t}=c();return n.hide_title||void 0!==t?null:e.title}();return(0,l.jsxs)("div",{className:(0,u.A)(b.G.docs.docMarkdown,"markdown"),children:[t&&(0,l.jsx)("header",{children:(0,l.jsx)(ue.A,{as:"h1",children:t})}),(0,l.jsx)(Ke,{children:n})]})}var nn=t(4142),tn=t(9169),sn=t(6025);function an(e){return(0,l.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,l.jsx)("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"})})}const ln={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function on(){const e=(0,sn.A)("/");return(0,l.jsx)("li",{className:"breadcrumbs__item",children:(0,l.jsx)(x.A,{"aria-label":(0,h.T)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e,children:(0,l.jsx)(an,{className:ln.breadcrumbHomeIcon})})})}const rn={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function cn(e){let{children:n,href:t,isLast:s}=e;const i="breadcrumbs__link";return s?(0,l.jsx)("span",{className:i,itemProp:"name",children:n}):t?(0,l.jsx)(x.A,{className:i,href:t,itemProp:"item",children:(0,l.jsx)("span",{itemProp:"name",children:n})}):(0,l.jsx)("span",{className:i,children:n})}function dn(e){let{children:n,active:t,index:s,addMicrodata:i}=e;return(0,l.jsxs)("li",{...i&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},className:(0,u.A)("breadcrumbs__item",{"breadcrumbs__item--active":t}),children:[n,(0,l.jsx)("meta",{itemProp:"position",content:String(s+1)})]})}function un(){const e=(0,nn.OF)(),n=(0,tn.Dt)();return e?(0,l.jsx)("nav",{className:(0,u.A)(b.G.docs.docBreadcrumbs,rn.breadcrumbsContainer),"aria-label":(0,h.T)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"}),children:(0,l.jsxs)("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList",children:[n&&(0,l.jsx)(on,{}),e.map(((n,t)=>{const s=t===e.length-1,i="category"===n.type&&n.linkUnlisted?void 0:n.href;return(0,l.jsx)(dn,{active:s,index:t,addMicrodata:!!i,children:(0,l.jsx)(cn,{href:i,isLast:s,children:n.label})},t)}))]})}):null}function mn(){return(0,l.jsx)(h.A,{id:"theme.unlistedContent.title",description:"The unlisted content banner title",children:"Unlisted page"})}function hn(){return(0,l.jsx)(h.A,{id:"theme.unlistedContent.message",description:"The unlisted content banner message",children:"This page is unlisted. Search engines will not index it, and only users having a direct link can access it."})}function xn(){return(0,l.jsx)(he.A,{children:(0,l.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})}function pn(e){let{className:n}=e;return(0,l.jsx)(Qe,{type:"caution",title:(0,l.jsx)(mn,{}),className:(0,u.A)(n,b.G.common.unlistedBanner),children:(0,l.jsx)(hn,{})})}function fn(e){return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(xn,{}),(0,l.jsx)(pn,{...e})]})}const vn={docItemContainer:"docItemContainer_Djhp",docItemCol:"docItemCol_VOVn"};function gn(e){let{children:n}=e;const t=function(){const{frontMatter:e,toc:n}=c(),t=(0,m.l)(),s=e.hide_table_of_contents,i=!s&&n.length>0;return{hidden:s,mobile:i?(0,l.jsx)(ae,{}):void 0,desktop:!i||"desktop"!==t&&"ssr"!==t?void 0:(0,l.jsx)(de,{})}}(),{metadata:{unlisted:s}}=c();return(0,l.jsxs)("div",{className:"row",children:[(0,l.jsxs)("div",{className:(0,u.A)("col",!t.hidden&&vn.docItemCol),children:[s&&(0,l.jsx)(fn,{}),(0,l.jsx)(y,{}),(0,l.jsxs)("div",{className:vn.docItemContainer,children:[(0,l.jsxs)("article",{children:[(0,l.jsx)(un,{}),(0,l.jsx)(k,{}),t.mobile,(0,l.jsx)(en,{children:n}),(0,l.jsx)(O,{})]}),(0,l.jsx)(v,{})]})]}),t.desktop&&(0,l.jsx)("div",{className:"col col--3",children:t.desktop})]})}function jn(e){const n=`docs-doc-id-${e.content.metadata.id}`,t=e.content;return(0,l.jsx)(r,{content:e.content,children:(0,l.jsxs)(i.e3,{className:n,children:[(0,l.jsx)(d,{}),(0,l.jsx)(gn,{children:(0,l.jsx)(t,{})})]})})}}}]); \ No newline at end of file diff --git a/assets/js/1a4e3797.0583fddb.js b/assets/js/1a4e3797.0583fddb.js new file mode 100644 index 000000000..432152814 --- /dev/null +++ b/assets/js/1a4e3797.0583fddb.js @@ -0,0 +1,2 @@ +/*! For license information please see 1a4e3797.0583fddb.js.LICENSE.txt */ +(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[138],{2733:e=>{function t(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=t,t.prototype._events=void 0,t.prototype._maxListeners=void 0,t.defaultMaxListeners=10,t.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},t.prototype.emit=function(e){var t,s,a,c,o,u;if(this._events||(this._events={}),"error"===e&&(!this._events.error||n(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(i(s=this._events[e]))return!1;if(r(s))switch(arguments.length){case 1:s.call(this);break;case 2:s.call(this,arguments[1]);break;case 3:s.call(this,arguments[1],arguments[2]);break;default:c=Array.prototype.slice.call(arguments,1),s.apply(this,c)}else if(n(s))for(c=Array.prototype.slice.call(arguments,1),a=(u=s.slice()).length,o=0;o<a;o++)u[o].apply(this,c);return!0},t.prototype.addListener=function(e,s){var a;if(!r(s))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,r(s.listener)?s.listener:s),this._events[e]?n(this._events[e])?this._events[e].push(s):this._events[e]=[this._events[e],s]:this._events[e]=s,n(this._events[e])&&!this._events[e].warned&&(a=i(this._maxListeners)?t.defaultMaxListeners:this._maxListeners)&&a>0&&this._events[e].length>a&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function i(){this.removeListener(e,i),n||(n=!0,t.apply(this,arguments))}return i.listener=t,this.on(e,i),this},t.prototype.removeListener=function(e,t){var i,s,a,c;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(a=(i=this._events[e]).length,s=-1,i===t||r(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(n(i)){for(c=a;c-- >0;)if(i[c]===t||i[c].listener&&i[c].listener===t){s=c;break}if(s<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(s,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},t.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},t.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},t.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},t.listenerCount=function(e,t){return e.listenerCount(t)}},4103:(e,t,r)=>{"use strict";var n=r(6571),i=r(9127),s=r(3371),a=r(7691);function c(e,t,r,i){return new n(e,t,r,i)}c.version=r(6938),c.AlgoliaSearchHelper=n,c.SearchParameters=s,c.RecommendParameters=i,c.SearchResults=a,e.exports=c},6732:(e,t,r)=>{"use strict";var n=r(2733);function i(e,t,r){this.main=e,this.fn=t,this.recommendFn=r,this.lastResults=null,this.lastRecommendResults=null}r(3014)(i,n),i.prototype.detach=function(){this.removeAllListeners(),this.main.detachDerivedHelper(this)},i.prototype.getModifiedState=function(e){return this.fn(e)},i.prototype.getModifiedRecommendState=function(e){return this.recommendFn(e)},e.exports=i},9127:e=>{"use strict";function t(e){e=e||{},this.params=e.params||[]}t.prototype={constructor:t,addParams:function(e){var r=this.params.slice(),n=this.params.findIndex((function(t){return t.$$id===e.$$id}));return-1!==n?r.splice(n,1,e):r.push(e),new t({params:r})},removeParams:function(e){return new t({params:this.params.filter((function(t){return t.$$id!==e}))})},addFrequentlyBoughtTogether:function(e){return this.addParams(Object.assign({},e,{model:"bought-together"}))},addRelatedProducts:function(e){return this.addParams(Object.assign({},e,{model:"related-products"}))},addTrendingItems:function(e){return this.addParams(Object.assign({},e,{model:"trending-items"}))},addTrendingFacets:function(e){return this.addParams(Object.assign({},e,{model:"trending-facets"}))},addLookingSimilar:function(e){return this.addParams(Object.assign({},e,{model:"looking-similar"}))},_buildQueries:function(e){return this.params.map((function(t){var r=Object.assign({},t,{indexName:e});return delete r.$$id,r}))}},e.exports=t},1673:(e,t,r)=>{"use strict";var n=r(9110),i=r(317),s=r(1383),a={addRefinement:function(e,t,r){if(a.isRefined(e,t,r))return e;var i=""+r,s=e[t]?e[t].concat(i):[i],c={};return c[t]=s,n({},c,e)},removeRefinement:function(e,t,r){if(void 0===r)return a.clearRefinement(e,(function(e,r){return t===r}));var n=""+r;return a.clearRefinement(e,(function(e,r){return t===r&&n===e}))},toggleRefinement:function(e,t,r){if(void 0===r)throw new Error("toggleRefinement should be used with a value");return a.isRefined(e,t,r)?a.removeRefinement(e,t,r):a.addRefinement(e,t,r)},clearRefinement:function(e,t,r){if(void 0===t)return i(e)?{}:e;if("string"==typeof t)return s(e,[t]);if("function"==typeof t){var n=!1,a=Object.keys(e).reduce((function(i,s){var a=e[s]||[],c=a.filter((function(e){return!t(e,s,r)}));return c.length!==a.length&&(n=!0),i[s]=c,i}),{});return n?a:e}},isRefined:function(e,t,r){var n=Boolean(e[t])&&e[t].length>0;if(void 0===r||!n)return n;var i=""+r;return-1!==e[t].indexOf(i)}};e.exports=a},3371:(e,t,r)=>{"use strict";var n=r(9110),i=r(849),s=r(4843),a=r(4728),c=r(317),o=r(1383),u=r(7507),h=r(2208),f=r(1673);function l(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((function(e,r){return l(t[r],e)})):e===t}function m(e){var t=e?m._parseNumbers(e):{};void 0===t.userToken||h(t.userToken)||console.warn("[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\n - Format: [a-zA-Z0-9_-]{1,64}"),this.facets=t.facets||[],this.disjunctiveFacets=t.disjunctiveFacets||[],this.hierarchicalFacets=t.hierarchicalFacets||[],this.facetsRefinements=t.facetsRefinements||{},this.facetsExcludes=t.facetsExcludes||{},this.disjunctiveFacetsRefinements=t.disjunctiveFacetsRefinements||{},this.numericRefinements=t.numericRefinements||{},this.tagRefinements=t.tagRefinements||[],this.hierarchicalFacetsRefinements=t.hierarchicalFacetsRefinements||{};var r=this;Object.keys(t).forEach((function(e){var n=-1!==m.PARAMETERS.indexOf(e),i=void 0!==t[e];!n&&i&&(r[e]=t[e])}))}m.PARAMETERS=Object.keys(new m),m._parseNumbers=function(e){if(e instanceof m)return e;var t={};if(["aroundPrecision","aroundRadius","getRankingInfo","minWordSizefor2Typos","minWordSizefor1Typo","page","maxValuesPerFacet","distinct","minimumAroundRadius","hitsPerPage","minProximity"].forEach((function(r){var n=e[r];if("string"==typeof n){var i=parseFloat(n);t[r]=isNaN(i)?n:i}})),Array.isArray(e.insideBoundingBox)&&(t.insideBoundingBox=e.insideBoundingBox.map((function(e){return Array.isArray(e)?e.map((function(e){return parseFloat(e)})):e}))),e.numericRefinements){var r={};Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t]||{};r[t]={},Object.keys(n).forEach((function(e){var i=n[e].map((function(e){return Array.isArray(e)?e.map((function(e){return"string"==typeof e?parseFloat(e):e})):"string"==typeof e?parseFloat(e):e}));r[t][e]=i}))})),t.numericRefinements=r}return a(e,t)},m.make=function(e){var t=new m(e);return(e.hierarchicalFacets||[]).forEach((function(e){if(e.rootPath){var r=t.getHierarchicalRefinement(e.name);r.length>0&&0!==r[0].indexOf(e.rootPath)&&(t=t.clearRefinements(e.name)),0===(r=t.getHierarchicalRefinement(e.name)).length&&(t=t.toggleHierarchicalFacetRefinement(e.name,e.rootPath))}})),t},m.validate=function(e,t){var r=t||{};return e.tagFilters&&r.tagRefinements&&r.tagRefinements.length>0?new Error("[Tags] Cannot switch from the managed tag API to the advanced API. It is probably an error, if it is really what you want, you should first clear the tags with clearTags method."):e.tagRefinements.length>0&&r.tagFilters?new Error("[Tags] Cannot switch from the advanced tag API to the managed API. It is probably an error, if it is not, you should first clear the tags with clearTags method."):e.numericFilters&&r.numericRefinements&&c(r.numericRefinements)?new Error("[Numeric filters] Can't switch from the advanced to the managed API. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):c(e.numericRefinements)&&r.numericFilters?new Error("[Numeric filters] Can't switch from the managed API to the advanced. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):null},m.prototype={constructor:m,clearRefinements:function(e){var t={numericRefinements:this._clearNumericRefinements(e),facetsRefinements:f.clearRefinement(this.facetsRefinements,e,"conjunctiveFacet"),facetsExcludes:f.clearRefinement(this.facetsExcludes,e,"exclude"),disjunctiveFacetsRefinements:f.clearRefinement(this.disjunctiveFacetsRefinements,e,"disjunctiveFacet"),hierarchicalFacetsRefinements:f.clearRefinement(this.hierarchicalFacetsRefinements,e,"hierarchicalFacet")};return t.numericRefinements===this.numericRefinements&&t.facetsRefinements===this.facetsRefinements&&t.facetsExcludes===this.facetsExcludes&&t.disjunctiveFacetsRefinements===this.disjunctiveFacetsRefinements&&t.hierarchicalFacetsRefinements===this.hierarchicalFacetsRefinements?this:this.setQueryParameters(t)},clearTags:function(){return void 0===this.tagFilters&&0===this.tagRefinements.length?this:this.setQueryParameters({tagFilters:void 0,tagRefinements:[]})},setIndex:function(e){return e===this.index?this:this.setQueryParameters({index:e})},setQuery:function(e){return e===this.query?this:this.setQueryParameters({query:e})},setPage:function(e){return e===this.page?this:this.setQueryParameters({page:e})},setFacets:function(e){return this.setQueryParameters({facets:e})},setDisjunctiveFacets:function(e){return this.setQueryParameters({disjunctiveFacets:e})},setHitsPerPage:function(e){return this.hitsPerPage===e?this:this.setQueryParameters({hitsPerPage:e})},setTypoTolerance:function(e){return this.typoTolerance===e?this:this.setQueryParameters({typoTolerance:e})},addNumericRefinement:function(e,t,r){var n=u(r);if(this.isNumericRefined(e,t,n))return this;var i=a({},this.numericRefinements);return i[e]=a({},i[e]),i[e][t]?(i[e][t]=i[e][t].slice(),i[e][t].push(n)):i[e][t]=[n],this.setQueryParameters({numericRefinements:i})},getConjunctiveRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsRefinements[e]||[]},getDisjunctiveRefinements:function(e){return this.isDisjunctiveFacet(e)&&this.disjunctiveFacetsRefinements[e]||[]},getHierarchicalRefinement:function(e){return this.hierarchicalFacetsRefinements[e]||[]},getExcludeRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsExcludes[e]||[]},removeNumericRefinement:function(e,t,r){var n=r;return void 0!==n?this.isNumericRefined(e,t,n)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,i){return i===e&&r.op===t&&l(r.val,u(n))}))}):this:void 0!==t?this.isNumericRefined(e,t)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,n){return n===e&&r.op===t}))}):this:this.isNumericRefined(e)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(t,r){return r===e}))}):this},getNumericRefinements:function(e){return this.numericRefinements[e]||{}},getNumericRefinement:function(e,t){return this.numericRefinements[e]&&this.numericRefinements[e][t]},_clearNumericRefinements:function(e){if(void 0===e)return c(this.numericRefinements)?{}:this.numericRefinements;if("string"==typeof e)return o(this.numericRefinements,[e]);if("function"==typeof e){var t=!1,r=this.numericRefinements,n=Object.keys(r).reduce((function(n,i){var s=r[i],a={};return s=s||{},Object.keys(s).forEach((function(r){var n=s[r]||[],c=[];n.forEach((function(t){e({val:t,op:r},i,"numeric")||c.push(t)})),c.length!==n.length&&(t=!0),a[r]=c})),n[i]=a,n}),{});return t?n:this.numericRefinements}},addFacet:function(e){return this.isConjunctiveFacet(e)?this:this.setQueryParameters({facets:this.facets.concat([e])})},addDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this:this.setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.concat([e])})},addHierarchicalFacet:function(e){if(this.isHierarchicalFacet(e.name))throw new Error("Cannot declare two hierarchical facets with the same name: `"+e.name+"`");return this.setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.concat([e])})},addFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this:this.setQueryParameters({facetsRefinements:f.addRefinement(this.facetsRefinements,e,t)})},addExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this:this.setQueryParameters({facetsExcludes:f.addRefinement(this.facetsExcludes,e,t)})},addDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this:this.setQueryParameters({disjunctiveFacetsRefinements:f.addRefinement(this.disjunctiveFacetsRefinements,e,t)})},addTagRefinement:function(e){if(this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.concat(e)};return this.setQueryParameters(t)},removeFacet:function(e){return this.isConjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({facets:this.facets.filter((function(t){return t!==e}))}):this},removeDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.filter((function(t){return t!==e}))}):this},removeHierarchicalFacet:function(e){return this.isHierarchicalFacet(e)?this.clearRefinements(e).setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.filter((function(t){return t.name!==e}))}):this},removeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this.setQueryParameters({facetsRefinements:f.removeRefinement(this.facetsRefinements,e,t)}):this},removeExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this.setQueryParameters({facetsExcludes:f.removeRefinement(this.facetsExcludes,e,t)}):this},removeDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this.setQueryParameters({disjunctiveFacetsRefinements:f.removeRefinement(this.disjunctiveFacetsRefinements,e,t)}):this},removeTagRefinement:function(e){if(!this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.filter((function(t){return t!==e}))};return this.setQueryParameters(t)},toggleRefinement:function(e,t){return this.toggleFacetRefinement(e,t)},toggleFacetRefinement:function(e,t){if(this.isHierarchicalFacet(e))return this.toggleHierarchicalFacetRefinement(e,t);if(this.isConjunctiveFacet(e))return this.toggleConjunctiveFacetRefinement(e,t);if(this.isDisjunctiveFacet(e))return this.toggleDisjunctiveFacetRefinement(e,t);throw new Error("Cannot refine the undeclared facet "+e+"; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets")},toggleConjunctiveFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsRefinements:f.toggleRefinement(this.facetsRefinements,e,t)})},toggleExcludeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsExcludes:f.toggleRefinement(this.facetsExcludes,e,t)})},toggleDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return this.setQueryParameters({disjunctiveFacetsRefinements:f.toggleRefinement(this.disjunctiveFacetsRefinements,e,t)})},toggleHierarchicalFacetRefinement:function(e,t){if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration");var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e)),i={};return void 0!==this.hierarchicalFacetsRefinements[e]&&this.hierarchicalFacetsRefinements[e].length>0&&(this.hierarchicalFacetsRefinements[e][0]===t||0===this.hierarchicalFacetsRefinements[e][0].indexOf(t+r))?-1===t.indexOf(r)?i[e]=[]:i[e]=[t.slice(0,t.lastIndexOf(r))]:i[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},i,this.hierarchicalFacetsRefinements)})},addHierarchicalFacetRefinement:function(e,t){if(this.isHierarchicalFacetRefined(e))throw new Error(e+" is already refined.");if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration.");var r={};return r[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},r,this.hierarchicalFacetsRefinements)})},removeHierarchicalFacetRefinement:function(e){if(!this.isHierarchicalFacetRefined(e))return this;var t={};return t[e]=[],this.setQueryParameters({hierarchicalFacetsRefinements:n({},t,this.hierarchicalFacetsRefinements)})},toggleTagRefinement:function(e){return this.isTagRefined(e)?this.removeTagRefinement(e):this.addTagRefinement(e)},isDisjunctiveFacet:function(e){return this.disjunctiveFacets.indexOf(e)>-1},isHierarchicalFacet:function(e){return void 0!==this.getHierarchicalFacetByName(e)},isConjunctiveFacet:function(e){return this.facets.indexOf(e)>-1},isFacetRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsRefinements,e,t)},isExcludeRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsExcludes,e,t)},isDisjunctiveFacetRefined:function(e,t){return!!this.isDisjunctiveFacet(e)&&f.isRefined(this.disjunctiveFacetsRefinements,e,t)},isHierarchicalFacetRefined:function(e,t){if(!this.isHierarchicalFacet(e))return!1;var r=this.getHierarchicalRefinement(e);return t?-1!==r.indexOf(t):r.length>0},isNumericRefined:function(e,t,r){if(void 0===r&&void 0===t)return Boolean(this.numericRefinements[e]);var n=this.numericRefinements[e]&&void 0!==this.numericRefinements[e][t];if(void 0===r||!n)return n;var s,a,c=u(r),o=void 0!==(s=this.numericRefinements[e][t],a=c,i(s,(function(e){return l(e,a)})));return n&&o},isTagRefined:function(e){return-1!==this.tagRefinements.indexOf(e)},getRefinedDisjunctiveFacets:function(){var e=this,t=s(Object.keys(this.numericRefinements).filter((function(t){return Object.keys(e.numericRefinements[t]).length>0})),this.disjunctiveFacets);return Object.keys(this.disjunctiveFacetsRefinements).filter((function(t){return e.disjunctiveFacetsRefinements[t].length>0})).concat(t).concat(this.getRefinedHierarchicalFacets()).sort()},getRefinedHierarchicalFacets:function(){var e=this;return s(this.hierarchicalFacets.map((function(e){return e.name})),Object.keys(this.hierarchicalFacetsRefinements).filter((function(t){return e.hierarchicalFacetsRefinements[t].length>0}))).sort()},getUnrefinedDisjunctiveFacets:function(){var e=this.getRefinedDisjunctiveFacets();return this.disjunctiveFacets.filter((function(t){return-1===e.indexOf(t)}))},managedParameters:["index","facets","disjunctiveFacets","facetsRefinements","hierarchicalFacets","facetsExcludes","disjunctiveFacetsRefinements","numericRefinements","tagRefinements","hierarchicalFacetsRefinements"],getQueryParams:function(){var e=this.managedParameters,t={},r=this;return Object.keys(this).forEach((function(n){var i=r[n];-1===e.indexOf(n)&&void 0!==i&&(t[n]=i)})),t},setQueryParameter:function(e,t){if(this[e]===t)return this;var r={};return r[e]=t,this.setQueryParameters(r)},setQueryParameters:function(e){if(!e)return this;var t=m.validate(this,e);if(t)throw t;var r=this,n=m._parseNumbers(e),i=Object.keys(this).reduce((function(e,t){return e[t]=r[t],e}),{}),s=Object.keys(n).reduce((function(e,t){var r=void 0!==e[t],i=void 0!==n[t];return r&&!i?o(e,[t]):(i&&(e[t]=n[t]),e)}),i);return new this.constructor(s)},resetPage:function(){return void 0===this.page?this:this.setPage(0)},_getHierarchicalFacetSortBy:function(e){return e.sortBy||["isRefined:desc","name:asc"]},_getHierarchicalFacetSeparator:function(e){return e.separator||" > "},_getHierarchicalRootPath:function(e){return e.rootPath||null},_getHierarchicalShowParentLevel:function(e){return"boolean"!=typeof e.showParentLevel||e.showParentLevel},getHierarchicalFacetByName:function(e){return i(this.hierarchicalFacets,(function(t){return t.name===e}))},getHierarchicalFacetBreadcrumb:function(e){if(!this.isHierarchicalFacet(e))return[];var t=this.getHierarchicalRefinement(e)[0];if(!t)return[];var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e));return t.split(r).map((function(e){return e.trim()}))},toString:function(){return JSON.stringify(this,null,2)}},e.exports=m},6673:(e,t,r)=>{"use strict";e.exports=function(e){return function(t,r){var n=e.hierarchicalFacets[r],u=e.hierarchicalFacetsRefinements[n.name]&&e.hierarchicalFacetsRefinements[n.name][0]||"",h=e._getHierarchicalFacetSeparator(n),f=e._getHierarchicalRootPath(n),l=e._getHierarchicalShowParentLevel(n),m=s(e._getHierarchicalFacetSortBy(n)),d=t.every((function(e){return e.exhaustive})),p=function(e,t,r,n,s){return function(u,h,f){var l=u;if(f>0){var m=0;for(l=u;m<f;){var d=l&&Array.isArray(l.data)?l.data:[];l=i(d,(function(e){return e.isRefined})),m++}}if(l){var p=Object.keys(h.data).map((function(e){return[e,h.data[e]]})).filter((function(e){return function(e,t,r,n,i,s){if(i&&(0!==e.indexOf(i)||i===e))return!1;return!i&&-1===e.indexOf(n)||i&&e.split(n).length-i.split(n).length==1||-1===e.indexOf(n)&&-1===r.indexOf(n)||0===r.indexOf(e)||0===e.indexOf(t+n)&&(s||0===e.indexOf(r))}(e[0],l.path||r,s,t,r,n)}));l.data=a(p.map((function(e){var r=e[0];return function(e,t,r,n,i){var s=t.split(r);return{name:s[s.length-1].trim(),path:t,escapedValue:c(t),count:e,isRefined:n===t||0===n.indexOf(t+r),exhaustive:i,data:null}}(e[1],r,t,o(s),h.exhaustive)})),e[0],e[1])}return u}}(m,h,f,l,u),g=t;return f&&(g=t.slice(f.split(h).length)),g.reduce(p,{name:e.hierarchicalFacets[r].name,count:null,isRefined:!0,path:null,escapedValue:null,exhaustive:d,data:null})}};var n=r(2909),i=r(849),s=r(7577),a=r(8601),c=n.escapeFacetValue,o=n.unescapeFacetValue},7691:(e,t,r)=>{"use strict";var n=r(8965),i=r(9110),s=r(2909),a=r(849),c=r(3917),o=r(7577),u=r(4728),h=r(8601),f=s.escapeFacetValue,l=s.unescapeFacetValue,m=r(6673);function d(e){var t={};return e.forEach((function(e,r){t[e]=r})),t}function p(e,t,r){t&&t[r]&&(e.stats=t[r])}function g(e,t,r){var s=t[0];this._rawResults=t;var o=this;Object.keys(s).forEach((function(e){o[e]=s[e]}));var h=u({persistHierarchicalRootCount:!1},r);Object.keys(h).forEach((function(e){o[e]=h[e]})),this.processingTimeMS=t.reduce((function(e,t){return void 0===t.processingTimeMS?e:e+t.processingTimeMS}),0),this.disjunctiveFacets=[],this.hierarchicalFacets=e.hierarchicalFacets.map((function(){return[]})),this.facets=[];var f=e.getRefinedDisjunctiveFacets(),g=d(e.facets),v=d(e.disjunctiveFacets),y=1,R=s.facets||{};Object.keys(R).forEach((function(t){var r,n,i=R[t],u=(r=e.hierarchicalFacets,n=t,a(r,(function(e){return(e.attributes||[]).indexOf(n)>-1})));if(u){var h=u.attributes.indexOf(t),f=c(e.hierarchicalFacets,(function(e){return e.name===u.name}));o.hierarchicalFacets[f][h]={attribute:t,data:i,exhaustive:s.exhaustiveFacetsCount}}else{var l,m=-1!==e.disjunctiveFacets.indexOf(t),d=-1!==e.facets.indexOf(t);m&&(l=v[t],o.disjunctiveFacets[l]={name:t,data:i,exhaustive:s.exhaustiveFacetsCount},p(o.disjunctiveFacets[l],s.facets_stats,t)),d&&(l=g[t],o.facets[l]={name:t,data:i,exhaustive:s.exhaustiveFacetsCount},p(o.facets[l],s.facets_stats,t))}})),this.hierarchicalFacets=n(this.hierarchicalFacets),f.forEach((function(r){var n=t[y],a=n&&n.facets?n.facets:{},h=e.getHierarchicalFacetByName(r);Object.keys(a).forEach((function(t){var r,f=a[t];if(h){r=c(e.hierarchicalFacets,(function(e){return e.name===h.name}));var m=c(o.hierarchicalFacets[r],(function(e){return e.attribute===t}));if(-1===m)return;o.hierarchicalFacets[r][m].data=u({},o.hierarchicalFacets[r][m].data,f)}else{r=v[t];var d=s.facets&&s.facets[t]||{};o.disjunctiveFacets[r]={name:t,data:i({},f,d),exhaustive:n.exhaustiveFacetsCount},p(o.disjunctiveFacets[r],n.facets_stats,t),e.disjunctiveFacetsRefinements[t]&&e.disjunctiveFacetsRefinements[t].forEach((function(n){!o.disjunctiveFacets[r].data[n]&&e.disjunctiveFacetsRefinements[t].indexOf(l(n))>-1&&(o.disjunctiveFacets[r].data[n]=0)}))}})),y++})),e.getRefinedHierarchicalFacets().forEach((function(r){var n=e.getHierarchicalFacetByName(r),s=e._getHierarchicalFacetSeparator(n),a=e.getHierarchicalRefinement(r);0===a.length||a[0].split(s).length<2||t.slice(y).forEach((function(t){var r=t&&t.facets?t.facets:{};Object.keys(r).forEach((function(t){var u=r[t],h=c(e.hierarchicalFacets,(function(e){return e.name===n.name})),f=c(o.hierarchicalFacets[h],(function(e){return e.attribute===t}));if(-1!==f){var l={};if(a.length>0&&!o.persistHierarchicalRootCount){var m=a[0].split(s)[0];l[m]=o.hierarchicalFacets[h][f].data[m]}o.hierarchicalFacets[h][f].data=i(l,u,o.hierarchicalFacets[h][f].data)}})),y++}))})),Object.keys(e.facetsExcludes).forEach((function(t){var r=e.facetsExcludes[t],n=g[t];o.facets[n]={name:t,data:R[t],exhaustive:s.exhaustiveFacetsCount},r.forEach((function(e){o.facets[n]=o.facets[n]||{name:t},o.facets[n].data=o.facets[n].data||{},o.facets[n].data[e]=0}))})),this.hierarchicalFacets=this.hierarchicalFacets.map(m(e)),this.facets=n(this.facets),this.disjunctiveFacets=n(this.disjunctiveFacets),this._state=e}function v(e,t){function r(e){return e.name===t}if(e._state.isConjunctiveFacet(t)){var n=a(e.facets,r);return n?Object.keys(n.data).map((function(r){var i=f(r);return{name:r,escapedValue:i,count:n.data[r],isRefined:e._state.isFacetRefined(t,i),isExcluded:e._state.isExcludeRefined(t,r)}})):[]}if(e._state.isDisjunctiveFacet(t)){var i=a(e.disjunctiveFacets,r);return i?Object.keys(i.data).map((function(r){var n=f(r);return{name:r,escapedValue:n,count:i.data[r],isRefined:e._state.isDisjunctiveFacetRefined(t,n)}})):[]}if(e._state.isHierarchicalFacet(t)){var s=a(e.hierarchicalFacets,r);if(!s)return s;var c=e._state.getHierarchicalFacetByName(t),o=e._state._getHierarchicalFacetSeparator(c),u=l(e._state.getHierarchicalRefinement(t)[0]||"");0===u.indexOf(c.rootPath)&&(u=u.replace(c.rootPath+o,""));var h=u.split(o);return h.unshift(t),y(s,h,0),s}}function y(e,t,r){e.isRefined=e.name===(t[r]&&t[r].trim()),e.data&&e.data.forEach((function(e){y(e,t,r+1)}))}function R(e,t,r,n){if(n=n||0,Array.isArray(t))return e(t,r[n]);if(!t.data||0===t.data.length)return t;var s=t.data.map((function(t){return R(e,t,r,n+1)})),a=e(s,r[n]);return i({data:a},t)}function F(e,t){var r=a(e,(function(e){return e.name===t}));return r&&r.stats}function b(e,t,r,n,i){var s=a(i,(function(e){return e.name===r})),c=s&&s.data&&s.data[n]?s.data[n]:0,o=s&&s.exhaustive||!1;return{type:t,attributeName:r,name:n,count:c,exhaustive:o}}g.prototype.getFacetByName=function(e){function t(t){return t.name===e}return a(this.facets,t)||a(this.disjunctiveFacets,t)||a(this.hierarchicalFacets,t)},g.DEFAULT_SORT=["isRefined:desc","count:desc","name:asc"],g.prototype.getFacetValues=function(e,t){var r=v(this,e);if(r){var n,s=i({},t,{sortBy:g.DEFAULT_SORT,facetOrdering:!(t&&t.sortBy)}),a=this;if(Array.isArray(r))n=[e];else n=a._state.getHierarchicalFacetByName(r.name).attributes;return R((function(e,t){if(s.facetOrdering){var r=function(e,t){return e.renderingContent&&e.renderingContent.facetOrdering&&e.renderingContent.facetOrdering.values&&e.renderingContent.facetOrdering.values[t]}(a,t);if(r)return function(e,t){var r=[],n=[],i=(t.order||[]).reduce((function(e,t,r){return e[t]=r,e}),{});e.forEach((function(e){var t=e.path||e.name;void 0!==i[t]?r[i[t]]=e:n.push(e)})),r=r.filter((function(e){return e}));var s,a=t.sortRemainingBy;return"hidden"===a?r:(s="alpha"===a?[["path","name"],["asc","asc"]]:[["count"],["desc"]],r.concat(h(n,s[0],s[1])))}(e,r)}if(Array.isArray(s.sortBy)){var n=o(s.sortBy,g.DEFAULT_SORT);return h(e,n[0],n[1])}if("function"==typeof s.sortBy)return function(e,t){return t.sort(e)}(s.sortBy,e);throw new Error("options.sortBy is optional but if defined it must be either an array of string (predicates) or a sorting function")}),r,n)}},g.prototype.getFacetStats=function(e){return this._state.isConjunctiveFacet(e)?F(this.facets,e):this._state.isDisjunctiveFacet(e)?F(this.disjunctiveFacets,e):void 0},g.prototype.getRefinements=function(){var e=this._state,t=this,r=[];return Object.keys(e.facetsRefinements).forEach((function(n){e.facetsRefinements[n].forEach((function(i){r.push(b(e,"facet",n,i,t.facets))}))})),Object.keys(e.facetsExcludes).forEach((function(n){e.facetsExcludes[n].forEach((function(i){r.push(b(e,"exclude",n,i,t.facets))}))})),Object.keys(e.disjunctiveFacetsRefinements).forEach((function(n){e.disjunctiveFacetsRefinements[n].forEach((function(i){r.push(b(e,"disjunctive",n,i,t.disjunctiveFacets))}))})),Object.keys(e.hierarchicalFacetsRefinements).forEach((function(n){e.hierarchicalFacetsRefinements[n].forEach((function(i){r.push(function(e,t,r,n){var i=e.getHierarchicalFacetByName(t),s=e._getHierarchicalFacetSeparator(i),c=r.split(s),o=a(n,(function(e){return e.name===t})),u=c.reduce((function(e,t){var r=e&&a(e.data,(function(e){return e.name===t}));return void 0!==r?r:e}),o),h=u&&u.count||0,f=u&&u.exhaustive||!1,l=u&&u.path||"";return{type:"hierarchical",attributeName:t,name:l,count:h,exhaustive:f}}(e,n,i,t.hierarchicalFacets))}))})),Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t];Object.keys(n).forEach((function(e){n[e].forEach((function(n){r.push({type:"numeric",attributeName:t,name:n,numericValue:n,operator:e})}))}))})),e.tagRefinements.forEach((function(e){r.push({type:"tag",attributeName:"_tags",name:e})})),r},e.exports=g},6571:(e,t,r)=>{"use strict";var n=r(2733),i=r(6732),s=r(2909).escapeFacetValue,a=r(3014),c=r(4728),o=r(317),u=r(1383),h=r(9127),f=r(9228),l=r(3371),m=r(7691),d=r(6938);function p(e,t,r,n){"function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+d+")"),this.setClient(e);var i=r||{};i.index=t,this.state=l.make(i),this.recommendState=new h({params:i.recommendState}),this.lastResults=null,this.lastRecommendResults=null,this._queryId=0,this._recommendQueryId=0,this._lastQueryIdReceived=-1,this._lastRecommendQueryIdReceived=-1,this.derivedHelpers=[],this._currentNbQueries=0,this._currentNbRecommendQueries=0,this._searchResultsOptions=n}function g(e){if(e<0)throw new Error("Page requested below 0.");return this._change({state:this.state.setPage(e),isPageReset:!1}),this}function v(){return this.state.page}a(p,n),p.prototype.search=function(){return this._search({onlyWithDerivedHelpers:!1}),this},p.prototype.searchOnlyWithDerivedHelpers=function(){return this._search({onlyWithDerivedHelpers:!0}),this},p.prototype.recommend=function(){return this._recommend(),this},p.prototype.getQuery=function(){var e=this.state;return f._getHitsSearchParams(e)},p.prototype.searchOnce=function(e,t){var r=e?this.state.setQueryParameters(e):this.state,n=f._getQueries(r.index,r),i=this;if(this._currentNbQueries++,this.emit("searchOnce",{state:r}),!t)return this.client.search(n).then((function(e){return i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),{content:new m(r,e.results),state:r,_originalResponse:e}}),(function(e){throw i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),e}));this.client.search(n).then((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(null,new m(r,e.results),r)})).catch((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(e,null,r)}))},p.prototype.findAnswers=function(e){console.warn("[algoliasearch-helper] answers is no longer supported");var t=this.state,r=this.derivedHelpers[0];if(!r)return Promise.resolve([]);var n=r.getModifiedState(t),i=c({attributesForPrediction:e.attributesForPrediction,nbHits:e.nbHits},{params:u(f._getHitsSearchParams(n),["attributesToSnippet","hitsPerPage","restrictSearchableAttributes","snippetEllipsisText"])}),s="search for answers was called, but this client does not have a function client.initIndex(index).findAnswers";if("function"!=typeof this.client.initIndex)throw new Error(s);var a=this.client.initIndex(n.index);if("function"!=typeof a.findAnswers)throw new Error(s);return a.findAnswers(n.query,e.queryLanguages,i)},p.prototype.searchForFacetValues=function(e,t,r,n){var i="function"==typeof this.client.searchForFacetValues,a="function"==typeof this.client.initIndex;if(!i&&!a&&"function"!=typeof this.client.search)throw new Error("search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues");var c=this.state.setQueryParameters(n||{}),o=c.isDisjunctiveFacet(e),u=f.getSearchForFacetQuery(e,t,r,c);this._currentNbQueries++;var h,l=this;return i?h=this.client.searchForFacetValues([{indexName:c.index,params:u}]):a?h=this.client.initIndex(c.index).searchForFacetValues(u):(delete u.facetName,h=this.client.search([{type:"facet",facet:e,indexName:c.index,params:u}]).then((function(e){return e.results[0]}))),this.emit("searchForFacetValues",{state:c,facet:e,query:t}),h.then((function(t){return l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),(t=Array.isArray(t)?t[0]:t).facetHits.forEach((function(t){t.escapedValue=s(t.value),t.isRefined=o?c.isDisjunctiveFacetRefined(e,t.escapedValue):c.isFacetRefined(e,t.escapedValue)})),t}),(function(e){throw l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),e}))},p.prototype.setQuery=function(e){return this._change({state:this.state.resetPage().setQuery(e),isPageReset:!0}),this},p.prototype.clearRefinements=function(e){return this._change({state:this.state.resetPage().clearRefinements(e),isPageReset:!0}),this},p.prototype.clearTags=function(){return this._change({state:this.state.resetPage().clearTags(),isPageReset:!0}),this},p.prototype.addDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},p.prototype.addDisjunctiveRefine=function(){return this.addDisjunctiveFacetRefinement.apply(this,arguments)},p.prototype.addHierarchicalFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addHierarchicalFacetRefinement(e,t),isPageReset:!0}),this},p.prototype.addNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().addNumericRefinement(e,t,r),isPageReset:!0}),this},p.prototype.addFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addFacetRefinement(e,t),isPageReset:!0}),this},p.prototype.addRefine=function(){return this.addFacetRefinement.apply(this,arguments)},p.prototype.addFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().addExcludeRefinement(e,t),isPageReset:!0}),this},p.prototype.addExclude=function(){return this.addFacetExclusion.apply(this,arguments)},p.prototype.addTag=function(e){return this._change({state:this.state.resetPage().addTagRefinement(e),isPageReset:!0}),this},p.prototype.addFrequentlyBoughtTogether=function(e){return this._recommendChange({state:this.recommendState.addFrequentlyBoughtTogether(e)}),this},p.prototype.addRelatedProducts=function(e){return this._recommendChange({state:this.recommendState.addRelatedProducts(e)}),this},p.prototype.addTrendingItems=function(e){return this._recommendChange({state:this.recommendState.addTrendingItems(e)}),this},p.prototype.addTrendingFacets=function(e){return this._recommendChange({state:this.recommendState.addTrendingFacets(e)}),this},p.prototype.addLookingSimilar=function(e){return this._recommendChange({state:this.recommendState.addLookingSimilar(e)}),this},p.prototype.removeNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().removeNumericRefinement(e,t,r),isPageReset:!0}),this},p.prototype.removeDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},p.prototype.removeDisjunctiveRefine=function(){return this.removeDisjunctiveFacetRefinement.apply(this,arguments)},p.prototype.removeHierarchicalFacetRefinement=function(e){return this._change({state:this.state.resetPage().removeHierarchicalFacetRefinement(e),isPageReset:!0}),this},p.prototype.removeFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeFacetRefinement(e,t),isPageReset:!0}),this},p.prototype.removeRefine=function(){return this.removeFacetRefinement.apply(this,arguments)},p.prototype.removeFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().removeExcludeRefinement(e,t),isPageReset:!0}),this},p.prototype.removeExclude=function(){return this.removeFacetExclusion.apply(this,arguments)},p.prototype.removeTag=function(e){return this._change({state:this.state.resetPage().removeTagRefinement(e),isPageReset:!0}),this},p.prototype.removeFrequentlyBoughtTogether=function(e){return this._recommendChange({state:this.recommendState.removeParams(e)}),this},p.prototype.removeRelatedProducts=function(e){return this._recommendChange({state:this.recommendState.removeParams(e)}),this},p.prototype.removeTrendingItems=function(e){return this._recommendChange({state:this.recommendState.removeParams(e)}),this},p.prototype.removeTrendingFacets=function(e){return this._recommendChange({state:this.recommendState.removeParams(e)}),this},p.prototype.removeLookingSimilar=function(e){return this._recommendChange({state:this.recommendState.removeParams(e)}),this},p.prototype.toggleFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().toggleExcludeFacetRefinement(e,t),isPageReset:!0}),this},p.prototype.toggleExclude=function(){return this.toggleFacetExclusion.apply(this,arguments)},p.prototype.toggleRefinement=function(e,t){return this.toggleFacetRefinement(e,t)},p.prototype.toggleFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().toggleFacetRefinement(e,t),isPageReset:!0}),this},p.prototype.toggleRefine=function(){return this.toggleFacetRefinement.apply(this,arguments)},p.prototype.toggleTag=function(e){return this._change({state:this.state.resetPage().toggleTagRefinement(e),isPageReset:!0}),this},p.prototype.nextPage=function(){var e=this.state.page||0;return this.setPage(e+1)},p.prototype.previousPage=function(){var e=this.state.page||0;return this.setPage(e-1)},p.prototype.setCurrentPage=g,p.prototype.setPage=g,p.prototype.setIndex=function(e){return this._change({state:this.state.resetPage().setIndex(e),isPageReset:!0}),this},p.prototype.setQueryParameter=function(e,t){return this._change({state:this.state.resetPage().setQueryParameter(e,t),isPageReset:!0}),this},p.prototype.setState=function(e){return this._change({state:l.make(e),isPageReset:!1}),this},p.prototype.overrideStateWithoutTriggeringChangeEvent=function(e){return this.state=new l(e),this},p.prototype.hasRefinements=function(e){return!!o(this.state.getNumericRefinements(e))||(this.state.isConjunctiveFacet(e)?this.state.isFacetRefined(e):this.state.isDisjunctiveFacet(e)?this.state.isDisjunctiveFacetRefined(e):!!this.state.isHierarchicalFacet(e)&&this.state.isHierarchicalFacetRefined(e))},p.prototype.isExcluded=function(e,t){return this.state.isExcludeRefined(e,t)},p.prototype.isDisjunctiveRefined=function(e,t){return this.state.isDisjunctiveFacetRefined(e,t)},p.prototype.hasTag=function(e){return this.state.isTagRefined(e)},p.prototype.isTagRefined=function(){return this.hasTagRefinements.apply(this,arguments)},p.prototype.getIndex=function(){return this.state.index},p.prototype.getCurrentPage=v,p.prototype.getPage=v,p.prototype.getTags=function(){return this.state.tagRefinements},p.prototype.getRefinements=function(e){var t=[];if(this.state.isConjunctiveFacet(e))this.state.getConjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"conjunctive"})})),this.state.getExcludeRefinements(e).forEach((function(e){t.push({value:e,type:"exclude"})}));else if(this.state.isDisjunctiveFacet(e)){this.state.getDisjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"disjunctive"})}))}var r=this.state.getNumericRefinements(e);return Object.keys(r).forEach((function(e){var n=r[e];t.push({value:n,operator:e,type:"numeric"})})),t},p.prototype.getNumericRefinement=function(e,t){return this.state.getNumericRefinement(e,t)},p.prototype.getHierarchicalFacetBreadcrumb=function(e){return this.state.getHierarchicalFacetBreadcrumb(e)},p.prototype._search=function(e){var t=this.state,r=[],n=[];e.onlyWithDerivedHelpers||(n=f._getQueries(t.index,t),r.push({state:t,queriesCount:n.length,helper:this}),this.emit("search",{state:t,results:this.lastResults}));var i=this.derivedHelpers.map((function(e){var n=e.getModifiedState(t),i=n.index?f._getQueries(n.index,n):[];return r.push({state:n,queriesCount:i.length,helper:e}),e.emit("search",{state:n,results:e.lastResults}),i})),s=Array.prototype.concat.apply(n,i),a=this._queryId++;if(this._currentNbQueries++,!s.length)return Promise.resolve({results:[]}).then(this._dispatchAlgoliaResponse.bind(this,r,a));try{this.client.search(s).then(this._dispatchAlgoliaResponse.bind(this,r,a)).catch(this._dispatchAlgoliaError.bind(this,a))}catch(c){this.emit("error",{error:c})}},p.prototype._recommend=function(){var e=this.state,t=this.recommendState,r=this.getIndex(),n=[{state:t,index:r,helper:this}];this.emit("fetch",{recommend:{state:t,results:this.lastRecommendResults}});var i=this.derivedHelpers.map((function(t){var r=t.getModifiedState(e).index;if(!r)return[];var i=t.getModifiedRecommendState(new h);return n.push({state:i,index:r,helper:t}),t.emit("fetch",{recommend:{state:i,results:t.lastRecommendResults}}),i._buildQueries(r)})),s=Array.prototype.concat.apply(this.recommendState._buildQueries(r),i);if(0!==s.length)if(s.length>0&&void 0===this.client.getRecommendations)console.warn("Please update algoliasearch/lite to the latest version in order to use recommendations widgets.");else{var a=this._recommendQueryId++;this._currentNbRecommendQueries++;try{this.client.getRecommendations(s).then(this._dispatchRecommendResponse.bind(this,a,n)).catch(this._dispatchRecommendError.bind(this,a))}catch(c){this.emit("error",{error:c})}}},p.prototype._dispatchAlgoliaResponse=function(e,t,r){var n=this;if(!(t<this._lastQueryIdReceived)){this._currentNbQueries-=t-this._lastQueryIdReceived,this._lastQueryIdReceived=t,0===this._currentNbQueries&&this.emit("searchQueueEmpty");var i=r.results.slice();e.forEach((function(e){var t=e.state,r=e.queriesCount,s=e.helper,a=i.splice(0,r);t.index?(s.lastResults=new m(t,a,n._searchResultsOptions),s.emit("result",{results:s.lastResults,state:t})):s.emit("result",{results:null,state:t})}))}},p.prototype._dispatchRecommendResponse=function(e,t,r){if(!(e<this._lastRecommendQueryIdReceived)){this._currentNbRecommendQueries-=e-this._lastRecommendQueryIdReceived,this._lastRecommendQueryIdReceived=e,0===this._currentNbRecommendQueries&&this.emit("recommendQueueEmpty");var n=r.results.slice();t.forEach((function(e){var t=e.state,r=e.helper;e.index?(r.lastRecommendResults=n,r.emit("recommend:result",{recommend:{results:r.lastRecommendResults,state:t}})):r.emit("recommend:result",{results:null,state:t})}))}},p.prototype._dispatchAlgoliaError=function(e,t){e<this._lastQueryIdReceived||(this._currentNbQueries-=e-this._lastQueryIdReceived,this._lastQueryIdReceived=e,this.emit("error",{error:t}),0===this._currentNbQueries&&this.emit("searchQueueEmpty"))},p.prototype._dispatchRecommendError=function(e,t){e<this._lastRecommendQueryIdReceived||(this._currentNbRecommendQueries-=e-this._lastRecommendQueryIdReceived,this._lastRecommendQueryIdReceived=e,this.emit("error",{error:t}),0===this._currentNbRecommendQueries&&this.emit("recommendQueueEmpty"))},p.prototype.containsRefinement=function(e,t,r,n){return e||0!==t.length||0!==r.length||0!==n.length},p.prototype._hasDisjunctiveRefinements=function(e){return this.state.disjunctiveRefinements[e]&&this.state.disjunctiveRefinements[e].length>0},p.prototype._change=function(e){var t=e.state,r=e.isPageReset;t!==this.state&&(this.state=t,this.emit("change",{state:this.state,results:this.lastResults,isPageReset:r}))},p.prototype._recommendChange=function(e){var t=e.state;t!==this.recommendState&&(this.recommendState=t,this.emit("recommend:change",{search:{results:this.lastResults,state:this.state},recommend:{results:this.lastRecommendResults,state:this.recommendState}}))},p.prototype.clearCache=function(){return this.client.clearCache&&this.client.clearCache(),this},p.prototype.setClient=function(e){return this.client===e||("function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+d+")"),this.client=e),this},p.prototype.getClient=function(){return this.client},p.prototype.derive=function(e,t){var r=new i(this,e,t);return this.derivedHelpers.push(r),r},p.prototype.detachDerivedHelper=function(e){var t=this.derivedHelpers.indexOf(e);if(-1===t)throw new Error("Derived helper already detached");this.derivedHelpers.splice(t,1)},p.prototype.hasPendingRequests=function(){return this._currentNbQueries>0},e.exports=p},8965:e=>{"use strict";e.exports=function(e){return Array.isArray(e)?e.filter(Boolean):[]}},9110:e=>{"use strict";e.exports=function(){return Array.prototype.slice.call(arguments).reduceRight((function(e,t){return Object.keys(Object(t)).forEach((function(r){void 0!==t[r]&&(void 0!==e[r]&&delete e[r],e[r]=t[r])})),e}),{})}},2909:e=>{"use strict";e.exports={escapeFacetValue:function(e){return"string"!=typeof e?e:String(e).replace(/^-/,"\\-")},unescapeFacetValue:function(e){return"string"!=typeof e?e:e.replace(/^\\-/,"-")}}},849:e=>{"use strict";e.exports=function(e,t){if(Array.isArray(e))for(var r=0;r<e.length;r++)if(t(e[r]))return e[r]}},3917:e=>{"use strict";e.exports=function(e,t){if(!Array.isArray(e))return-1;for(var r=0;r<e.length;r++)if(t(e[r]))return r;return-1}},7577:(e,t,r)=>{"use strict";var n=r(849);e.exports=function(e,t){var r=(t||[]).map((function(e){return e.split(":")}));return e.reduce((function(e,t){var i=t.split(":"),s=n(r,(function(e){return e[0]===i[0]}));return i.length>1||!s?(e[0].push(i[0]),e[1].push(i[1]),e):(e[0].push(s[0]),e[1].push(s[1]),e)}),[[],[]])}},3014:e=>{"use strict";e.exports=function(e,t){e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}},4843:e=>{"use strict";e.exports=function(e,t){return e.filter((function(r,n){return t.indexOf(r)>-1&&e.indexOf(r)===n}))}},4728:e=>{"use strict";function t(e){return"function"==typeof e||Array.isArray(e)||"[object Object]"===Object.prototype.toString.call(e)}function r(e,n){if(e===n)return e;for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)&&"__proto__"!==i&&"constructor"!==i){var s=n[i],a=e[i];void 0!==a&&void 0===s||(t(a)&&t(s)?e[i]=r(a,s):e[i]="object"==typeof(c=s)&&null!==c?r(Array.isArray(c)?[]:{},c):c)}var c;return e}e.exports=function(e){t(e)||(e={});for(var n=1,i=arguments.length;n<i;n++){var s=arguments[n];t(s)&&r(e,s)}return e}},317:e=>{"use strict";e.exports=function(e){return e&&Object.keys(e).length>0}},1383:e=>{"use strict";e.exports=function(e,t){if(null===e)return{};var r,n,i={},s=Object.keys(e);for(n=0;n<s.length;n++)r=s[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}},8601:e=>{"use strict";function t(e,t){if(e!==t){var r=void 0!==e,n=null===e,i=void 0!==t,s=null===t;if(!s&&e>t||n&&i||!r)return 1;if(!n&&e<t||s&&r||!i)return-1}return 0}e.exports=function(e,r,n){if(!Array.isArray(e))return[];Array.isArray(n)||(n=[]);var i=e.map((function(e,t){return{criteria:r.map((function(t){return e[t]})),index:t,value:e}}));return i.sort((function(e,r){for(var i=-1;++i<e.criteria.length;){var s=t(e.criteria[i],r.criteria[i]);if(s)return i>=n.length?s:"desc"===n[i]?-s:s}return e.index-r.index})),i.map((function(e){return e.value}))}},7507:e=>{"use strict";e.exports=function e(t){if("number"==typeof t)return t;if("string"==typeof t)return parseFloat(t);if(Array.isArray(t))return t.map(e);throw new Error("The value should be a number, a parsable string or an array of those.")}},9228:(e,t,r)=>{"use strict";var n=r(4728);function i(e){return Object.keys(e).sort().reduce((function(t,r){return t[r]=e[r],t}),{})}var s={_getQueries:function(e,t){var r=[];return r.push({indexName:e,params:s._getHitsSearchParams(t)}),t.getRefinedDisjunctiveFacets().forEach((function(n){r.push({indexName:e,params:s._getDisjunctiveFacetSearchParams(t,n)})})),t.getRefinedHierarchicalFacets().forEach((function(n){var i=t.getHierarchicalFacetByName(n),a=t.getHierarchicalRefinement(n),c=t._getHierarchicalFacetSeparator(i);if(a.length>0&&a[0].split(c).length>1){var o=a[0].split(c).slice(0,-1).reduce((function(e,t,r){return e.concat({attribute:i.attributes[r],value:0===r?t:[e[e.length-1].value,t].join(c)})}),[]);o.forEach((function(n,a){var c=s._getDisjunctiveFacetSearchParams(t,n.attribute,0===a);function u(e){return i.attributes.some((function(t){return t===e.split(":")[0]}))}var h=(c.facetFilters||[]).reduce((function(e,t){if(Array.isArray(t)){var r=t.filter((function(e){return!u(e)}));r.length>0&&e.push(r)}return"string"!=typeof t||u(t)||e.push(t),e}),[]),f=o[a-1];c.facetFilters=a>0?h.concat(f.attribute+":"+f.value):h.length>0?h:void 0,r.push({indexName:e,params:c})}))}})),r},_getHitsSearchParams:function(e){var t=e.facets.concat(e.disjunctiveFacets).concat(s._getHitsHierarchicalFacetsAttributes(e)).sort(),r=s._getFacetFilters(e),a=s._getNumericFilters(e),c=s._getTagFilters(e),o={facets:t.indexOf("*")>-1?["*"]:t,tagFilters:c};return r.length>0&&(o.facetFilters=r),a.length>0&&(o.numericFilters=a),i(n({},e.getQueryParams(),o))},_getDisjunctiveFacetSearchParams:function(e,t,r){var a=s._getFacetFilters(e,t,r),c=s._getNumericFilters(e,t),o=s._getTagFilters(e),u={hitsPerPage:0,page:0,analytics:!1,clickAnalytics:!1};o.length>0&&(u.tagFilters=o);var h=e.getHierarchicalFacetByName(t);return u.facets=h?s._getDisjunctiveHierarchicalFacetAttribute(e,h,r):t,c.length>0&&(u.numericFilters=c),a.length>0&&(u.facetFilters=a),i(n({},e.getQueryParams(),u))},_getNumericFilters:function(e,t){if(e.numericFilters)return e.numericFilters;var r=[];return Object.keys(e.numericRefinements).forEach((function(n){var i=e.numericRefinements[n]||{};Object.keys(i).forEach((function(e){var s=i[e]||[];t!==n&&s.forEach((function(t){if(Array.isArray(t)){var i=t.map((function(t){return n+e+t}));r.push(i)}else r.push(n+e+t)}))}))})),r},_getTagFilters:function(e){return e.tagFilters?e.tagFilters:e.tagRefinements.join(",")},_getFacetFilters:function(e,t,r){var n=[],i=e.facetsRefinements||{};Object.keys(i).sort().forEach((function(e){(i[e]||[]).slice().sort().forEach((function(t){n.push(e+":"+t)}))}));var s=e.facetsExcludes||{};Object.keys(s).sort().forEach((function(e){(s[e]||[]).sort().forEach((function(t){n.push(e+":-"+t)}))}));var a=e.disjunctiveFacetsRefinements||{};Object.keys(a).sort().forEach((function(e){var r=a[e]||[];if(e!==t&&r&&0!==r.length){var i=[];r.slice().sort().forEach((function(t){i.push(e+":"+t)})),n.push(i)}}));var c=e.hierarchicalFacetsRefinements||{};return Object.keys(c).sort().forEach((function(i){var s=(c[i]||[])[0];if(void 0!==s){var a,o,u=e.getHierarchicalFacetByName(i),h=e._getHierarchicalFacetSeparator(u),f=e._getHierarchicalRootPath(u);if(t===i){if(-1===s.indexOf(h)||!f&&!0===r||f&&f.split(h).length===s.split(h).length)return;f?(o=f.split(h).length-1,s=f):(o=s.split(h).length-2,s=s.slice(0,s.lastIndexOf(h))),a=u.attributes[o]}else o=s.split(h).length-1,a=u.attributes[o];a&&n.push([a+":"+s])}})),n},_getHitsHierarchicalFacetsAttributes:function(e){return e.hierarchicalFacets.reduce((function(t,r){var n=e.getHierarchicalRefinement(r.name)[0];if(!n)return t.push(r.attributes[0]),t;var i=e._getHierarchicalFacetSeparator(r),s=n.split(i).length,a=r.attributes.slice(0,s+1);return t.concat(a)}),[])},_getDisjunctiveHierarchicalFacetAttribute:function(e,t,r){var n=e._getHierarchicalFacetSeparator(t);if(!0===r){var i=e._getHierarchicalRootPath(t),s=0;return i&&(s=i.split(n).length),[t.attributes[s]]}var a=(e.getHierarchicalRefinement(t.name)[0]||"").split(n).length-1;return t.attributes.slice(0,a+1)},getSearchForFacetQuery:function(e,t,r,a){var c=a.isDisjunctiveFacet(e)?a.clearRefinements(e):a,o={facetQuery:t,facetName:e};return"number"==typeof r&&(o.maxFacetHits=r),i(n({},s._getHitsSearchParams(c),o))}};e.exports=s},2208:e=>{"use strict";e.exports=function(e){return null!==e&&/^[a-zA-Z0-9_-]{1,64}$/.test(e)}},6938:e=>{"use strict";e.exports="3.19.0"},3643:function(e){e.exports=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n<arguments.length;n++){var i=null!=arguments[n]?arguments[n]:{};n%2?t(Object(i),!0).forEach((function(t){e(r,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(i)):t(Object(i)).forEach((function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(i,e))}))}return r}function n(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},s=Object.keys(e);for(n=0;n<s.length;n++)r=s[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n<s.length;n++)r=s[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],n=!0,i=!1,s=void 0;try{for(var a,c=e[Symbol.iterator]();!(n=(a=c.next()).done)&&(r.push(a.value),!t||r.length!==t);n=!0);}catch(e){i=!0,s=e}finally{try{n||null==c.return||c.return()}finally{if(i)throw s}}return r}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function s(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t<e.length;t++)r[t]=e[t];return r}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function a(e){var t,r="algoliasearch-client-js-".concat(e.key),n=function(){return void 0===t&&(t=e.localStorage||window.localStorage),t},s=function(){return JSON.parse(n().getItem(r)||"{}")},a=function(e){n().setItem(r,JSON.stringify(e))},c=function(){var t=e.timeToLive?1e3*e.timeToLive:null,r=s(),n=Object.fromEntries(Object.entries(r).filter((function(e){return void 0!==i(e,2)[1].timestamp})));if(a(n),t){var c=Object.fromEntries(Object.entries(n).filter((function(e){var r=i(e,2)[1],n=(new Date).getTime();return!(r.timestamp+t<n)})));a(c)}};return{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){c();var t=JSON.stringify(e);return s()[t]})).then((function(e){return Promise.all([e?e.value:t(),void 0!==e])})).then((function(e){var t=i(e,2),n=t[0],s=t[1];return Promise.all([n,s||r.miss(n)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var i=s();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:t},n().setItem(r,JSON.stringify(i)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=s();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function c(e){var t=s(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return t().then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,i).catch((function(){return c({caches:t}).get(e,n,i)}))},set:function(e,n){return r.set(e,n).catch((function(){return c({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return c({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return c({caches:t}).clear()}))}}}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},s=JSON.stringify(r);if(s in t)return Promise.resolve(e.serializable?JSON.parse(t[s]):t[s]);var a=n(),c=i&&i.miss||function(){return Promise.resolve()};return a.then((function(e){return c(e)})).then((function(){return a}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function u(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function h(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n<t;n++)r[n-1]=arguments[n];var i=0;return e.replace(/%s/g,(function(){return encodeURIComponent(r[i++])}))}var l={WithinQueryParameters:0,WithinHeaders:1};function m(e,t){var r=e||{},n=r.data||{};return Object.keys(r).forEach((function(e){-1===["timeout","headers","queryParameters","data","cacheable"].indexOf(e)&&(n[e]=r[e])})),{data:Object.entries(n).length>0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var d={Read:1,Write:2,Any:3},p=1,g=2,v=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:p;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function R(e){return"string"==typeof e?{protocol:"https",url:e,accept:d.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||d.Any}}var F="GET",b="POST";function j(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===p||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===v&&Date.now()-e.lastUpdate<=12e4}(e)})),i=[].concat(s(r),s(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:i.length>0?i.map((function(e){return R(e)})):t}}))}function P(e,t,n,i){var a=[],c=function(e,t){if(e.method!==F&&(void 0!==e.data||void 0!==t.data)){var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}}(n,i),o=function(e,t){var n=r(r({},e.headers),t.headers),i={};return Object.keys(n).forEach((function(e){var t=n[e];i[e.toLowerCase()]=t})),i}(e,i),u=n.method,h=n.method!==F?{}:r(r({},n.data),i.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),h),i.queryParameters),l=0,m=function t(r,s){var h=r.pop();if(void 0===h)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:O(a)};var m={data:c,headers:o,method:u,url:x(h,n.path,f),connectTimeout:s(l,e.timeouts.connect),responseTimeout:s(l,i.timeout)},d=function(e){var t={request:m,response:e,host:h,triesLeft:r.length};return a.push(t),t},p={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var i=d(n);return n.isTimedOut&&l++,Promise.all([e.logger.info("Retryable failure",w(i)),e.hostsCache.set(h,y(h,n.isTimedOut?v:g))]).then((function(){return t(r,s)}))},onFail:function(e){throw d(e),function(e,t){var r=e.content,n=e.status,i=r;try{i=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(i,n,t)}(e,O(a))}};return e.requester.send(m).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&!~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,p)}))};return j(e.hostsCache,t).then((function(e){return m(s(e.statelessHosts).reverse(),e.getTimeout)}))}function _(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function x(e,t,r){var n=E(r),i="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(i+="?".concat(n)),i}function E(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function O(e){return e.map((function(e){return w(e)}))}function w(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var S=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===l.WithinHeaders?n:{}},queryParameters:function(){return e===l.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:l.WithinHeaders,t,e.apiKey),s=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,s=e.requestsCache,a=e.responsesCache,c=e.timeouts,o=e.userAgent,u=e.hosts,h=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:s,responsesCache:a,timeouts:c,userAgent:o,headers:e.headers,queryParameters:h,hosts:u.map((function(e){return R(e)})),read:function(e,t){var r=m(t,f.timeouts.read),n=function(){return P(f,f.hosts.filter((function(e){return!!(e.accept&d.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var s={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(s,(function(){return f.requestsCache.get(s,(function(){return f.requestsCache.set(s,n()).then((function(e){return Promise.all([f.requestsCache.delete(s),e])}),(function(e){return Promise.all([f.requestsCache.delete(s),Promise.reject(e)])})).then((function(e){var t=i(e,2);return t[0],t[1]}))}))}),{miss:function(e){return f.responsesCache.set(s,e)}})},write:function(e,t){return P(f,f.hosts.filter((function(e){return!!(e.accept&d.Write)})),e,m(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:d.Read},{url:"".concat(t,".algolia.net"),accept:d.Write}].concat(u([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return h({transporter:s,appId:t,addAlgoliaAgent:function(e,t){s.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([s.requestsCache.clear(),s.responsesCache.clear()]).then((function(){}))}},e.methods)},A=function(e){return function(t,r){return t.method===F?e.transporter.read(t,r):e.transporter.write(t,r)}},N=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return h({transporter:e.transporter,appId:e.appId,indexName:t},r.methods)}},T=function(e){return function(t,n){var i=t.map((function(e){return r(r({},e),{},{params:E(e.params||{})})}));return e.transporter.read({method:b,path:"1/indexes/*/queries",data:{requests:i},cacheable:!0},n)}},H=function(e){return function(t,i){return Promise.all(t.map((function(t){var s=t.params,a=s.facetName,c=s.facetQuery,o=n(s,["facetName","facetQuery"]);return N(e)(t.indexName,{methods:{searchForFacetValues:I}}).searchForFacetValues(a,c,r(r({},i),o))})))}},Q=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},C=function(e){return function(t,r){return e.transporter.read({method:b,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},I=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},k=1,D=2,q=3,L=function(e){return function(t,n){var i=t.map((function(e){return r(r({},e),{},{threshold:e.threshold||0})}));return e.transporter.read({method:b,path:"1/indexes/*/recommendations",data:{requests:i},cacheable:!0},n)}};function V(e,t,n){var i,s={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,i=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},s=i(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(s),n=i(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(s),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(s),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(i=q,{debug:function(e,t){return k>=i&&console.debug(e,t),Promise.resolve()},info:function(e,t){return D>=i&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:o(),requestsCache:o({serializable:!1}),hostsCache:c({caches:[a({key:"".concat("4.23.3","-").concat(e)}),o()]}),userAgent:_("4.23.3").add({segment:"Browser",version:"lite"}),authMode:l.WithinQueryParameters};return S(r(r(r({},s),n),{},{methods:{search:T,searchForFacetValues:H,multipleQueries:T,multipleSearchForFacetValues:H,customRequest:A,initIndex:function(e){return function(t){return N(e)(t,{methods:{search:C,searchForFacetValues:I,findAnswers:Q}})}},getRecommendations:L}}))}return V.version="4.23.3",V}()},9057:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>T});var n=r(6540),i=r(4164),s=r(4103),a=r.n(s),c=r(3643),o=r.n(c),u=r(8193),h=r(5260),f=r(8774),l=r(4070),m=r(4586);const d=["zero","one","two","few","many","other"];function p(e){return d.filter((t=>e.includes(t)))}const g={locale:"en",pluralForms:p(["one","other"]),select:e=>1===e?"one":"other"};function v(){const{i18n:{currentLocale:e}}=(0,m.A)();return(0,n.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:p(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),g}}),[e])}function y(){const e=v();return{selectMessage:(t,r)=>function(e,t,r){const n=e.split("|");if(1===n.length)return n[0];n.length>r.pluralForms.length&&console.error(`For locale=${r.locale}, a maximum of ${r.pluralForms.length} plural forms are expected (${r.pluralForms.join(",")}), but the message contains ${n.length}: ${e}`);const i=r.select(t),s=r.pluralForms.indexOf(i);return n[Math.min(s,n.length-1)]}(r,t,e)}}var R=r(4255),F=r(9532),b=r(9024),j=r(481),P=r(1312),_=r(8126),x=r(1062),E=r(9201),O=r(1107);const w={searchQueryInput:"searchQueryInput_u2C7",searchVersionInput:"searchVersionInput_m0Ui",searchResultsColumn:"searchResultsColumn_JPFH",algoliaLogo:"algoliaLogo_rT1R",algoliaLogoPathFill:"algoliaLogoPathFill_WdUC",searchResultItem:"searchResultItem_Tv2o",searchResultItemHeading:"searchResultItemHeading_KbCB",searchResultItemPath:"searchResultItemPath_lhe1",searchResultItemSummary:"searchResultItemSummary_AEaO",searchQueryColumn:"searchQueryColumn_RTkw",searchVersionColumn:"searchVersionColumn_ypXd",searchLogoColumn:"searchLogoColumn_rJIA",loadingSpinner:"loadingSpinner_XVxU","loading-spin":"loading-spin_vzvp",loader:"loader_vvXV"};var S=r(4848);function A(e){let{docsSearchVersionsHelpers:t}=e;const r=Object.entries(t.allDocsData).filter((e=>{let[,t]=e;return t.versions.length>1}));return(0,S.jsx)("div",{className:(0,i.A)("col","col--3","padding-left--none",w.searchVersionColumn),children:r.map((e=>{let[n,i]=e;const s=r.length>1?`${n}: `:"";return(0,S.jsx)("select",{onChange:e=>t.setSearchVersion(n,e.target.value),defaultValue:t.searchVersions[n],className:w.searchVersionInput,children:i.versions.map(((e,t)=>(0,S.jsx)("option",{label:`${s}${e.label}`,value:e.name},t)))},n)}))})}function N(){const{i18n:{currentLocale:e}}=(0,m.A)(),{algolia:{appId:t,apiKey:r,indexName:s}}=(0,_.c)(),c=(0,x.C)(),d=function(){const{selectMessage:e}=y();return t=>e(t,(0,P.T)({id:"theme.SearchPage.documentsFound.plurals",description:'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One document found|{count} documents found"},{count:t}))}(),p=function(){const e=(0,l.Gy)(),[t,r]=(0,n.useState)((()=>Object.entries(e).reduce(((e,t)=>{let[r,n]=t;return{...e,[r]:n.versions[0].name}}),{}))),i=Object.values(e).some((e=>e.versions.length>1));return{allDocsData:e,versioningEnabled:i,searchVersions:t,setSearchVersion:(e,t)=>r((r=>({...r,[e]:t})))}}(),[g,v]=(0,R.b)(),b={items:[],query:null,totalResults:null,totalPages:null,lastPage:null,hasMore:null,loading:null},[N,T]=(0,n.useReducer)(((e,t)=>{switch(t.type){case"reset":return b;case"loading":return{...e,loading:!0};case"update":return g!==t.value.query?e:{...t.value,items:0===t.value.lastPage?t.value.items:e.items.concat(t.value.items)};case"advance":{const t=e.totalPages>e.lastPage+1;return{...e,lastPage:t?e.lastPage+1:e.lastPage,hasMore:t}}default:return e}}),b),H=o()(t,r),Q=a()(H,s,{hitsPerPage:15,advancedSyntax:!0,disjunctiveFacets:["language","docusaurus_tag"]});Q.on("result",(e=>{let{results:{query:t,hits:r,page:n,nbHits:i,nbPages:s}}=e;if(""===t||!Array.isArray(r))return void T({type:"reset"});const a=e=>e.replace(/algolia-docsearch-suggestion--highlight/g,"search-result-match"),o=r.map((e=>{let{url:t,_highlightResult:{hierarchy:r},_snippetResult:n={}}=e;const i=Object.keys(r).map((e=>a(r[e].value)));return{title:i.pop(),url:c(t),summary:n.content?`${a(n.content.value)}...`:"",breadcrumbs:i}}));T({type:"update",value:{items:o,query:t,totalResults:i,totalPages:s,lastPage:n,hasMore:s>n+1,loading:!1}})}));const[C,I]=(0,n.useState)(null),k=(0,n.useRef)(0),D=(0,n.useRef)(u.A.canUseIntersectionObserver&&new IntersectionObserver((e=>{const{isIntersecting:t,boundingClientRect:{y:r}}=e[0];t&&k.current>r&&T({type:"advance"}),k.current=r}),{threshold:1})),q=()=>g?(0,P.T)({id:"theme.SearchPage.existingResultsTitle",message:'Search results for "{query}"',description:"The search page title for non-empty query"},{query:g}):(0,P.T)({id:"theme.SearchPage.emptyResultsTitle",message:"Search the documentation",description:"The search page title for empty query"}),L=(0,F._q)((function(t){void 0===t&&(t=0),Q.addDisjunctiveFacetRefinement("docusaurus_tag","default"),Q.addDisjunctiveFacetRefinement("language",e),Object.entries(p.searchVersions).forEach((e=>{let[t,r]=e;Q.addDisjunctiveFacetRefinement("docusaurus_tag",`docs-${t}-${r}`)})),Q.setQuery(g).setPage(t).search()}));return(0,n.useEffect)((()=>{if(!C)return;const e=D.current;return e?(e.observe(C),()=>e.unobserve(C)):()=>!0}),[C]),(0,n.useEffect)((()=>{T({type:"reset"}),g&&(T({type:"loading"}),setTimeout((()=>{L()}),300))}),[g,p.searchVersions,L]),(0,n.useEffect)((()=>{N.lastPage&&0!==N.lastPage&&L(N.lastPage)}),[L,N.lastPage]),(0,S.jsxs)(E.A,{children:[(0,S.jsxs)(h.A,{children:[(0,S.jsx)("title",{children:(0,j.s)(q())}),(0,S.jsx)("meta",{property:"robots",content:"noindex, follow"})]}),(0,S.jsxs)("div",{className:"container margin-vert--lg",children:[(0,S.jsx)(O.A,{as:"h1",children:q()}),(0,S.jsxs)("form",{className:"row",onSubmit:e=>e.preventDefault(),children:[(0,S.jsx)("div",{className:(0,i.A)("col",w.searchQueryColumn,{"col--9":p.versioningEnabled,"col--12":!p.versioningEnabled}),children:(0,S.jsx)("input",{type:"search",name:"q",className:w.searchQueryInput,placeholder:(0,P.T)({id:"theme.SearchPage.inputPlaceholder",message:"Type your search here",description:"The placeholder for search page input"}),"aria-label":(0,P.T)({id:"theme.SearchPage.inputLabel",message:"Search",description:"The ARIA label for search page input"}),onChange:e=>v(e.target.value),value:g,autoComplete:"off",autoFocus:!0})}),p.versioningEnabled&&(0,S.jsx)(A,{docsSearchVersionsHelpers:p})]}),(0,S.jsxs)("div",{className:"row",children:[(0,S.jsx)("div",{className:(0,i.A)("col","col--8",w.searchResultsColumn),children:!!N.totalResults&&d(N.totalResults)}),(0,S.jsx)("div",{className:(0,i.A)("col","col--4","text--right",w.searchLogoColumn),children:(0,S.jsx)(f.A,{to:"https://www.algolia.com/","aria-label":(0,P.T)({id:"theme.SearchPage.algoliaLabel",message:"Search by Algolia",description:"The ARIA label for Algolia mention"}),children:(0,S.jsx)("svg",{viewBox:"0 0 168 24",className:w.algoliaLogo,children:(0,S.jsxs)("g",{fill:"none",children:[(0,S.jsx)("path",{className:w.algoliaLogoPathFill,d:"M120.925 18.804c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17zM6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z"}),(0,S.jsx)("path",{fill:"#5468FF",d:"M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938z"}),(0,S.jsx)("path",{fill:"white",d:"M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36"})]})})})})]}),N.items.length>0?(0,S.jsx)("main",{children:N.items.map(((e,t)=>{let{title:r,url:n,summary:s,breadcrumbs:a}=e;return(0,S.jsxs)("article",{className:w.searchResultItem,children:[(0,S.jsx)(O.A,{as:"h2",className:w.searchResultItemHeading,children:(0,S.jsx)(f.A,{to:n,dangerouslySetInnerHTML:{__html:r}})}),a.length>0&&(0,S.jsx)("nav",{"aria-label":"breadcrumbs",children:(0,S.jsx)("ul",{className:(0,i.A)("breadcrumbs",w.searchResultItemPath),children:a.map(((e,t)=>(0,S.jsx)("li",{className:"breadcrumbs__item",dangerouslySetInnerHTML:{__html:e}},t)))})}),s&&(0,S.jsx)("p",{className:w.searchResultItemSummary,dangerouslySetInnerHTML:{__html:s}})]},t)}))}):[g&&!N.loading&&(0,S.jsx)("p",{children:(0,S.jsx)(P.A,{id:"theme.SearchPage.noResultsText",description:"The paragraph for empty search result",children:"No results were found"})},"no-results"),!!N.loading&&(0,S.jsx)("div",{className:w.loadingSpinner},"spinner")],N.hasMore&&(0,S.jsx)("div",{className:w.loader,ref:I,children:(0,S.jsx)(P.A,{id:"theme.SearchPage.fetchingNewResults",description:"The paragraph for fetching new search results",children:"Fetching new results..."})})]})]})}function T(){return(0,S.jsx)(b.e3,{className:"search-page-wrapper",children:(0,S.jsx)(N,{})})}}}]); \ No newline at end of file diff --git a/assets/js/1a4e3797.0583fddb.js.LICENSE.txt b/assets/js/1a4e3797.0583fddb.js.LICENSE.txt new file mode 100644 index 000000000..92dc1757f --- /dev/null +++ b/assets/js/1a4e3797.0583fddb.js.LICENSE.txt @@ -0,0 +1 @@ +/*! algoliasearch-lite.umd.js | 4.23.3 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */ diff --git a/assets/js/1a4e3797.ca05490f.js b/assets/js/1a4e3797.ca05490f.js deleted file mode 100644 index 8b442067d..000000000 --- a/assets/js/1a4e3797.ca05490f.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see 1a4e3797.ca05490f.js.LICENSE.txt */ -(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[920],{7331:e=>{function t(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=t,t.prototype._events=void 0,t.prototype._maxListeners=void 0,t.defaultMaxListeners=10,t.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},t.prototype.emit=function(e){var t,a,s,c,u,o;if(this._events||(this._events={}),"error"===e&&(!this._events.error||n(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var h=new Error('Uncaught, unspecified "error" event. ('+t+")");throw h.context=t,h}if(i(a=this._events[e]))return!1;if(r(a))switch(arguments.length){case 1:a.call(this);break;case 2:a.call(this,arguments[1]);break;case 3:a.call(this,arguments[1],arguments[2]);break;default:c=Array.prototype.slice.call(arguments,1),a.apply(this,c)}else if(n(a))for(c=Array.prototype.slice.call(arguments,1),s=(o=a.slice()).length,u=0;u<s;u++)o[u].apply(this,c);return!0},t.prototype.addListener=function(e,a){var s;if(!r(a))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,r(a.listener)?a.listener:a),this._events[e]?n(this._events[e])?this._events[e].push(a):this._events[e]=[this._events[e],a]:this._events[e]=a,n(this._events[e])&&!this._events[e].warned&&(s=i(this._maxListeners)?t.defaultMaxListeners:this._maxListeners)&&s>0&&this._events[e].length>s&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},t.prototype.on=t.prototype.addListener,t.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function i(){this.removeListener(e,i),n||(n=!0,t.apply(this,arguments))}return i.listener=t,this.on(e,i),this},t.prototype.removeListener=function(e,t){var i,a,s,c;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(s=(i=this._events[e]).length,a=-1,i===t||r(i.listener)&&i.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(n(i)){for(c=s;c-- >0;)if(i[c]===t||i[c].listener&&i[c].listener===t){a=c;break}if(a<0)return this;1===i.length?(i.length=0,delete this._events[e]):i.splice(a,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},t.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},t.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},t.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},t.listenerCount=function(e,t){return e.listenerCount(t)}},8131:(e,t,r)=>{"use strict";var n=r(9374),i=r(7775),a=r(3076);function s(e,t,r){return new n(e,t,r)}s.version=r(4336),s.AlgoliaSearchHelper=n,s.SearchParameters=i,s.SearchResults=a,e.exports=s},8078:(e,t,r)=>{"use strict";var n=r(7331);function i(e,t){this.main=e,this.fn=t,this.lastResults=null}r(4853)(i,n),i.prototype.detach=function(){this.removeAllListeners(),this.main.detachDerivedHelper(this)},i.prototype.getModifiedState=function(e){return this.fn(e)},e.exports=i},2437:(e,t,r)=>{"use strict";var n=r(2344),i=r(116),a=r(9803),s={addRefinement:function(e,t,r){if(s.isRefined(e,t,r))return e;var i=""+r,a=e[t]?e[t].concat(i):[i],c={};return c[t]=a,n({},c,e)},removeRefinement:function(e,t,r){if(void 0===r)return s.clearRefinement(e,(function(e,r){return t===r}));var n=""+r;return s.clearRefinement(e,(function(e,r){return t===r&&n===e}))},toggleRefinement:function(e,t,r){if(void 0===r)throw new Error("toggleRefinement should be used with a value");return s.isRefined(e,t,r)?s.removeRefinement(e,t,r):s.addRefinement(e,t,r)},clearRefinement:function(e,t,r){if(void 0===t)return i(e)?{}:e;if("string"==typeof t)return a(e,[t]);if("function"==typeof t){var n=!1,s=Object.keys(e).reduce((function(i,a){var s=e[a]||[],c=s.filter((function(e){return!t(e,a,r)}));return c.length!==s.length&&(n=!0),i[a]=c,i}),{});return n?s:e}},isRefined:function(e,t,r){var n=Boolean(e[t])&&e[t].length>0;if(void 0===r||!n)return n;var i=""+r;return-1!==e[t].indexOf(i)}};e.exports=s},7775:(e,t,r)=>{"use strict";var n=r(2344),i=r(7888),a=r(2686),s=r(185),c=r(116),u=r(9803),o=r(8023),h=r(6801),f=r(2437);function l(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((function(e,r){return l(t[r],e)})):e===t}function m(e){var t=e?m._parseNumbers(e):{};void 0===t.userToken||h(t.userToken)||console.warn("[algoliasearch-helper] The `userToken` parameter is invalid. This can lead to wrong analytics.\n - Format: [a-zA-Z0-9_-]{1,64}"),this.facets=t.facets||[],this.disjunctiveFacets=t.disjunctiveFacets||[],this.hierarchicalFacets=t.hierarchicalFacets||[],this.facetsRefinements=t.facetsRefinements||{},this.facetsExcludes=t.facetsExcludes||{},this.disjunctiveFacetsRefinements=t.disjunctiveFacetsRefinements||{},this.numericRefinements=t.numericRefinements||{},this.tagRefinements=t.tagRefinements||[],this.hierarchicalFacetsRefinements=t.hierarchicalFacetsRefinements||{};var r=this;Object.keys(t).forEach((function(e){var n=-1!==m.PARAMETERS.indexOf(e),i=void 0!==t[e];!n&&i&&(r[e]=t[e])}))}m.PARAMETERS=Object.keys(new m),m._parseNumbers=function(e){if(e instanceof m)return e;var t={};if(["aroundPrecision","aroundRadius","getRankingInfo","minWordSizefor2Typos","minWordSizefor1Typo","page","maxValuesPerFacet","distinct","minimumAroundRadius","hitsPerPage","minProximity"].forEach((function(r){var n=e[r];if("string"==typeof n){var i=parseFloat(n);t[r]=isNaN(i)?n:i}})),Array.isArray(e.insideBoundingBox)&&(t.insideBoundingBox=e.insideBoundingBox.map((function(e){return Array.isArray(e)?e.map((function(e){return parseFloat(e)})):e}))),e.numericRefinements){var r={};Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t]||{};r[t]={},Object.keys(n).forEach((function(e){var i=n[e].map((function(e){return Array.isArray(e)?e.map((function(e){return"string"==typeof e?parseFloat(e):e})):"string"==typeof e?parseFloat(e):e}));r[t][e]=i}))})),t.numericRefinements=r}return s({},e,t)},m.make=function(e){var t=new m(e);return(e.hierarchicalFacets||[]).forEach((function(e){if(e.rootPath){var r=t.getHierarchicalRefinement(e.name);r.length>0&&0!==r[0].indexOf(e.rootPath)&&(t=t.clearRefinements(e.name)),0===(r=t.getHierarchicalRefinement(e.name)).length&&(t=t.toggleHierarchicalFacetRefinement(e.name,e.rootPath))}})),t},m.validate=function(e,t){var r=t||{};return e.tagFilters&&r.tagRefinements&&r.tagRefinements.length>0?new Error("[Tags] Cannot switch from the managed tag API to the advanced API. It is probably an error, if it is really what you want, you should first clear the tags with clearTags method."):e.tagRefinements.length>0&&r.tagFilters?new Error("[Tags] Cannot switch from the advanced tag API to the managed API. It is probably an error, if it is not, you should first clear the tags with clearTags method."):e.numericFilters&&r.numericRefinements&&c(r.numericRefinements)?new Error("[Numeric filters] Can't switch from the advanced to the managed API. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):c(e.numericRefinements)&&r.numericFilters?new Error("[Numeric filters] Can't switch from the managed API to the advanced. It is probably an error, if this is really what you want, you have to first clear the numeric filters."):null},m.prototype={constructor:m,clearRefinements:function(e){var t={numericRefinements:this._clearNumericRefinements(e),facetsRefinements:f.clearRefinement(this.facetsRefinements,e,"conjunctiveFacet"),facetsExcludes:f.clearRefinement(this.facetsExcludes,e,"exclude"),disjunctiveFacetsRefinements:f.clearRefinement(this.disjunctiveFacetsRefinements,e,"disjunctiveFacet"),hierarchicalFacetsRefinements:f.clearRefinement(this.hierarchicalFacetsRefinements,e,"hierarchicalFacet")};return t.numericRefinements===this.numericRefinements&&t.facetsRefinements===this.facetsRefinements&&t.facetsExcludes===this.facetsExcludes&&t.disjunctiveFacetsRefinements===this.disjunctiveFacetsRefinements&&t.hierarchicalFacetsRefinements===this.hierarchicalFacetsRefinements?this:this.setQueryParameters(t)},clearTags:function(){return void 0===this.tagFilters&&0===this.tagRefinements.length?this:this.setQueryParameters({tagFilters:void 0,tagRefinements:[]})},setIndex:function(e){return e===this.index?this:this.setQueryParameters({index:e})},setQuery:function(e){return e===this.query?this:this.setQueryParameters({query:e})},setPage:function(e){return e===this.page?this:this.setQueryParameters({page:e})},setFacets:function(e){return this.setQueryParameters({facets:e})},setDisjunctiveFacets:function(e){return this.setQueryParameters({disjunctiveFacets:e})},setHitsPerPage:function(e){return this.hitsPerPage===e?this:this.setQueryParameters({hitsPerPage:e})},setTypoTolerance:function(e){return this.typoTolerance===e?this:this.setQueryParameters({typoTolerance:e})},addNumericRefinement:function(e,t,r){var n=o(r);if(this.isNumericRefined(e,t,n))return this;var i=s({},this.numericRefinements);return i[e]=s({},i[e]),i[e][t]?(i[e][t]=i[e][t].slice(),i[e][t].push(n)):i[e][t]=[n],this.setQueryParameters({numericRefinements:i})},getConjunctiveRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsRefinements[e]||[]},getDisjunctiveRefinements:function(e){return this.isDisjunctiveFacet(e)&&this.disjunctiveFacetsRefinements[e]||[]},getHierarchicalRefinement:function(e){return this.hierarchicalFacetsRefinements[e]||[]},getExcludeRefinements:function(e){return this.isConjunctiveFacet(e)&&this.facetsExcludes[e]||[]},removeNumericRefinement:function(e,t,r){var n=r;return void 0!==n?this.isNumericRefined(e,t,n)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,i){return i===e&&r.op===t&&l(r.val,o(n))}))}):this:void 0!==t?this.isNumericRefined(e,t)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(r,n){return n===e&&r.op===t}))}):this:this.isNumericRefined(e)?this.setQueryParameters({numericRefinements:this._clearNumericRefinements((function(t,r){return r===e}))}):this},getNumericRefinements:function(e){return this.numericRefinements[e]||{}},getNumericRefinement:function(e,t){return this.numericRefinements[e]&&this.numericRefinements[e][t]},_clearNumericRefinements:function(e){if(void 0===e)return c(this.numericRefinements)?{}:this.numericRefinements;if("string"==typeof e)return u(this.numericRefinements,[e]);if("function"==typeof e){var t=!1,r=this.numericRefinements,n=Object.keys(r).reduce((function(n,i){var a=r[i],s={};return a=a||{},Object.keys(a).forEach((function(r){var n=a[r]||[],c=[];n.forEach((function(t){e({val:t,op:r},i,"numeric")||c.push(t)})),c.length!==n.length&&(t=!0),s[r]=c})),n[i]=s,n}),{});return t?n:this.numericRefinements}},addFacet:function(e){return this.isConjunctiveFacet(e)?this:this.setQueryParameters({facets:this.facets.concat([e])})},addDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this:this.setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.concat([e])})},addHierarchicalFacet:function(e){if(this.isHierarchicalFacet(e.name))throw new Error("Cannot declare two hierarchical facets with the same name: `"+e.name+"`");return this.setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.concat([e])})},addFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this:this.setQueryParameters({facetsRefinements:f.addRefinement(this.facetsRefinements,e,t)})},addExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this:this.setQueryParameters({facetsExcludes:f.addRefinement(this.facetsExcludes,e,t)})},addDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this:this.setQueryParameters({disjunctiveFacetsRefinements:f.addRefinement(this.disjunctiveFacetsRefinements,e,t)})},addTagRefinement:function(e){if(this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.concat(e)};return this.setQueryParameters(t)},removeFacet:function(e){return this.isConjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({facets:this.facets.filter((function(t){return t!==e}))}):this},removeDisjunctiveFacet:function(e){return this.isDisjunctiveFacet(e)?this.clearRefinements(e).setQueryParameters({disjunctiveFacets:this.disjunctiveFacets.filter((function(t){return t!==e}))}):this},removeHierarchicalFacet:function(e){return this.isHierarchicalFacet(e)?this.clearRefinements(e).setQueryParameters({hierarchicalFacets:this.hierarchicalFacets.filter((function(t){return t.name!==e}))}):this},removeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsRefinements,e,t)?this.setQueryParameters({facetsRefinements:f.removeRefinement(this.facetsRefinements,e,t)}):this},removeExcludeRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return f.isRefined(this.facetsExcludes,e,t)?this.setQueryParameters({facetsExcludes:f.removeRefinement(this.facetsExcludes,e,t)}):this},removeDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return f.isRefined(this.disjunctiveFacetsRefinements,e,t)?this.setQueryParameters({disjunctiveFacetsRefinements:f.removeRefinement(this.disjunctiveFacetsRefinements,e,t)}):this},removeTagRefinement:function(e){if(!this.isTagRefined(e))return this;var t={tagRefinements:this.tagRefinements.filter((function(t){return t!==e}))};return this.setQueryParameters(t)},toggleRefinement:function(e,t){return this.toggleFacetRefinement(e,t)},toggleFacetRefinement:function(e,t){if(this.isHierarchicalFacet(e))return this.toggleHierarchicalFacetRefinement(e,t);if(this.isConjunctiveFacet(e))return this.toggleConjunctiveFacetRefinement(e,t);if(this.isDisjunctiveFacet(e))return this.toggleDisjunctiveFacetRefinement(e,t);throw new Error("Cannot refine the undeclared facet "+e+"; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets")},toggleConjunctiveFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsRefinements:f.toggleRefinement(this.facetsRefinements,e,t)})},toggleExcludeFacetRefinement:function(e,t){if(!this.isConjunctiveFacet(e))throw new Error(e+" is not defined in the facets attribute of the helper configuration");return this.setQueryParameters({facetsExcludes:f.toggleRefinement(this.facetsExcludes,e,t)})},toggleDisjunctiveFacetRefinement:function(e,t){if(!this.isDisjunctiveFacet(e))throw new Error(e+" is not defined in the disjunctiveFacets attribute of the helper configuration");return this.setQueryParameters({disjunctiveFacetsRefinements:f.toggleRefinement(this.disjunctiveFacetsRefinements,e,t)})},toggleHierarchicalFacetRefinement:function(e,t){if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration");var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e)),i={};return void 0!==this.hierarchicalFacetsRefinements[e]&&this.hierarchicalFacetsRefinements[e].length>0&&(this.hierarchicalFacetsRefinements[e][0]===t||0===this.hierarchicalFacetsRefinements[e][0].indexOf(t+r))?-1===t.indexOf(r)?i[e]=[]:i[e]=[t.slice(0,t.lastIndexOf(r))]:i[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},i,this.hierarchicalFacetsRefinements)})},addHierarchicalFacetRefinement:function(e,t){if(this.isHierarchicalFacetRefined(e))throw new Error(e+" is already refined.");if(!this.isHierarchicalFacet(e))throw new Error(e+" is not defined in the hierarchicalFacets attribute of the helper configuration.");var r={};return r[e]=[t],this.setQueryParameters({hierarchicalFacetsRefinements:n({},r,this.hierarchicalFacetsRefinements)})},removeHierarchicalFacetRefinement:function(e){if(!this.isHierarchicalFacetRefined(e))return this;var t={};return t[e]=[],this.setQueryParameters({hierarchicalFacetsRefinements:n({},t,this.hierarchicalFacetsRefinements)})},toggleTagRefinement:function(e){return this.isTagRefined(e)?this.removeTagRefinement(e):this.addTagRefinement(e)},isDisjunctiveFacet:function(e){return this.disjunctiveFacets.indexOf(e)>-1},isHierarchicalFacet:function(e){return void 0!==this.getHierarchicalFacetByName(e)},isConjunctiveFacet:function(e){return this.facets.indexOf(e)>-1},isFacetRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsRefinements,e,t)},isExcludeRefined:function(e,t){return!!this.isConjunctiveFacet(e)&&f.isRefined(this.facetsExcludes,e,t)},isDisjunctiveFacetRefined:function(e,t){return!!this.isDisjunctiveFacet(e)&&f.isRefined(this.disjunctiveFacetsRefinements,e,t)},isHierarchicalFacetRefined:function(e,t){if(!this.isHierarchicalFacet(e))return!1;var r=this.getHierarchicalRefinement(e);return t?-1!==r.indexOf(t):r.length>0},isNumericRefined:function(e,t,r){if(void 0===r&&void 0===t)return Boolean(this.numericRefinements[e]);var n=this.numericRefinements[e]&&void 0!==this.numericRefinements[e][t];if(void 0===r||!n)return n;var a,s,c=o(r),u=void 0!==(a=this.numericRefinements[e][t],s=c,i(a,(function(e){return l(e,s)})));return n&&u},isTagRefined:function(e){return-1!==this.tagRefinements.indexOf(e)},getRefinedDisjunctiveFacets:function(){var e=this,t=a(Object.keys(this.numericRefinements).filter((function(t){return Object.keys(e.numericRefinements[t]).length>0})),this.disjunctiveFacets);return Object.keys(this.disjunctiveFacetsRefinements).filter((function(t){return e.disjunctiveFacetsRefinements[t].length>0})).concat(t).concat(this.getRefinedHierarchicalFacets()).sort()},getRefinedHierarchicalFacets:function(){var e=this;return a(this.hierarchicalFacets.map((function(e){return e.name})),Object.keys(this.hierarchicalFacetsRefinements).filter((function(t){return e.hierarchicalFacetsRefinements[t].length>0}))).sort()},getUnrefinedDisjunctiveFacets:function(){var e=this.getRefinedDisjunctiveFacets();return this.disjunctiveFacets.filter((function(t){return-1===e.indexOf(t)}))},managedParameters:["index","facets","disjunctiveFacets","facetsRefinements","hierarchicalFacets","facetsExcludes","disjunctiveFacetsRefinements","numericRefinements","tagRefinements","hierarchicalFacetsRefinements"],getQueryParams:function(){var e=this.managedParameters,t={},r=this;return Object.keys(this).forEach((function(n){var i=r[n];-1===e.indexOf(n)&&void 0!==i&&(t[n]=i)})),t},setQueryParameter:function(e,t){if(this[e]===t)return this;var r={};return r[e]=t,this.setQueryParameters(r)},setQueryParameters:function(e){if(!e)return this;var t=m.validate(this,e);if(t)throw t;var r=this,n=m._parseNumbers(e),i=Object.keys(this).reduce((function(e,t){return e[t]=r[t],e}),{}),a=Object.keys(n).reduce((function(e,t){var r=void 0!==e[t],i=void 0!==n[t];return r&&!i?u(e,[t]):(i&&(e[t]=n[t]),e)}),i);return new this.constructor(a)},resetPage:function(){return void 0===this.page?this:this.setPage(0)},_getHierarchicalFacetSortBy:function(e){return e.sortBy||["isRefined:desc","name:asc"]},_getHierarchicalFacetSeparator:function(e){return e.separator||" > "},_getHierarchicalRootPath:function(e){return e.rootPath||null},_getHierarchicalShowParentLevel:function(e){return"boolean"!=typeof e.showParentLevel||e.showParentLevel},getHierarchicalFacetByName:function(e){return i(this.hierarchicalFacets,(function(t){return t.name===e}))},getHierarchicalFacetBreadcrumb:function(e){if(!this.isHierarchicalFacet(e))return[];var t=this.getHierarchicalRefinement(e)[0];if(!t)return[];var r=this._getHierarchicalFacetSeparator(this.getHierarchicalFacetByName(e));return t.split(r).map((function(e){return e.trim()}))},toString:function(){return JSON.stringify(this,null,2)}},e.exports=m},210:(e,t,r)=>{"use strict";e.exports=function(e){return function(t,r){var n=e.hierarchicalFacets[r],o=e.hierarchicalFacetsRefinements[n.name]&&e.hierarchicalFacetsRefinements[n.name][0]||"",h=e._getHierarchicalFacetSeparator(n),f=e._getHierarchicalRootPath(n),l=e._getHierarchicalShowParentLevel(n),m=a(e._getHierarchicalFacetSortBy(n)),d=t.every((function(e){return e.exhaustive})),p=function(e,t,r,n,a){return function(o,h,f){var l=o;if(f>0){var m=0;for(l=o;m<f;){var d=l&&Array.isArray(l.data)?l.data:[];l=i(d,(function(e){return e.isRefined})),m++}}if(l){var p=Object.keys(h.data).map((function(e){return[e,h.data[e]]})).filter((function(e){return function(e,t,r,n,i,a){if(i&&(0!==e.indexOf(i)||i===e))return!1;return!i&&-1===e.indexOf(n)||i&&e.split(n).length-i.split(n).length==1||-1===e.indexOf(n)&&-1===r.indexOf(n)||0===r.indexOf(e)||0===e.indexOf(t+n)&&(a||0===e.indexOf(r))}(e[0],l.path||r,a,t,r,n)}));l.data=s(p.map((function(e){var r=e[0];return function(e,t,r,n,i){var a=t.split(r);return{name:a[a.length-1].trim(),path:t,escapedValue:c(t),count:e,isRefined:n===t||0===n.indexOf(t+r),exhaustive:i,data:null}}(e[1],r,t,u(a),h.exhaustive)})),e[0],e[1])}return o}}(m,h,f,l,o),v=t;return f&&(v=t.slice(f.split(h).length)),v.reduce(p,{name:e.hierarchicalFacets[r].name,count:null,isRefined:!0,path:null,escapedValue:null,exhaustive:d,data:null})}};var n=r(4039),i=r(7888),a=r(2293),s=r(2148),c=n.escapeFacetValue,u=n.unescapeFacetValue},3076:(e,t,r)=>{"use strict";var n=r(4587),i=r(2344),a=r(4039),s=r(7888),c=r(9725),u=r(2293),o=r(185),h=r(2148),f=a.escapeFacetValue,l=a.unescapeFacetValue,m=r(210);function d(e){var t={};return e.forEach((function(e,r){t[e]=r})),t}function p(e,t,r){t&&t[r]&&(e.stats=t[r])}function v(e,t,r){var a=t[0];this._rawResults=t;var u=this;Object.keys(a).forEach((function(e){u[e]=a[e]})),Object.keys(r||{}).forEach((function(e){u[e]=r[e]})),this.processingTimeMS=t.reduce((function(e,t){return void 0===t.processingTimeMS?e:e+t.processingTimeMS}),0),this.disjunctiveFacets=[],this.hierarchicalFacets=e.hierarchicalFacets.map((function(){return[]})),this.facets=[];var h=e.getRefinedDisjunctiveFacets(),f=d(e.facets),v=d(e.disjunctiveFacets),g=1,y=a.facets||{};Object.keys(y).forEach((function(t){var r,n,i=y[t],o=(r=e.hierarchicalFacets,n=t,s(r,(function(e){return(e.attributes||[]).indexOf(n)>-1})));if(o){var h=o.attributes.indexOf(t),l=c(e.hierarchicalFacets,(function(e){return e.name===o.name}));u.hierarchicalFacets[l][h]={attribute:t,data:i,exhaustive:a.exhaustiveFacetsCount}}else{var m,d=-1!==e.disjunctiveFacets.indexOf(t),g=-1!==e.facets.indexOf(t);d&&(m=v[t],u.disjunctiveFacets[m]={name:t,data:i,exhaustive:a.exhaustiveFacetsCount},p(u.disjunctiveFacets[m],a.facets_stats,t)),g&&(m=f[t],u.facets[m]={name:t,data:i,exhaustive:a.exhaustiveFacetsCount},p(u.facets[m],a.facets_stats,t))}})),this.hierarchicalFacets=n(this.hierarchicalFacets),h.forEach((function(r){var n=t[g],s=n&&n.facets?n.facets:{},h=e.getHierarchicalFacetByName(r);Object.keys(s).forEach((function(t){var r,f=s[t];if(h){r=c(e.hierarchicalFacets,(function(e){return e.name===h.name}));var m=c(u.hierarchicalFacets[r],(function(e){return e.attribute===t}));if(-1===m)return;u.hierarchicalFacets[r][m].data=o({},u.hierarchicalFacets[r][m].data,f)}else{r=v[t];var d=a.facets&&a.facets[t]||{};u.disjunctiveFacets[r]={name:t,data:i({},f,d),exhaustive:n.exhaustiveFacetsCount},p(u.disjunctiveFacets[r],n.facets_stats,t),e.disjunctiveFacetsRefinements[t]&&e.disjunctiveFacetsRefinements[t].forEach((function(n){!u.disjunctiveFacets[r].data[n]&&e.disjunctiveFacetsRefinements[t].indexOf(l(n))>-1&&(u.disjunctiveFacets[r].data[n]=0)}))}})),g++})),e.getRefinedHierarchicalFacets().forEach((function(r){var n=e.getHierarchicalFacetByName(r),a=e._getHierarchicalFacetSeparator(n),s=e.getHierarchicalRefinement(r);0===s.length||s[0].split(a).length<2||t.slice(g).forEach((function(t){var r=t&&t.facets?t.facets:{};Object.keys(r).forEach((function(t){var o=r[t],h=c(e.hierarchicalFacets,(function(e){return e.name===n.name})),f=c(u.hierarchicalFacets[h],(function(e){return e.attribute===t}));if(-1!==f){var l={};if(s.length>0){var m=s[0].split(a)[0];l[m]=u.hierarchicalFacets[h][f].data[m]}u.hierarchicalFacets[h][f].data=i(l,o,u.hierarchicalFacets[h][f].data)}})),g++}))})),Object.keys(e.facetsExcludes).forEach((function(t){var r=e.facetsExcludes[t],n=f[t];u.facets[n]={name:t,data:y[t],exhaustive:a.exhaustiveFacetsCount},r.forEach((function(e){u.facets[n]=u.facets[n]||{name:t},u.facets[n].data=u.facets[n].data||{},u.facets[n].data[e]=0}))})),this.hierarchicalFacets=this.hierarchicalFacets.map(m(e)),this.facets=n(this.facets),this.disjunctiveFacets=n(this.disjunctiveFacets),this._state=e}function g(e,t){function r(e){return e.name===t}if(e._state.isConjunctiveFacet(t)){var n=s(e.facets,r);return n?Object.keys(n.data).map((function(r){var i=f(r);return{name:r,escapedValue:i,count:n.data[r],isRefined:e._state.isFacetRefined(t,i),isExcluded:e._state.isExcludeRefined(t,r)}})):[]}if(e._state.isDisjunctiveFacet(t)){var i=s(e.disjunctiveFacets,r);return i?Object.keys(i.data).map((function(r){var n=f(r);return{name:r,escapedValue:n,count:i.data[r],isRefined:e._state.isDisjunctiveFacetRefined(t,n)}})):[]}if(e._state.isHierarchicalFacet(t)){var a=s(e.hierarchicalFacets,r);if(!a)return a;var c=e._state.getHierarchicalFacetByName(t),u=e._state._getHierarchicalFacetSeparator(c),o=l(e._state.getHierarchicalRefinement(t)[0]||"");0===o.indexOf(c.rootPath)&&(o=o.replace(c.rootPath+u,""));var h=o.split(u);return h.unshift(t),y(a,h,0),a}}function y(e,t,r){e.isRefined=e.name===t[r],e.data&&e.data.forEach((function(e){y(e,t,r+1)}))}function R(e,t,r,n){if(n=n||0,Array.isArray(t))return e(t,r[n]);if(!t.data||0===t.data.length)return t;var a=t.data.map((function(t){return R(e,t,r,n+1)})),s=e(a,r[n]);return i({data:s},t)}function F(e,t){var r=s(e,(function(e){return e.name===t}));return r&&r.stats}function b(e,t,r,n,i){var a=s(i,(function(e){return e.name===r})),c=a&&a.data&&a.data[n]?a.data[n]:0,u=a&&a.exhaustive||!1;return{type:t,attributeName:r,name:n,count:c,exhaustive:u}}v.prototype.getFacetByName=function(e){function t(t){return t.name===e}return s(this.facets,t)||s(this.disjunctiveFacets,t)||s(this.hierarchicalFacets,t)},v.DEFAULT_SORT=["isRefined:desc","count:desc","name:asc"],v.prototype.getFacetValues=function(e,t){var r=g(this,e);if(r){var n,a=i({},t,{sortBy:v.DEFAULT_SORT,facetOrdering:!(t&&t.sortBy)}),s=this;if(Array.isArray(r))n=[e];else n=s._state.getHierarchicalFacetByName(r.name).attributes;return R((function(e,t){if(a.facetOrdering){var r=function(e,t){return e.renderingContent&&e.renderingContent.facetOrdering&&e.renderingContent.facetOrdering.values&&e.renderingContent.facetOrdering.values[t]}(s,t);if(r)return function(e,t){var r=[],n=[],i=(t.order||[]).reduce((function(e,t,r){return e[t]=r,e}),{});e.forEach((function(e){var t=e.path||e.name;void 0!==i[t]?r[i[t]]=e:n.push(e)})),r=r.filter((function(e){return e}));var a,s=t.sortRemainingBy;return"hidden"===s?r:(a="alpha"===s?[["path","name"],["asc","asc"]]:[["count"],["desc"]],r.concat(h(n,a[0],a[1])))}(e,r)}if(Array.isArray(a.sortBy)){var n=u(a.sortBy,v.DEFAULT_SORT);return h(e,n[0],n[1])}if("function"==typeof a.sortBy)return function(e,t){return t.sort(e)}(a.sortBy,e);throw new Error("options.sortBy is optional but if defined it must be either an array of string (predicates) or a sorting function")}),r,n)}},v.prototype.getFacetStats=function(e){return this._state.isConjunctiveFacet(e)?F(this.facets,e):this._state.isDisjunctiveFacet(e)?F(this.disjunctiveFacets,e):void 0},v.prototype.getRefinements=function(){var e=this._state,t=this,r=[];return Object.keys(e.facetsRefinements).forEach((function(n){e.facetsRefinements[n].forEach((function(i){r.push(b(e,"facet",n,i,t.facets))}))})),Object.keys(e.facetsExcludes).forEach((function(n){e.facetsExcludes[n].forEach((function(i){r.push(b(e,"exclude",n,i,t.facets))}))})),Object.keys(e.disjunctiveFacetsRefinements).forEach((function(n){e.disjunctiveFacetsRefinements[n].forEach((function(i){r.push(b(e,"disjunctive",n,i,t.disjunctiveFacets))}))})),Object.keys(e.hierarchicalFacetsRefinements).forEach((function(n){e.hierarchicalFacetsRefinements[n].forEach((function(i){r.push(function(e,t,r,n){var i=e.getHierarchicalFacetByName(t),a=e._getHierarchicalFacetSeparator(i),c=r.split(a),u=s(n,(function(e){return e.name===t})),o=c.reduce((function(e,t){var r=e&&s(e.data,(function(e){return e.name===t}));return void 0!==r?r:e}),u),h=o&&o.count||0,f=o&&o.exhaustive||!1,l=o&&o.path||"";return{type:"hierarchical",attributeName:t,name:l,count:h,exhaustive:f}}(e,n,i,t.hierarchicalFacets))}))})),Object.keys(e.numericRefinements).forEach((function(t){var n=e.numericRefinements[t];Object.keys(n).forEach((function(e){n[e].forEach((function(n){r.push({type:"numeric",attributeName:t,name:n,numericValue:n,operator:e})}))}))})),e.tagRefinements.forEach((function(e){r.push({type:"tag",attributeName:"_tags",name:e})})),r},e.exports=v},9374:(e,t,r)=>{"use strict";var n=r(7331),i=r(8078),a=r(4039).escapeFacetValue,s=r(4853),c=r(185),u=r(116),o=r(9803),h=r(6394),f=r(7775),l=r(3076),m=r(4336);function d(e,t,r){"function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+m+")"),this.setClient(e);var n=r||{};n.index=t,this.state=f.make(n),this.lastResults=null,this._queryId=0,this._lastQueryIdReceived=-1,this.derivedHelpers=[],this._currentNbQueries=0}function p(e){if(e<0)throw new Error("Page requested below 0.");return this._change({state:this.state.setPage(e),isPageReset:!1}),this}function v(){return this.state.page}s(d,n),d.prototype.search=function(){return this._search({onlyWithDerivedHelpers:!1}),this},d.prototype.searchOnlyWithDerivedHelpers=function(){return this._search({onlyWithDerivedHelpers:!0}),this},d.prototype.getQuery=function(){var e=this.state;return h._getHitsSearchParams(e)},d.prototype.searchOnce=function(e,t){var r=e?this.state.setQueryParameters(e):this.state,n=h._getQueries(r.index,r),i=this;if(this._currentNbQueries++,this.emit("searchOnce",{state:r}),!t)return this.client.search(n).then((function(e){return i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),{content:new l(r,e.results),state:r,_originalResponse:e}}),(function(e){throw i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),e}));this.client.search(n).then((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(null,new l(r,e.results),r)})).catch((function(e){i._currentNbQueries--,0===i._currentNbQueries&&i.emit("searchQueueEmpty"),t(e,null,r)}))},d.prototype.findAnswers=function(e){console.warn("[algoliasearch-helper] answers is no longer supported");var t=this.state,r=this.derivedHelpers[0];if(!r)return Promise.resolve([]);var n=r.getModifiedState(t),i=c({attributesForPrediction:e.attributesForPrediction,nbHits:e.nbHits},{params:o(h._getHitsSearchParams(n),["attributesToSnippet","hitsPerPage","restrictSearchableAttributes","snippetEllipsisText"])}),a="search for answers was called, but this client does not have a function client.initIndex(index).findAnswers";if("function"!=typeof this.client.initIndex)throw new Error(a);var s=this.client.initIndex(n.index);if("function"!=typeof s.findAnswers)throw new Error(a);return s.findAnswers(n.query,e.queryLanguages,i)},d.prototype.searchForFacetValues=function(e,t,r,n){var i="function"==typeof this.client.searchForFacetValues,s="function"==typeof this.client.initIndex;if(!i&&!s&&"function"!=typeof this.client.search)throw new Error("search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues");var c=this.state.setQueryParameters(n||{}),u=c.isDisjunctiveFacet(e),o=h.getSearchForFacetQuery(e,t,r,c);this._currentNbQueries++;var f,l=this;return i?f=this.client.searchForFacetValues([{indexName:c.index,params:o}]):s?f=this.client.initIndex(c.index).searchForFacetValues(o):(delete o.facetName,f=this.client.search([{type:"facet",facet:e,indexName:c.index,params:o}]).then((function(e){return e.results[0]}))),this.emit("searchForFacetValues",{state:c,facet:e,query:t}),f.then((function(t){return l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),(t=Array.isArray(t)?t[0]:t).facetHits.forEach((function(t){t.escapedValue=a(t.value),t.isRefined=u?c.isDisjunctiveFacetRefined(e,t.escapedValue):c.isFacetRefined(e,t.escapedValue)})),t}),(function(e){throw l._currentNbQueries--,0===l._currentNbQueries&&l.emit("searchQueueEmpty"),e}))},d.prototype.setQuery=function(e){return this._change({state:this.state.resetPage().setQuery(e),isPageReset:!0}),this},d.prototype.clearRefinements=function(e){return this._change({state:this.state.resetPage().clearRefinements(e),isPageReset:!0}),this},d.prototype.clearTags=function(){return this._change({state:this.state.resetPage().clearTags(),isPageReset:!0}),this},d.prototype.addDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addDisjunctiveRefine=function(){return this.addDisjunctiveFacetRefinement.apply(this,arguments)},d.prototype.addHierarchicalFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addHierarchicalFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().addNumericRefinement(e,t,r),isPageReset:!0}),this},d.prototype.addFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().addFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.addRefine=function(){return this.addFacetRefinement.apply(this,arguments)},d.prototype.addFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().addExcludeRefinement(e,t),isPageReset:!0}),this},d.prototype.addExclude=function(){return this.addFacetExclusion.apply(this,arguments)},d.prototype.addTag=function(e){return this._change({state:this.state.resetPage().addTagRefinement(e),isPageReset:!0}),this},d.prototype.removeNumericRefinement=function(e,t,r){return this._change({state:this.state.resetPage().removeNumericRefinement(e,t,r),isPageReset:!0}),this},d.prototype.removeDisjunctiveFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeDisjunctiveFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.removeDisjunctiveRefine=function(){return this.removeDisjunctiveFacetRefinement.apply(this,arguments)},d.prototype.removeHierarchicalFacetRefinement=function(e){return this._change({state:this.state.resetPage().removeHierarchicalFacetRefinement(e),isPageReset:!0}),this},d.prototype.removeFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().removeFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.removeRefine=function(){return this.removeFacetRefinement.apply(this,arguments)},d.prototype.removeFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().removeExcludeRefinement(e,t),isPageReset:!0}),this},d.prototype.removeExclude=function(){return this.removeFacetExclusion.apply(this,arguments)},d.prototype.removeTag=function(e){return this._change({state:this.state.resetPage().removeTagRefinement(e),isPageReset:!0}),this},d.prototype.toggleFacetExclusion=function(e,t){return this._change({state:this.state.resetPage().toggleExcludeFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.toggleExclude=function(){return this.toggleFacetExclusion.apply(this,arguments)},d.prototype.toggleRefinement=function(e,t){return this.toggleFacetRefinement(e,t)},d.prototype.toggleFacetRefinement=function(e,t){return this._change({state:this.state.resetPage().toggleFacetRefinement(e,t),isPageReset:!0}),this},d.prototype.toggleRefine=function(){return this.toggleFacetRefinement.apply(this,arguments)},d.prototype.toggleTag=function(e){return this._change({state:this.state.resetPage().toggleTagRefinement(e),isPageReset:!0}),this},d.prototype.nextPage=function(){var e=this.state.page||0;return this.setPage(e+1)},d.prototype.previousPage=function(){var e=this.state.page||0;return this.setPage(e-1)},d.prototype.setCurrentPage=p,d.prototype.setPage=p,d.prototype.setIndex=function(e){return this._change({state:this.state.resetPage().setIndex(e),isPageReset:!0}),this},d.prototype.setQueryParameter=function(e,t){return this._change({state:this.state.resetPage().setQueryParameter(e,t),isPageReset:!0}),this},d.prototype.setState=function(e){return this._change({state:f.make(e),isPageReset:!1}),this},d.prototype.overrideStateWithoutTriggeringChangeEvent=function(e){return this.state=new f(e),this},d.prototype.hasRefinements=function(e){return!!u(this.state.getNumericRefinements(e))||(this.state.isConjunctiveFacet(e)?this.state.isFacetRefined(e):this.state.isDisjunctiveFacet(e)?this.state.isDisjunctiveFacetRefined(e):!!this.state.isHierarchicalFacet(e)&&this.state.isHierarchicalFacetRefined(e))},d.prototype.isExcluded=function(e,t){return this.state.isExcludeRefined(e,t)},d.prototype.isDisjunctiveRefined=function(e,t){return this.state.isDisjunctiveFacetRefined(e,t)},d.prototype.hasTag=function(e){return this.state.isTagRefined(e)},d.prototype.isTagRefined=function(){return this.hasTagRefinements.apply(this,arguments)},d.prototype.getIndex=function(){return this.state.index},d.prototype.getCurrentPage=v,d.prototype.getPage=v,d.prototype.getTags=function(){return this.state.tagRefinements},d.prototype.getRefinements=function(e){var t=[];if(this.state.isConjunctiveFacet(e))this.state.getConjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"conjunctive"})})),this.state.getExcludeRefinements(e).forEach((function(e){t.push({value:e,type:"exclude"})}));else if(this.state.isDisjunctiveFacet(e)){this.state.getDisjunctiveRefinements(e).forEach((function(e){t.push({value:e,type:"disjunctive"})}))}var r=this.state.getNumericRefinements(e);return Object.keys(r).forEach((function(e){var n=r[e];t.push({value:n,operator:e,type:"numeric"})})),t},d.prototype.getNumericRefinement=function(e,t){return this.state.getNumericRefinement(e,t)},d.prototype.getHierarchicalFacetBreadcrumb=function(e){return this.state.getHierarchicalFacetBreadcrumb(e)},d.prototype._search=function(e){var t=this.state,r=[],n=[];e.onlyWithDerivedHelpers||(n=h._getQueries(t.index,t),r.push({state:t,queriesCount:n.length,helper:this}),this.emit("search",{state:t,results:this.lastResults}));var i=this.derivedHelpers.map((function(e){var n=e.getModifiedState(t),i=n.index?h._getQueries(n.index,n):[];return r.push({state:n,queriesCount:i.length,helper:e}),e.emit("search",{state:n,results:e.lastResults}),i})),a=Array.prototype.concat.apply(n,i),s=this._queryId++;if(this._currentNbQueries++,!a.length)return Promise.resolve({results:[]}).then(this._dispatchAlgoliaResponse.bind(this,r,s));try{this.client.search(a).then(this._dispatchAlgoliaResponse.bind(this,r,s)).catch(this._dispatchAlgoliaError.bind(this,s))}catch(c){this.emit("error",{error:c})}},d.prototype._dispatchAlgoliaResponse=function(e,t,r){if(!(t<this._lastQueryIdReceived)){this._currentNbQueries-=t-this._lastQueryIdReceived,this._lastQueryIdReceived=t,0===this._currentNbQueries&&this.emit("searchQueueEmpty");var n=r.results.slice();e.forEach((function(e){var t=e.state,r=e.queriesCount,i=e.helper,a=n.splice(0,r);t.index?(i.lastResults=new l(t,a),i.emit("result",{results:i.lastResults,state:t})):i.emit("result",{results:null,state:t})}))}},d.prototype._dispatchAlgoliaError=function(e,t){e<this._lastQueryIdReceived||(this._currentNbQueries-=e-this._lastQueryIdReceived,this._lastQueryIdReceived=e,this.emit("error",{error:t}),0===this._currentNbQueries&&this.emit("searchQueueEmpty"))},d.prototype.containsRefinement=function(e,t,r,n){return e||0!==t.length||0!==r.length||0!==n.length},d.prototype._hasDisjunctiveRefinements=function(e){return this.state.disjunctiveRefinements[e]&&this.state.disjunctiveRefinements[e].length>0},d.prototype._change=function(e){var t=e.state,r=e.isPageReset;t!==this.state&&(this.state=t,this.emit("change",{state:this.state,results:this.lastResults,isPageReset:r}))},d.prototype.clearCache=function(){return this.client.clearCache&&this.client.clearCache(),this},d.prototype.setClient=function(e){return this.client===e||("function"==typeof e.addAlgoliaAgent&&e.addAlgoliaAgent("JS Helper ("+m+")"),this.client=e),this},d.prototype.getClient=function(){return this.client},d.prototype.derive=function(e){var t=new i(this,e);return this.derivedHelpers.push(t),t},d.prototype.detachDerivedHelper=function(e){var t=this.derivedHelpers.indexOf(e);if(-1===t)throw new Error("Derived helper already detached");this.derivedHelpers.splice(t,1)},d.prototype.hasPendingRequests=function(){return this._currentNbQueries>0},e.exports=d},4587:e=>{"use strict";e.exports=function(e){return Array.isArray(e)?e.filter(Boolean):[]}},2344:e=>{"use strict";e.exports=function(){return Array.prototype.slice.call(arguments).reduceRight((function(e,t){return Object.keys(Object(t)).forEach((function(r){void 0!==t[r]&&(void 0!==e[r]&&delete e[r],e[r]=t[r])})),e}),{})}},4039:e=>{"use strict";e.exports={escapeFacetValue:function(e){return"string"!=typeof e?e:String(e).replace(/^-/,"\\-")},unescapeFacetValue:function(e){return"string"!=typeof e?e:e.replace(/^\\-/,"-")}}},7888:e=>{"use strict";e.exports=function(e,t){if(Array.isArray(e))for(var r=0;r<e.length;r++)if(t(e[r]))return e[r]}},9725:e=>{"use strict";e.exports=function(e,t){if(!Array.isArray(e))return-1;for(var r=0;r<e.length;r++)if(t(e[r]))return r;return-1}},2293:(e,t,r)=>{"use strict";var n=r(7888);e.exports=function(e,t){var r=(t||[]).map((function(e){return e.split(":")}));return e.reduce((function(e,t){var i=t.split(":"),a=n(r,(function(e){return e[0]===i[0]}));return i.length>1||!a?(e[0].push(i[0]),e[1].push(i[1]),e):(e[0].push(a[0]),e[1].push(a[1]),e)}),[[],[]])}},4853:e=>{"use strict";e.exports=function(e,t){e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}},2686:e=>{"use strict";e.exports=function(e,t){return e.filter((function(r,n){return t.indexOf(r)>-1&&e.indexOf(r)===n}))}},185:e=>{"use strict";function t(e){return"function"==typeof e||Array.isArray(e)||"[object Object]"===Object.prototype.toString.call(e)}function r(e,n){if(e===n)return e;for(var i in n)if(Object.prototype.hasOwnProperty.call(n,i)&&"__proto__"!==i&&"constructor"!==i){var a=n[i],s=e[i];void 0!==s&&void 0===a||(t(s)&&t(a)?e[i]=r(s,a):e[i]="object"==typeof(c=a)&&null!==c?r(Array.isArray(c)?[]:{},c):c)}var c;return e}e.exports=function(e){t(e)||(e={});for(var n=1,i=arguments.length;n<i;n++){var a=arguments[n];t(a)&&r(e,a)}return e}},116:e=>{"use strict";e.exports=function(e){return e&&Object.keys(e).length>0}},9803:e=>{"use strict";e.exports=function(e,t){if(null===e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}},2148:e=>{"use strict";function t(e,t){if(e!==t){var r=void 0!==e,n=null===e,i=void 0!==t,a=null===t;if(!a&&e>t||n&&i||!r)return 1;if(!n&&e<t||a&&r||!i)return-1}return 0}e.exports=function(e,r,n){if(!Array.isArray(e))return[];Array.isArray(n)||(n=[]);var i=e.map((function(e,t){return{criteria:r.map((function(t){return e[t]})),index:t,value:e}}));return i.sort((function(e,r){for(var i=-1;++i<e.criteria.length;){var a=t(e.criteria[i],r.criteria[i]);if(a)return i>=n.length?a:"desc"===n[i]?-a:a}return e.index-r.index})),i.map((function(e){return e.value}))}},8023:e=>{"use strict";e.exports=function e(t){if("number"==typeof t)return t;if("string"==typeof t)return parseFloat(t);if(Array.isArray(t))return t.map(e);throw new Error("The value should be a number, a parsable string or an array of those.")}},6394:(e,t,r)=>{"use strict";var n=r(185);function i(e){return Object.keys(e).sort().reduce((function(t,r){return t[r]=e[r],t}),{})}var a={_getQueries:function(e,t){var r=[];return r.push({indexName:e,params:a._getHitsSearchParams(t)}),t.getRefinedDisjunctiveFacets().forEach((function(n){r.push({indexName:e,params:a._getDisjunctiveFacetSearchParams(t,n)})})),t.getRefinedHierarchicalFacets().forEach((function(n){var i=t.getHierarchicalFacetByName(n),s=t.getHierarchicalRefinement(n),c=t._getHierarchicalFacetSeparator(i);if(s.length>0&&s[0].split(c).length>1){var u=s[0].split(c).slice(0,-1).reduce((function(e,t,r){return e.concat({attribute:i.attributes[r],value:0===r?t:[e[e.length-1].value,t].join(c)})}),[]);u.forEach((function(n,s){var c=a._getDisjunctiveFacetSearchParams(t,n.attribute,0===s);function o(e){return i.attributes.some((function(t){return t===e.split(":")[0]}))}var h=(c.facetFilters||[]).reduce((function(e,t){if(Array.isArray(t)){var r=t.filter((function(e){return!o(e)}));r.length>0&&e.push(r)}return"string"!=typeof t||o(t)||e.push(t),e}),[]),f=u[s-1];c.facetFilters=s>0?h.concat(f.attribute+":"+f.value):h.length>0?h:void 0,r.push({indexName:e,params:c})}))}})),r},_getHitsSearchParams:function(e){var t=e.facets.concat(e.disjunctiveFacets).concat(a._getHitsHierarchicalFacetsAttributes(e)).sort(),r=a._getFacetFilters(e),s=a._getNumericFilters(e),c=a._getTagFilters(e),u={facets:t.indexOf("*")>-1?["*"]:t,tagFilters:c};return r.length>0&&(u.facetFilters=r),s.length>0&&(u.numericFilters=s),i(n({},e.getQueryParams(),u))},_getDisjunctiveFacetSearchParams:function(e,t,r){var s=a._getFacetFilters(e,t,r),c=a._getNumericFilters(e,t),u=a._getTagFilters(e),o={hitsPerPage:0,page:0,analytics:!1,clickAnalytics:!1};u.length>0&&(o.tagFilters=u);var h=e.getHierarchicalFacetByName(t);return o.facets=h?a._getDisjunctiveHierarchicalFacetAttribute(e,h,r):t,c.length>0&&(o.numericFilters=c),s.length>0&&(o.facetFilters=s),i(n({},e.getQueryParams(),o))},_getNumericFilters:function(e,t){if(e.numericFilters)return e.numericFilters;var r=[];return Object.keys(e.numericRefinements).forEach((function(n){var i=e.numericRefinements[n]||{};Object.keys(i).forEach((function(e){var a=i[e]||[];t!==n&&a.forEach((function(t){if(Array.isArray(t)){var i=t.map((function(t){return n+e+t}));r.push(i)}else r.push(n+e+t)}))}))})),r},_getTagFilters:function(e){return e.tagFilters?e.tagFilters:e.tagRefinements.join(",")},_getFacetFilters:function(e,t,r){var n=[],i=e.facetsRefinements||{};Object.keys(i).sort().forEach((function(e){(i[e]||[]).sort().forEach((function(t){n.push(e+":"+t)}))}));var a=e.facetsExcludes||{};Object.keys(a).sort().forEach((function(e){(a[e]||[]).sort().forEach((function(t){n.push(e+":-"+t)}))}));var s=e.disjunctiveFacetsRefinements||{};Object.keys(s).sort().forEach((function(e){var r=s[e]||[];if(e!==t&&r&&0!==r.length){var i=[];r.sort().forEach((function(t){i.push(e+":"+t)})),n.push(i)}}));var c=e.hierarchicalFacetsRefinements||{};return Object.keys(c).sort().forEach((function(i){var a=(c[i]||[])[0];if(void 0!==a){var s,u,o=e.getHierarchicalFacetByName(i),h=e._getHierarchicalFacetSeparator(o),f=e._getHierarchicalRootPath(o);if(t===i){if(-1===a.indexOf(h)||!f&&!0===r||f&&f.split(h).length===a.split(h).length)return;f?(u=f.split(h).length-1,a=f):(u=a.split(h).length-2,a=a.slice(0,a.lastIndexOf(h))),s=o.attributes[u]}else u=a.split(h).length-1,s=o.attributes[u];s&&n.push([s+":"+a])}})),n},_getHitsHierarchicalFacetsAttributes:function(e){return e.hierarchicalFacets.reduce((function(t,r){var n=e.getHierarchicalRefinement(r.name)[0];if(!n)return t.push(r.attributes[0]),t;var i=e._getHierarchicalFacetSeparator(r),a=n.split(i).length,s=r.attributes.slice(0,a+1);return t.concat(s)}),[])},_getDisjunctiveHierarchicalFacetAttribute:function(e,t,r){var n=e._getHierarchicalFacetSeparator(t);if(!0===r){var i=e._getHierarchicalRootPath(t),a=0;return i&&(a=i.split(n).length),[t.attributes[a]]}var s=(e.getHierarchicalRefinement(t.name)[0]||"").split(n).length-1;return t.attributes.slice(0,s+1)},getSearchForFacetQuery:function(e,t,r,s){var c=s.isDisjunctiveFacet(e)?s.clearRefinements(e):s,u={facetQuery:t,facetName:e};return"number"==typeof r&&(u.maxFacetHits=r),i(n({},a._getHitsSearchParams(c),u))}};e.exports=a},6801:e=>{"use strict";e.exports=function(e){return null!==e&&/^[a-zA-Z0-9_-]{1,64}$/.test(e)}},4336:e=>{"use strict";e.exports="3.14.2"},290:function(e){e.exports=function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n<arguments.length;n++){var i=null!=arguments[n]?arguments[n]:{};n%2?t(Object(i),!0).forEach((function(t){e(r,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(i)):t(Object(i)).forEach((function(e){Object.defineProperty(r,e,Object.getOwnPropertyDescriptor(i,e))}))}return r}function n(e,t){if(null==e)return{};var r,n,i=function(e,t){if(null==e)return{};var r,n,i={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)){var r=[],n=!0,i=!1,a=void 0;try{for(var s,c=e[Symbol.iterator]();!(n=(s=c.next()).done)&&(r.push(s.value),!t||r.length!==t);n=!0);}catch(e){i=!0,a=e}finally{try{n||null==c.return||c.return()}finally{if(i)throw a}}return r}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t<e.length;t++)r[t]=e[t];return r}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function s(e){var t,r="algoliasearch-client-js-".concat(e.key),n=function(){return void 0===t&&(t=e.localStorage||window.localStorage),t},a=function(){return JSON.parse(n().getItem(r)||"{}")},s=function(e){n().setItem(r,JSON.stringify(e))},c=function(){var t=e.timeToLive?1e3*e.timeToLive:null,r=a(),n=Object.fromEntries(Object.entries(r).filter((function(e){return void 0!==i(e,2)[1].timestamp})));if(s(n),t){var c=Object.fromEntries(Object.entries(n).filter((function(e){var r=i(e,2)[1],n=(new Date).getTime();return!(r.timestamp+t<n)})));s(c)}};return{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){c();var t=JSON.stringify(e);return a()[t]})).then((function(e){return Promise.all([e?e.value:t(),void 0!==e])})).then((function(e){var t=i(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var i=a();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:t},n().setItem(r,JSON.stringify(i)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function c(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return t().then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return i(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,i).catch((function(){return c({caches:t}).get(e,n,i)}))},set:function(e,n){return r.set(e,n).catch((function(){return c({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return c({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return c({caches:t}).clear()}))}}}function u(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var s=n(),c=i&&i.miss||function(){return Promise.resolve()};return s.then((function(e){return c(e)})).then((function(){return s}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function o(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function h(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n<t;n++)r[n-1]=arguments[n];var i=0;return e.replace(/%s/g,(function(){return encodeURIComponent(r[i++])}))}var l={WithinQueryParameters:0,WithinHeaders:1};function m(e,t){var r=e||{},n=r.data||{};return Object.keys(r).forEach((function(e){-1===["timeout","headers","queryParameters","data","cacheable"].indexOf(e)&&(n[e]=r[e])})),{data:Object.entries(n).length>0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var d={Read:1,Write:2,Any:3},p=1,v=2,g=3;function y(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:p;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function R(e){return"string"==typeof e?{protocol:"https",url:e,accept:d.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||d.Any}}var F="GET",b="POST";function P(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(y(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===p||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===g&&Date.now()-e.lastUpdate<=12e4}(e)})),i=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:i.length>0?i.map((function(e){return R(e)})):t}}))}function j(e,t,n,i){var s=[],c=function(e,t){if(e.method!==F&&(void 0!==e.data||void 0!==t.data)){var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}}(n,i),u=function(e,t){var n=r(r({},e.headers),t.headers),i={};return Object.keys(n).forEach((function(e){var t=n[e];i[e.toLowerCase()]=t})),i}(e,i),o=n.method,h=n.method!==F?{}:r(r({},n.data),i.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),h),i.queryParameters),l=0,m=function t(r,a){var h=r.pop();if(void 0===h)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:O(s)};var m={data:c,headers:u,method:o,url:E(h,n.path,f),connectTimeout:a(l,e.timeouts.connect),responseTimeout:a(l,i.timeout)},d=function(e){var t={request:m,response:e,host:h,triesLeft:r.length};return s.push(t),t},p={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var i=d(n);return n.isTimedOut&&l++,Promise.all([e.logger.info("Retryable failure",w(i)),e.hostsCache.set(h,y(h,n.isTimedOut?g:v))]).then((function(){return t(r,a)}))},onFail:function(e){throw d(e),function(e,t){var r=e.content,n=e.status,i=r;try{i=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(i,n,t)}(e,O(s))}};return e.requester.send(m).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,p)}))};return P(e.hostsCache,t).then((function(e){return m(a(e.statelessHosts).reverse(),e.getTimeout)}))}function _(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function E(e,t,r){var n=x(r),i="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(i+="?".concat(n)),i}function x(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function O(e){return e.map((function(e){return w(e)}))}function w(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var N=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===l.WithinHeaders?n:{}},queryParameters:function(){return e===l.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:l.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,s=e.responsesCache,c=e.timeouts,u=e.userAgent,o=e.hosts,h=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:s,timeouts:c,userAgent:u,headers:e.headers,queryParameters:h,hosts:o.map((function(e){return R(e)})),read:function(e,t){var r=m(t,f.timeouts.read),n=function(){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=i(e,2);return t[0],t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return j(f,f.hosts.filter((function(e){return 0!=(e.accept&d.Write)})),e,m(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:d.Read},{url:"".concat(t,".algolia.net"),accept:d.Write}].concat(o([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return h({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},A=function(e){return function(t,r){return t.method===F?e.transporter.read(t,r):e.transporter.write(t,r)}},H=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return h({transporter:e.transporter,appId:e.appId,indexName:t},r.methods)}},S=function(e){return function(t,n){var i=t.map((function(e){return r(r({},e),{},{params:x(e.params||{})})}));return e.transporter.read({method:b,path:"1/indexes/*/queries",data:{requests:i},cacheable:!0},n)}},T=function(e){return function(t,i){return Promise.all(t.map((function(t){var a=t.params,s=a.facetName,c=a.facetQuery,u=n(a,["facetName","facetQuery"]);return H(e)(t.indexName,{methods:{searchForFacetValues:I}}).searchForFacetValues(s,c,r(r({},i),u))})))}},Q=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},C=function(e){return function(t,r){return e.transporter.read({method:b,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},I=function(e){return function(t,r,n){return e.transporter.read({method:b,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},k=1,D=2,q=3;function V(e,t,n){var i,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,i=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=i(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=i(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(i=q,{debug:function(e,t){return k>=i&&console.debug(e,t),Promise.resolve()},info:function(e,t){return D>=i&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:u(),requestsCache:u({serializable:!1}),hostsCache:c({caches:[s({key:"".concat("4.20.0","-").concat(e)}),u()]}),userAgent:_("4.20.0").add({segment:"Browser",version:"lite"}),authMode:l.WithinQueryParameters};return N(r(r(r({},a),n),{},{methods:{search:S,searchForFacetValues:T,multipleQueries:S,multipleSearchForFacetValues:T,customRequest:A,initIndex:function(e){return function(t){return H(e)(t,{methods:{search:C,searchForFacetValues:I,findAnswers:Q}})}}}}))}return V.version="4.20.0",V}()},6675:(e,t,r)=>{"use strict";r.r(t),r.d(t,{default:()=>A});var n=r(7294),i=r(6010),a=r(8131),s=r.n(a),c=r(290),u=r.n(c),o=r(412),h=r(5742),f=r(9960),l=r(143),m=r(2263);const d=["zero","one","two","few","many","other"];function p(e){return d.filter((t=>e.includes(t)))}const v={locale:"en",pluralForms:p(["one","other"]),select:e=>1===e?"one":"other"};function g(){const{i18n:{currentLocale:e}}=(0,m.Z)();return(0,n.useMemo)((()=>{try{return function(e){const t=new Intl.PluralRules(e);return{locale:e,pluralForms:p(t.resolvedOptions().pluralCategories),select:e=>t.select(e)}}(e)}catch(t){return console.error(`Failed to use Intl.PluralRules for locale "${e}".\nDocusaurus will fallback to the default (English) implementation.\nError: ${t.message}\n`),v}}),[e])}function y(){const e=g();return{selectMessage:(t,r)=>function(e,t,r){const n=e.split("|");if(1===n.length)return n[0];n.length>r.pluralForms.length&&console.error(`For locale=${r.locale}, a maximum of ${r.pluralForms.length} plural forms are expected (${r.pluralForms.join(",")}), but the message contains ${n.length}: ${e}`);const i=r.select(t),a=r.pluralForms.indexOf(i);return n[Math.min(a,n.length-1)]}(r,t,e)}}var R=r(6177),F=r(902),b=r(833),P=r(2128),j=r(5999),_=r(6278),E=r(239),x=r(7452);const O={searchQueryInput:"searchQueryInput_u2C7",searchVersionInput:"searchVersionInput_m0Ui",searchResultsColumn:"searchResultsColumn_JPFH",algoliaLogo:"algoliaLogo_rT1R",algoliaLogoPathFill:"algoliaLogoPathFill_WdUC",searchResultItem:"searchResultItem_Tv2o",searchResultItemHeading:"searchResultItemHeading_KbCB",searchResultItemPath:"searchResultItemPath_lhe1",searchResultItemSummary:"searchResultItemSummary_AEaO",searchQueryColumn:"searchQueryColumn_RTkw",searchVersionColumn:"searchVersionColumn_ypXd",searchLogoColumn:"searchLogoColumn_rJIA",loadingSpinner:"loadingSpinner_XVxU","loading-spin":"loading-spin_vzvp",loader:"loader_vvXV"};function w(e){let{docsSearchVersionsHelpers:t}=e;const r=Object.entries(t.allDocsData).filter((e=>{let[,t]=e;return t.versions.length>1}));return n.createElement("div",{className:(0,i.Z)("col","col--3","padding-left--none",O.searchVersionColumn)},r.map((e=>{let[i,a]=e;const s=r.length>1?`${i}: `:"";return n.createElement("select",{key:i,onChange:e=>t.setSearchVersion(i,e.target.value),defaultValue:t.searchVersions[i],className:O.searchVersionInput},a.versions.map(((e,t)=>n.createElement("option",{key:t,label:`${s}${e.label}`,value:e.name}))))})))}function N(){const{i18n:{currentLocale:e}}=(0,m.Z)(),{algolia:{appId:t,apiKey:r,indexName:a}}=(0,_.L)(),c=(0,E.l)(),d=function(){const{selectMessage:e}=y();return t=>e(t,(0,j.I)({id:"theme.SearchPage.documentsFound.plurals",description:'Pluralized label for "{count} documents found". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',message:"One document found|{count} documents found"},{count:t}))}(),p=function(){const e=(0,l._r)(),[t,r]=(0,n.useState)((()=>Object.entries(e).reduce(((e,t)=>{let[r,n]=t;return{...e,[r]:n.versions[0].name}}),{}))),i=Object.values(e).some((e=>e.versions.length>1));return{allDocsData:e,versioningEnabled:i,searchVersions:t,setSearchVersion:(e,t)=>r((r=>({...r,[e]:t})))}}(),[v,g]=(0,R.K)(),b={items:[],query:null,totalResults:null,totalPages:null,lastPage:null,hasMore:null,loading:null},[N,A]=(0,n.useReducer)(((e,t)=>{switch(t.type){case"reset":return b;case"loading":return{...e,loading:!0};case"update":return v!==t.value.query?e:{...t.value,items:0===t.value.lastPage?t.value.items:e.items.concat(t.value.items)};case"advance":{const t=e.totalPages>e.lastPage+1;return{...e,lastPage:t?e.lastPage+1:e.lastPage,hasMore:t}}default:return e}}),b),H=u()(t,r),S=s()(H,a,{hitsPerPage:15,advancedSyntax:!0,disjunctiveFacets:["language","docusaurus_tag"]});S.on("result",(e=>{let{results:{query:t,hits:r,page:n,nbHits:i,nbPages:a}}=e;if(""===t||!Array.isArray(r))return void A({type:"reset"});const s=e=>e.replace(/algolia-docsearch-suggestion--highlight/g,"search-result-match"),u=r.map((e=>{let{url:t,_highlightResult:{hierarchy:r},_snippetResult:n={}}=e;const i=Object.keys(r).map((e=>s(r[e].value)));return{title:i.pop(),url:c(t),summary:n.content?`${s(n.content.value)}...`:"",breadcrumbs:i}}));A({type:"update",value:{items:u,query:t,totalResults:i,totalPages:a,lastPage:n,hasMore:a>n+1,loading:!1}})}));const[T,Q]=(0,n.useState)(null),C=(0,n.useRef)(0),I=(0,n.useRef)(o.Z.canUseIntersectionObserver&&new IntersectionObserver((e=>{const{isIntersecting:t,boundingClientRect:{y:r}}=e[0];t&&C.current>r&&A({type:"advance"}),C.current=r}),{threshold:1})),k=()=>v?(0,j.I)({id:"theme.SearchPage.existingResultsTitle",message:'Search results for "{query}"',description:"The search page title for non-empty query"},{query:v}):(0,j.I)({id:"theme.SearchPage.emptyResultsTitle",message:"Search the documentation",description:"The search page title for empty query"}),D=(0,F.zX)((function(t){void 0===t&&(t=0),S.addDisjunctiveFacetRefinement("docusaurus_tag","default"),S.addDisjunctiveFacetRefinement("language",e),Object.entries(p.searchVersions).forEach((e=>{let[t,r]=e;S.addDisjunctiveFacetRefinement("docusaurus_tag",`docs-${t}-${r}`)})),S.setQuery(v).setPage(t).search()}));return(0,n.useEffect)((()=>{if(!T)return;const e=I.current;return e?(e.observe(T),()=>e.unobserve(T)):()=>!0}),[T]),(0,n.useEffect)((()=>{A({type:"reset"}),v&&(A({type:"loading"}),setTimeout((()=>{D()}),300))}),[v,p.searchVersions,D]),(0,n.useEffect)((()=>{N.lastPage&&0!==N.lastPage&&D(N.lastPage)}),[D,N.lastPage]),n.createElement(x.Z,null,n.createElement(h.Z,null,n.createElement("title",null,(0,P.p)(k())),n.createElement("meta",{property:"robots",content:"noindex, follow"})),n.createElement("div",{className:"container margin-vert--lg"},n.createElement("h1",null,k()),n.createElement("form",{className:"row",onSubmit:e=>e.preventDefault()},n.createElement("div",{className:(0,i.Z)("col",O.searchQueryColumn,{"col--9":p.versioningEnabled,"col--12":!p.versioningEnabled})},n.createElement("input",{type:"search",name:"q",className:O.searchQueryInput,placeholder:(0,j.I)({id:"theme.SearchPage.inputPlaceholder",message:"Type your search here",description:"The placeholder for search page input"}),"aria-label":(0,j.I)({id:"theme.SearchPage.inputLabel",message:"Search",description:"The ARIA label for search page input"}),onChange:e=>g(e.target.value),value:v,autoComplete:"off",autoFocus:!0})),p.versioningEnabled&&n.createElement(w,{docsSearchVersionsHelpers:p})),n.createElement("div",{className:"row"},n.createElement("div",{className:(0,i.Z)("col","col--8",O.searchResultsColumn)},!!N.totalResults&&d(N.totalResults)),n.createElement("div",{className:(0,i.Z)("col","col--4","text--right",O.searchLogoColumn)},n.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://www.algolia.com/","aria-label":(0,j.I)({id:"theme.SearchPage.algoliaLabel",message:"Search by Algolia",description:"The ARIA label for Algolia mention"})},n.createElement("svg",{viewBox:"0 0 168 24",className:O.algoliaLogo},n.createElement("g",{fill:"none"},n.createElement("path",{className:O.algoliaLogoPathFill,d:"M120.925 18.804c-4.386.02-4.386-3.54-4.386-4.106l-.007-13.336 2.675-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-10.846-2.18c.821 0 1.43-.047 1.855-.129v-2.719a6.334 6.334 0 0 0-1.574-.199 5.7 5.7 0 0 0-.897.069 2.699 2.699 0 0 0-.814.24c-.24.116-.439.28-.582.491-.15.212-.219.335-.219.656 0 .628.219.991.616 1.23s.938.362 1.615.362zm-.233-9.7c.883 0 1.629.109 2.231.328.602.218 1.088.525 1.444.915.363.396.609.922.76 1.483.157.56.232 1.175.232 1.85v6.874a32.5 32.5 0 0 1-1.868.314c-.834.123-1.772.185-2.813.185-.69 0-1.327-.069-1.895-.198a4.001 4.001 0 0 1-1.471-.636 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.803 0-.656.13-1.073.384-1.525a3.24 3.24 0 0 1 1.047-1.106c.445-.287.95-.492 1.532-.615a8.8 8.8 0 0 1 1.82-.185 8.404 8.404 0 0 1 1.972.24v-.438c0-.307-.035-.6-.11-.874a1.88 1.88 0 0 0-.384-.73 1.784 1.784 0 0 0-.724-.493 3.164 3.164 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.735 7.735 0 0 0-1.26.307l-.321-2.192c.335-.117.834-.233 1.478-.349a10.98 10.98 0 0 1 2.073-.178zm52.842 9.626c.822 0 1.43-.048 1.854-.13V13.7a6.347 6.347 0 0 0-1.574-.199c-.294 0-.595.021-.896.069a2.7 2.7 0 0 0-.814.24 1.46 1.46 0 0 0-.582.491c-.15.212-.218.335-.218.656 0 .628.218.991.615 1.23.404.245.938.362 1.615.362zm-.226-9.694c.883 0 1.629.108 2.231.327.602.219 1.088.526 1.444.915.355.39.609.923.759 1.483a6.8 6.8 0 0 1 .233 1.852v6.873c-.41.088-1.034.19-1.868.314-.834.123-1.772.184-2.813.184-.69 0-1.327-.068-1.895-.198a4.001 4.001 0 0 1-1.471-.635 3.085 3.085 0 0 1-.951-1.134c-.226-.465-.343-1.12-.343-1.804 0-.656.13-1.073.384-1.524.26-.45.608-.82 1.047-1.107.445-.286.95-.491 1.532-.614a8.803 8.803 0 0 1 2.751-.13c.329.034.671.096 1.04.185v-.437a3.3 3.3 0 0 0-.109-.875 1.873 1.873 0 0 0-.384-.731 1.784 1.784 0 0 0-.724-.492 3.165 3.165 0 0 0-1.143-.205c-.616 0-1.177.075-1.69.164a7.75 7.75 0 0 0-1.26.307l-.321-2.193c.335-.116.834-.232 1.478-.348a11.633 11.633 0 0 1 2.073-.177zm-8.034-1.271a1.626 1.626 0 0 1-1.628-1.62c0-.895.725-1.62 1.628-1.62.904 0 1.63.725 1.63 1.62 0 .895-.733 1.62-1.63 1.62zm1.348 13.22h-2.689V7.27l2.69-.423v11.956zm-4.714 0c-4.386.02-4.386-3.54-4.386-4.107l-.008-13.336 2.676-.424v13.254c0 .322 0 2.358 1.718 2.364v2.248zm-8.698-5.903c0-1.156-.253-2.119-.746-2.788-.493-.677-1.183-1.01-2.067-1.01-.882 0-1.574.333-2.065 1.01-.493.676-.733 1.632-.733 2.788 0 1.168.246 1.953.74 2.63.492.683 1.183 1.018 2.066 1.018.882 0 1.574-.342 2.067-1.019.492-.683.738-1.46.738-2.63zm2.737-.007c0 .902-.13 1.584-.397 2.33a5.52 5.52 0 0 1-1.128 1.906 4.986 4.986 0 0 1-1.752 1.223c-.685.286-1.739.45-2.265.45-.528-.006-1.574-.157-2.252-.45a5.096 5.096 0 0 1-1.744-1.223c-.487-.527-.863-1.162-1.137-1.906a6.345 6.345 0 0 1-.41-2.33c0-.902.123-1.77.397-2.508a5.554 5.554 0 0 1 1.15-1.892 5.133 5.133 0 0 1 1.75-1.216c.679-.287 1.425-.423 2.232-.423.808 0 1.553.142 2.237.423a4.88 4.88 0 0 1 1.753 1.216 5.644 5.644 0 0 1 1.135 1.892c.287.738.431 1.606.431 2.508zm-20.138 0c0 1.12.246 2.363.738 2.882.493.52 1.13.78 1.91.78.424 0 .828-.062 1.204-.178.377-.116.677-.253.917-.417V9.33a10.476 10.476 0 0 0-1.766-.226c-.971-.028-1.71.37-2.23 1.004-.513.636-.773 1.75-.773 2.788zm7.438 5.274c0 1.824-.466 3.156-1.404 4.004-.936.846-2.367 1.27-4.296 1.27-.705 0-2.17-.137-3.34-.396l.431-2.118c.98.205 2.272.26 2.95.26 1.074 0 1.84-.219 2.299-.656.459-.437.684-1.086.684-1.948v-.437a8.07 8.07 0 0 1-1.047.397c-.43.13-.93.198-1.492.198-.739 0-1.41-.116-2.018-.349a4.206 4.206 0 0 1-1.567-1.025c-.431-.45-.774-1.017-1.013-1.694-.24-.677-.363-1.885-.363-2.773 0-.834.13-1.88.384-2.577.26-.696.629-1.298 1.129-1.796.493-.498 1.095-.881 1.8-1.162a6.605 6.605 0 0 1 2.428-.457c.87 0 1.67.109 2.45.24.78.129 1.444.265 1.985.415V18.17zM6.972 6.677v1.627c-.712-.446-1.52-.67-2.425-.67-.585 0-1.045.13-1.38.391a1.24 1.24 0 0 0-.502 1.03c0 .425.164.765.494 1.02.33.256.835.532 1.516.83.447.192.795.356 1.045.495.25.138.537.332.862.582.324.25.563.548.718.894.154.345.23.741.23 1.188 0 .947-.334 1.691-1.004 2.234-.67.542-1.537.814-2.601.814-1.18 0-2.16-.229-2.936-.686v-1.708c.84.628 1.814.942 2.92.942.585 0 1.048-.136 1.388-.407.34-.271.51-.646.51-1.125 0-.287-.1-.55-.302-.79-.203-.24-.42-.42-.655-.542-.234-.123-.585-.29-1.053-.503a61.27 61.27 0 0 1-.582-.271 13.67 13.67 0 0 1-.55-.287 4.275 4.275 0 0 1-.567-.351 6.92 6.92 0 0 1-.455-.4c-.18-.17-.31-.34-.39-.51-.08-.17-.155-.37-.224-.598a2.553 2.553 0 0 1-.104-.742c0-.915.333-1.638.998-2.17.664-.532 1.523-.798 2.576-.798.968 0 1.793.17 2.473.51zm7.468 5.696v-.287c-.022-.607-.187-1.088-.495-1.444-.309-.357-.75-.535-1.324-.535-.532 0-.99.194-1.373.583-.382.388-.622.949-.717 1.683h3.909zm1.005 2.792v1.404c-.596.34-1.383.51-2.362.51-1.255 0-2.255-.377-3-1.132-.744-.755-1.116-1.744-1.116-2.968 0-1.297.34-2.316 1.021-3.055.68-.74 1.548-1.11 2.6-1.11 1.033 0 1.852.323 2.458.966.606.644.91 1.572.91 2.784 0 .33-.033.676-.096 1.038h-5.314c.107.702.405 1.239.894 1.611.49.372 1.106.558 1.85.558.862 0 1.58-.202 2.155-.606zm6.605-1.77h-1.212c-.596 0-1.045.116-1.349.35-.303.234-.454.532-.454.894 0 .372.117.664.35.877.235.213.575.32 1.022.32.51 0 .912-.142 1.204-.424.293-.281.44-.651.44-1.108v-.91zm-4.068-2.554V9.325c.627-.361 1.457-.542 2.489-.542 2.116 0 3.175 1.026 3.175 3.08V17h-1.548v-.957c-.415.68-1.143 1.02-2.186 1.02-.766 0-1.38-.22-1.843-.661-.462-.442-.694-1.003-.694-1.684 0-.776.293-1.38.878-1.81.585-.431 1.404-.647 2.457-.647h1.34V11.8c0-.554-.133-.971-.399-1.253-.266-.282-.707-.423-1.324-.423a4.07 4.07 0 0 0-2.345.718zm9.333-1.93v1.42c.394-1 1.101-1.5 2.123-1.5.148 0 .313.016.494.048v1.531a1.885 1.885 0 0 0-.75-.143c-.542 0-.989.24-1.34.718-.351.479-.527 1.048-.527 1.707V17h-1.563V8.91h1.563zm5.01 4.084c.022.82.272 1.492.75 2.019.479.526 1.15.79 2.01.79.639 0 1.235-.176 1.788-.527v1.404c-.521.319-1.186.479-1.995.479-1.265 0-2.276-.4-3.031-1.197-.755-.798-1.133-1.792-1.133-2.984 0-1.16.38-2.151 1.14-2.975.761-.825 1.79-1.237 3.088-1.237.702 0 1.346.149 1.93.447v1.436a3.242 3.242 0 0 0-1.77-.495c-.84 0-1.513.266-2.019.798-.505.532-.758 1.213-.758 2.042zM40.24 5.72v4.579c.458-1 1.293-1.5 2.505-1.5.787 0 1.42.245 1.899.734.479.49.718 1.17.718 2.042V17h-1.564v-5.106c0-.553-.14-.98-.422-1.284-.282-.303-.652-.455-1.11-.455-.531 0-1.002.202-1.411.606-.41.405-.615 1.022-.615 1.851V17h-1.563V5.72h1.563zm14.966 10.02c.596 0 1.096-.253 1.5-.758.404-.506.606-1.157.606-1.955 0-.915-.202-1.62-.606-2.114-.404-.495-.92-.742-1.548-.742-.553 0-1.05.224-1.491.67-.442.447-.662 1.133-.662 2.058 0 .958.212 1.67.638 2.138.425.469.946.703 1.563.703zM53.004 5.72v4.42c.574-.894 1.388-1.341 2.44-1.341 1.022 0 1.857.383 2.506 1.149.649.766.973 1.781.973 3.047 0 1.138-.309 2.109-.925 2.912-.617.803-1.463 1.205-2.537 1.205-1.075 0-1.894-.447-2.457-1.34V17h-1.58V5.72h1.58zm9.908 11.104l-3.223-7.913h1.739l1.005 2.632 1.26 3.415c.096-.32.48-1.458 1.15-3.415l.909-2.632h1.66l-2.92 7.866c-.777 2.074-1.963 3.11-3.559 3.11a2.92 2.92 0 0 1-.734-.079v-1.34c.17.042.351.064.543.064 1.032 0 1.755-.57 2.17-1.708z"}),n.createElement("path",{fill:"#5468FF",d:"M78.988.938h16.594a2.968 2.968 0 0 1 2.966 2.966V20.5a2.967 2.967 0 0 1-2.966 2.964H78.988a2.967 2.967 0 0 1-2.966-2.964V3.897A2.961 2.961 0 0 1 78.988.938z"}),n.createElement("path",{fill:"white",d:"M89.632 5.967v-.772a.978.978 0 0 0-.978-.977h-2.28a.978.978 0 0 0-.978.977v.793c0 .088.082.15.171.13a7.127 7.127 0 0 1 1.984-.28c.65 0 1.295.088 1.917.259.082.02.164-.04.164-.13m-6.248 1.01l-.39-.389a.977.977 0 0 0-1.382 0l-.465.465a.973.973 0 0 0 0 1.38l.383.383c.062.061.15.047.205-.014.226-.307.472-.601.746-.874.281-.28.568-.526.883-.751.068-.042.075-.137.02-.2m4.16 2.453v3.341c0 .096.104.165.192.117l2.97-1.537c.068-.034.089-.117.055-.184a3.695 3.695 0 0 0-3.08-1.866c-.068 0-.136.054-.136.13m0 8.048a4.489 4.489 0 0 1-4.49-4.482 4.488 4.488 0 0 1 4.49-4.482 4.488 4.488 0 0 1 4.489 4.482 4.484 4.484 0 0 1-4.49 4.482m0-10.85a6.363 6.363 0 1 0 0 12.729 6.37 6.37 0 0 0 6.372-6.368 6.358 6.358 0 0 0-6.371-6.36"})))))),N.items.length>0?n.createElement("main",null,N.items.map(((e,t)=>{let{title:r,url:a,summary:s,breadcrumbs:c}=e;return n.createElement("article",{key:t,className:O.searchResultItem},n.createElement("h2",{className:O.searchResultItemHeading},n.createElement(f.Z,{to:a,dangerouslySetInnerHTML:{__html:r}})),c.length>0&&n.createElement("nav",{"aria-label":"breadcrumbs"},n.createElement("ul",{className:(0,i.Z)("breadcrumbs",O.searchResultItemPath)},c.map(((e,t)=>n.createElement("li",{key:t,className:"breadcrumbs__item",dangerouslySetInnerHTML:{__html:e}}))))),s&&n.createElement("p",{className:O.searchResultItemSummary,dangerouslySetInnerHTML:{__html:s}}))}))):[v&&!N.loading&&n.createElement("p",{key:"no-results"},n.createElement(j.Z,{id:"theme.SearchPage.noResultsText",description:"The paragraph for empty search result"},"No results were found")),!!N.loading&&n.createElement("div",{key:"spinner",className:O.loadingSpinner})],N.hasMore&&n.createElement("div",{className:O.loader,ref:Q},n.createElement(j.Z,{id:"theme.SearchPage.fetchingNewResults",description:"The paragraph for fetching new search results"},"Fetching new results..."))))}function A(){return n.createElement(b.FG,{className:"search-page-wrapper"},n.createElement(N,null))}}}]); \ No newline at end of file diff --git a/assets/js/1a4e3797.ca05490f.js.LICENSE.txt b/assets/js/1a4e3797.ca05490f.js.LICENSE.txt deleted file mode 100644 index 8c17e740e..000000000 --- a/assets/js/1a4e3797.ca05490f.js.LICENSE.txt +++ /dev/null @@ -1 +0,0 @@ -/*! algoliasearch-lite.umd.js | 4.20.0 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */ diff --git a/assets/js/1be78505.fb48f26a.js b/assets/js/1be78505.fb48f26a.js deleted file mode 100644 index cf17297c5..000000000 --- a/assets/js/1be78505.fb48f26a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[514,972],{9963:(e,t,n)=>{n.r(t),n.d(t,{default:()=>ge});var a=n(7294),o=n(6010),l=n(833),r=n(5281),c=n(3320),i=n(3438),s=n(4477),d=n(1116),m=n(7452),u=n(5999),b=n(2466),p=n(5936);const h={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};function E(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,o]=(0,a.useState)(!1),l=(0,a.useRef)(!1),{startScroll:r,cancelScroll:c}=(0,b.Ct)();return(0,b.RF)(((e,n)=>{let{scrollY:a}=e;const r=n?.scrollY;r&&(l.current?l.current=!1:a>=r?(c(),o(!1)):a<t?o(!1):a+window.innerHeight<document.documentElement.scrollHeight&&o(!0))})),(0,p.S)((e=>{e.location.hash&&(l.current=!0,o(!1))})),{shown:n,scrollToTop:()=>r(0)}}({threshold:300});return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,o.Z)("clean-btn",r.k.common.backToTopButton,h.backToTopButton,e&&h.backToTopButtonShow),type:"button",onClick:t})}var f=n(1442),g=n(6550),v=n(7524),k=n(6668),_=n(1327),C=n(7462);function S(e){return a.createElement("svg",(0,C.Z)({width:"20",height:"20","aria-hidden":"true"},e),a.createElement("g",{fill:"#7a7a7a"},a.createElement("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),a.createElement("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})))}const I={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function N(e){let{onClick:t}=e;return a.createElement("button",{type:"button",title:(0,u.I)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,o.Z)("button button--secondary button--outline",I.collapseSidebarButton),onClick:t},a.createElement(S,{className:I.collapseSidebarButtonIcon}))}var T=n(9689),x=n(902);const Z=Symbol("EmptyContext"),B=a.createContext(Z);function y(e){let{children:t}=e;const[n,o]=(0,a.useState)(null),l=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:o})),[n]);return a.createElement(B.Provider,{value:l},t)}var w=n(6043),L=n(8596),A=n(9960),M=n(2389);function F(e){let{categoryLabel:t,onClick:n}=e;return a.createElement("button",{"aria-label":(0,u.I)({id:"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel",message:"Toggle the collapsible sidebar category '{label}'",description:"The ARIA label to toggle the collapsible sidebar category"},{label:t}),type:"button",className:"clean-btn menu__caret",onClick:n})}function H(e){let{item:t,onItemClick:n,activePath:l,level:c,index:s,...d}=e;const{items:m,label:u,collapsible:b,className:p,href:h}=t,{docs:{sidebar:{autoCollapseCategories:E}}}=(0,k.L)(),f=function(e){const t=(0,M.Z)();return(0,a.useMemo)((()=>e.href?e.href:!t&&e.collapsible?(0,i.Wl)(e):void 0),[e,t])}(t),g=(0,i._F)(t,l),v=(0,L.Mg)(h,l),{collapsed:_,setCollapsed:S}=(0,w.u)({initialState:()=>!!b&&(!g&&t.collapsed)}),{expandedItem:I,setExpandedItem:N}=function(){const e=(0,a.useContext)(B);if(e===Z)throw new x.i6("DocSidebarItemsExpandedStateProvider");return e}(),T=function(e){void 0===e&&(e=!_),N(e?null:s),S(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:o}=e;const l=(0,x.D9)(t);(0,a.useEffect)((()=>{t&&!l&&n&&o(!1)}),[t,l,n,o])}({isActive:g,collapsed:_,updateCollapsed:T}),(0,a.useEffect)((()=>{b&&null!=I&&I!==s&&E&&S(!0)}),[b,I,s,S,E]),a.createElement("li",{className:(0,o.Z)(r.k.docs.docSidebarItemCategory,r.k.docs.docSidebarItemCategoryLevel(c),"menu__list-item",{"menu__list-item--collapsed":_},p)},a.createElement("div",{className:(0,o.Z)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":v})},a.createElement(A.Z,(0,C.Z)({className:(0,o.Z)("menu__link",{"menu__link--sublist":b,"menu__link--sublist-caret":!h&&b,"menu__link--active":g}),onClick:b?e=>{n?.(t),h?T(!1):(e.preventDefault(),T())}:()=>{n?.(t)},"aria-current":v?"page":void 0,"aria-expanded":b?!_:void 0,href:b?f??"#":f},d),u),h&&b&&a.createElement(F,{categoryLabel:u,onClick:e=>{e.preventDefault(),T()}})),a.createElement(w.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:_},a.createElement(j,{items:m,tabIndex:_?-1:0,onItemClick:n,activePath:l,level:c+1})))}var P=n(3919),W=n(9471);const D={menuExternalLink:"menuExternalLink_NmtK"};function R(e){let{item:t,onItemClick:n,activePath:l,level:c,index:s,...d}=e;const{href:m,label:u,className:b,autoAddBaseUrl:p}=t,h=(0,i._F)(t,l),E=(0,P.Z)(m);return a.createElement("li",{className:(0,o.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(c),"menu__list-item",b),key:u},a.createElement(A.Z,(0,C.Z)({className:(0,o.Z)("menu__link",!E&&D.menuExternalLink,{"menu__link--active":h}),autoAddBaseUrl:p,"aria-current":h?"page":void 0,to:m},E&&{onClick:n?()=>n(t):void 0},d),u,!E&&a.createElement(W.Z,null)))}const V={menuHtmlItem:"menuHtmlItem_M9Kj"};function U(e){let{item:t,level:n,index:l}=e;const{value:c,defaultStyle:i,className:s}=t;return a.createElement("li",{className:(0,o.Z)(r.k.docs.docSidebarItemLink,r.k.docs.docSidebarItemLinkLevel(n),i&&[V.menuHtmlItem,"menu__list-item"],s),key:l,dangerouslySetInnerHTML:{__html:c}})}function z(e){let{item:t,...n}=e;switch(t.type){case"category":return a.createElement(H,(0,C.Z)({item:t},n));case"html":return a.createElement(U,(0,C.Z)({item:t},n));default:return a.createElement(R,(0,C.Z)({item:t},n))}}function K(e){let{items:t,...n}=e;return a.createElement(y,null,t.map(((e,t)=>a.createElement(z,(0,C.Z)({key:t,item:e,index:t},n)))))}const j=(0,a.memo)(K),q={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function G(e){let{path:t,sidebar:n,className:l}=e;const c=function(){const{isActive:e}=(0,T.nT)(),[t,n]=(0,a.useState)(e);return(0,b.RF)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return a.createElement("nav",{"aria-label":(0,u.I)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,o.Z)("menu thin-scrollbar",q.menu,c&&q.menuWithAnnouncementBar,l)},a.createElement("ul",{className:(0,o.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(j,{items:n,activePath:t,level:1})))}const Y="sidebar_njMd",O="sidebarWithHideableNavbar_wUlq",X="sidebarHidden_VK0M",J="sidebarLogo_isFc";function Q(e){let{path:t,sidebar:n,onCollapse:l,isHidden:r}=e;const{navbar:{hideOnScroll:c},docs:{sidebar:{hideable:i}}}=(0,k.L)();return a.createElement("div",{className:(0,o.Z)(Y,c&&O,r&&X)},c&&a.createElement(_.Z,{tabIndex:-1,className:J}),a.createElement(G,{path:t,sidebar:n}),i&&a.createElement(N,{onClick:l}))}const $=a.memo(Q);var ee=n(3102),te=n(3163);const ne=e=>{let{sidebar:t,path:n}=e;const l=(0,te.e)();return a.createElement("ul",{className:(0,o.Z)(r.k.docs.docSidebarMenu,"menu__list")},a.createElement(j,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&l.toggle(),"link"===e.type&&l.toggle()},level:1}))};function ae(e){return a.createElement(ee.Zo,{component:ne,props:e})}const oe=a.memo(ae);function le(e){const t=(0,v.i)(),n="desktop"===t||"ssr"===t,o="mobile"===t;return a.createElement(a.Fragment,null,n&&a.createElement($,e),o&&a.createElement(oe,e))}const re={expandButton:"expandButton_m80_",expandButtonIcon:"expandButtonIcon_BlDH"};function ce(e){let{toggleSidebar:t}=e;return a.createElement("div",{className:re.expandButton,title:(0,u.I)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,u.I)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t},a.createElement(S,{className:re.expandButtonIcon}))}const ie={docSidebarContainer:"docSidebarContainer_b6E3",docSidebarContainerHidden:"docSidebarContainerHidden_b3ry",sidebarViewport:"sidebarViewport_Xe31"};function se(e){let{children:t}=e;const n=(0,d.V)();return a.createElement(a.Fragment,{key:n?.name??"noSidebar"},t)}function de(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:l}=e;const{pathname:c}=(0,g.TH)(),[i,s]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{i&&s(!1),!i&&(0,f.n)()&&s(!0),l((e=>!e))}),[l,i]);return a.createElement("aside",{className:(0,o.Z)(r.k.docs.docSidebarContainer,ie.docSidebarContainer,n&&ie.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ie.docSidebarContainer)&&n&&s(!0)}},a.createElement(se,null,a.createElement("div",{className:(0,o.Z)(ie.sidebarViewport,i&&ie.sidebarViewportHidden)},a.createElement(le,{sidebar:t,path:c,onCollapse:d,isHidden:i}),i&&a.createElement(ce,{toggleSidebar:d}))))}const me={docMainContainer:"docMainContainer_gTbr",docMainContainerEnhanced:"docMainContainerEnhanced_Uz_u",docItemWrapperEnhanced:"docItemWrapperEnhanced_czyv"};function ue(e){let{hiddenSidebarContainer:t,children:n}=e;const l=(0,d.V)();return a.createElement("main",{className:(0,o.Z)(me.docMainContainer,(t||!l)&&me.docMainContainerEnhanced)},a.createElement("div",{className:(0,o.Z)("container padding-top--md padding-bottom--lg",me.docItemWrapper,t&&me.docItemWrapperEnhanced)},n))}const be={docPage:"docPage__5DB",docsWrapper:"docsWrapper_BCFX","themedComponent--light":"themedComponent--light_NU7w"};function pe(e){let{children:t}=e;const n=(0,d.V)(),[o,l]=(0,a.useState)(!1);return a.createElement(m.Z,{wrapperClassName:be.docsWrapper},a.createElement(E,null),a.createElement("div",{className:be.docPage},n&&a.createElement(de,{sidebar:n.items,hiddenSidebarContainer:o,setHiddenSidebarContainer:l}),a.createElement(ue,{hiddenSidebarContainer:o},t)))}var he=n(4972),Ee=n(197);function fe(e){const{versionMetadata:t}=e;return a.createElement(a.Fragment,null,a.createElement(Ee.Z,{version:t.version,tag:(0,c.os)(t.pluginId,t.version)}),a.createElement(l.d,null,t.noIndex&&a.createElement("meta",{name:"robots",content:"noindex, nofollow"})))}function ge(e){const{versionMetadata:t}=e,n=(0,i.hI)(e);if(!n)return a.createElement(he.default,null);const{docElement:c,sidebarName:m,sidebarItems:u}=n;return a.createElement(a.Fragment,null,a.createElement(fe,e),a.createElement(l.FG,{className:(0,o.Z)(r.k.wrapper.docsPages,r.k.page.docsDocPage,e.versionMetadata.className)},a.createElement(s.q,{version:t},a.createElement(d.b,{name:m,items:u},a.createElement(pe,null,c)))))}},4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>c});var a=n(7294),o=n(5999),l=n(833),r=n(7452);function c(){return a.createElement(a.Fragment,null,a.createElement(l.d,{title:(0,o.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(o.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}},4477:(e,t,n)=>{n.d(t,{E:()=>c,q:()=>r});var a=n(7294),o=n(902);const l=a.createContext(null);function r(e){let{children:t,version:n}=e;return a.createElement(l.Provider,{value:n},t)}function c(){const e=(0,a.useContext)(l);if(null===e)throw new o.i6("DocsVersionProvider");return e}}}]); \ No newline at end of file diff --git a/assets/js/21dc2778.95e24d3c.js b/assets/js/21dc2778.95e24d3c.js new file mode 100644 index 000000000..5ce32c14e --- /dev/null +++ b/assets/js/21dc2778.95e24d3c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[295],{6807:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>x,contentTitle:()=>m,default:()=>g,frontMatter:()=>h,metadata:()=>u,toc:()=>p});var l=i(4848),t=i(8453),s=i(6684),d=i(2364),a=i(9365),o=i(1470),r=i(7324),c=i(6694);const h={sidebar_position:2,sidebar_label:"Migrations",description:"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems.",keywords:["c++ orm","database","migrations","tinyorm"]},m="Database: Migrations",u={id:"database/migrations",title:"Database: Migrations",description:"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems.",source:"@site/docs/database/migrations.mdx",sourceDirName:"database",slug:"/database/migrations",permalink:"/database/migrations",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Migrations",description:"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems.",keywords:["c++ orm","database","migrations","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Query Builder",permalink:"/database/query-builder"},next:{title:"Seeding",permalink:"/database/seeding"}},x={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Generating Migrations",id:"generating-migrations",level:2},{value:"Migrations naming rules",id:"migrations-naming-rules",level:4},{value:"Tab completion",id:"tab-completion",level:2},{value:"Alternative installation methods",id:"alternative-installation-methods",level:3},{value:"Static installation",id:"static-installation",level:4},{value:"Dynamic installation",id:"dynamic-installation",level:4},{value:"Migration Structure",id:"migration-structure",level:2},{value:"Setting The Migration Connection",id:"setting-the-migration-connection",level:4},{value:"Running Migrations",id:"running-migrations",level:2},{value:"Forcing Migrations To Run In Production",id:"forcing-migrations-to-run-in-production",level:4},{value:"Rolling Back Migrations",id:"rolling-back-migrations",level:3},{value:"Roll Back & Migrate Using A Single Command",id:"roll-back--migrate-using-a-single-command",level:4},{value:"Drop All Tables & Migrate",id:"drop-all-tables--migrate",level:4},{value:"Tables",id:"tables",level:2},{value:"Creating Tables",id:"creating-tables",level:3},{value:"Checking For Table / Column Existence",id:"checking-for-table--column-existence",level:4},{value:"Database Connection & Table Options",id:"database-connection--table-options",level:4},{value:"Updating Tables",id:"updating-tables",level:3},{value:"Renaming / Dropping Tables",id:"renaming-and-dropping-tables",level:3},{value:"Renaming Tables With Foreign Keys",id:"renaming-tables-with-foreign-keys",level:4},{value:"Columns",id:"columns",level:2},{value:"Creating Columns",id:"creating-columns",level:3},{value:"Available Column Types",id:"available-column-types",level:3},{value:"<code>bigIncrements()</code>",id:"column-method-bigIncrements",level:4},{value:"<code>bigInteger()</code>",id:"column-method-bigInteger",level:4},{value:"<code>binary()</code>",id:"column-method-binary",level:4},{value:"<code>boolean()</code>",id:"column-method-boolean",level:4},{value:"<code>Char()</code>",id:"column-method-Char",level:4},{value:"<code>date()</code>",id:"column-method-date",level:4},{value:"<code>datetime()</code>",id:"column-method-datetime",level:4},{value:"<code>datetimes()</code>",id:"column-method-datetimes",level:4},{value:"<code>datetimeTz()</code>",id:"column-method-datetimeTz",level:4},{value:"<code>decimal()</code>",id:"column-method-decimal",level:4},{value:"<code>Double()</code>",id:"column-method-Double",level:4},{value:"<code>Enum()</code>",id:"column-method-Enum",level:4},{value:"<code>Float()</code>",id:"column-method-Float",level:4},{value:"<code>foreignId()</code>",id:"column-method-foreignId",level:4},{value:"<code>foreignIdFor()</code>",id:"column-method-foreignIdFor",level:4},{value:"<code>foreignUuid()</code>",id:"column-method-foreignUuid",level:4},{value:"<code>geometry()</code>",id:"column-method-geometry",level:4},{value:"<code>geometryCollection()</code>",id:"column-method-geometryCollection",level:4},{value:"<code>id()</code>",id:"column-method-id",level:4},{value:"<code>increments()</code>",id:"column-method-increments",level:4},{value:"<code>integer()</code>",id:"column-method-integer",level:4},{value:"<code>ipAddress()</code>",id:"column-method-ipAddress",level:4},{value:"<code>json()</code>",id:"column-method-json",level:4},{value:"<code>jsonb()</code>",id:"column-method-jsonb",level:4},{value:"<code>lineString()</code>",id:"column-method-lineString",level:4},{value:"<code>longBinary()</code>",id:"column-method-longBinary",level:4},{value:"<code>longText()</code>",id:"column-method-longText",level:4},{value:"<code>macAddress()</code>",id:"column-method-macAddress",level:4},{value:"<code>mediumBinary()</code>",id:"column-method-mediumBinary",level:4},{value:"<code>mediumIncrements()</code>",id:"column-method-mediumIncrements",level:4},{value:"<code>mediumInteger()</code>",id:"column-method-mediumInteger",level:4},{value:"<code>mediumText()</code>",id:"column-method-mediumText",level:4},{value:"<code>multiLineString()</code>",id:"column-method-multiLineString",level:4},{value:"<code>multiPoint()</code>",id:"column-method-multiPoint",level:4},{value:"<code>multiPolygon()</code>",id:"column-method-multiPolygon",level:4},{value:"<code>point()</code>",id:"column-method-point",level:4},{value:"<code>polygon()</code>",id:"column-method-polygon",level:4},{value:"<code>rememberToken()</code>",id:"column-method-rememberToken",level:4},{value:"<code>set()</code>",id:"column-method-set",level:4},{value:"<code>smallIncrements()</code>",id:"column-method-smallIncrements",level:4},{value:"<code>smallInteger()</code>",id:"column-method-smallInteger",level:4},{value:"<code>softDeletes()</code>",id:"column-method-softDeletes",level:4},{value:"<code>softDeletesDatetime()</code>",id:"column-method-softDeletesDatetime",level:4},{value:"<code>softDeletesTz()</code>",id:"column-method-softDeletesTz",level:4},{value:"<code>string()</code>",id:"column-method-string",level:4},{value:"<code>text()</code>",id:"column-method-text",level:4},{value:"<code>time()</code>",id:"column-method-time",level:4},{value:"<code>timeTz()</code>",id:"column-method-timeTz",level:4},{value:"<code>timestamp()</code>",id:"column-method-timestamp",level:4},{value:"<code>timestampTz()</code>",id:"column-method-timestampTz",level:4},{value:"<code>timestampsTz()</code>",id:"column-method-timestampsTz",level:4},{value:"<code>timestamps()</code>",id:"column-method-timestamps",level:4},{value:"<code>tinyBinary()</code>",id:"column-method-tinyBinary",level:4},{value:"<code>tinyIncrements()</code>",id:"column-method-tinyIncrements",level:4},{value:"<code>tinyInteger()</code>",id:"column-method-tinyInteger",level:4},{value:"<code>tinyText()</code>",id:"column-method-tinyText",level:4},{value:"<code>unsignedBigInteger()</code>",id:"column-method-unsignedBigInteger",level:4},{value:"<code>unsignedDecimal()</code>",id:"column-method-unsignedDecimal",level:4},{value:"<code>unsignedInteger()</code>",id:"column-method-unsignedInteger",level:4},{value:"<code>unsignedMediumInteger()</code>",id:"column-method-unsignedMediumInteger",level:4},{value:"<code>unsignedSmallInteger()</code>",id:"column-method-unsignedSmallInteger",level:4},{value:"<code>unsignedTinyInteger()</code>",id:"column-method-unsignedTinyInteger",level:4},{value:"<code>uuid()</code>",id:"column-method-uuid",level:4},{value:"<code>year()</code>",id:"column-method-year",level:4},{value:"Column Modifiers",id:"column-modifiers",level:3},{value:"Default Expressions",id:"default-expressions",level:4},{value:"Column Order",id:"column-order",level:4},{value:"Modifying Columns",id:"modifying-columns",level:3},{value:"Renaming Columns",id:"renaming-columns",level:4},{value:"Renaming Columns On Legacy Databases",id:"renaming-columns-on-legacy-databases",level:4},{value:"Dropping Columns",id:"dropping-columns",level:3},{value:"Available Command Aliases",id:"available-command-aliases",level:4},{value:"Indexes",id:"indexes",level:2},{value:"Creating Indexes",id:"creating-indexes",level:3},{value:"Available Index Types",id:"available-index-types",level:4},{value:"Index Lengths & MySQL / MariaDB",id:"index-lengths--mysql--mariadb",level:4},{value:"Renaming Indexes",id:"renaming-indexes",level:3},{value:"Dropping Indexes",id:"dropping-indexes",level:3},{value:"Foreign Key Constraints",id:"foreign-key-constraints",level:3},{value:"Dropping Foreign Keys",id:"dropping-foreign-keys",level:4},{value:"Toggling Foreign Key Constraints",id:"toggling-foreign-key-constraints",level:4}];function j(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",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(n.h1,{id:"database-migrations",children:"Database: Migrations"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#generating-migrations",children:"Generating Migrations"})}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.a,{href:"#tab-completion",children:"Tab completion"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#alternative-installation-methods",children:"Alternative installation methods"})}),"\n"]}),"\n"]}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#migration-structure",children:"Migration Structure"})}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.a,{href:"#running-migrations",children:"Running Migrations"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#rolling-back-migrations",children:"Rolling Back Migrations"})}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.a,{href:"#tables",children:"Tables"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#creating-tables",children:"Creating Tables"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#updating-tables",children:"Updating Tables"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#renaming-and-dropping-tables",children:"Renaming / Dropping Tables"})}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.a,{href:"#columns",children:"Columns"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#creating-columns",children:"Creating Columns"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#available-column-types",children:"Available Column Types"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#column-modifiers",children:"Column Modifiers"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#modifying-columns",children:"Modifying Columns"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#dropping-columns",children:"Dropping Columns"})}),"\n"]}),"\n"]}),"\n",(0,l.jsxs)(n.li,{children:[(0,l.jsx)(n.a,{href:"#indexes",children:"Indexes"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#creating-indexes",children:"Creating Indexes"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#renaming-indexes",children:"Renaming Indexes"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#dropping-indexes",children:"Dropping Indexes"})}),"\n",(0,l.jsx)(n.li,{children:(0,l.jsx)(n.a,{href:"#foreign-key-constraints",children:"Foreign Key Constraints"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,l.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,l.jsx)(n.p,{children:"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. If you have ever had to tell a teammate to manually add a column to their local database schema after pulling in your changes from source control, you've faced the problem that database migrations solve."}),"\n",(0,l.jsxs)(n.p,{children:["The TinyORM ",(0,l.jsx)(n.code,{children:"Schema"})," facade provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems. Typically, migrations will use this facade to create and modify database tables and columns."]}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"tom"})," migrations is a small console application that depends on the ",(0,l.jsx)(n.code,{children:"TinyORM"})," library. All migrations logic is compiled so recompilation is needed after adding a new migration class."]}),"\n",(0,l.jsx)(n.admonition,{type:"warning",children:(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.a,{href:"/database/migrations#tables",children:(0,l.jsx)(n.code,{children:"schema builder"})})," and ",(0,l.jsx)(n.a,{href:"/database/migrations",children:(0,l.jsx)(n.code,{children:"migrations"})})," don't support ",(0,l.jsx)(n.a,{href:"/database/getting-started#multi-threading-support",children:"multi-threading"}),"."]})}),"\n",(0,l.jsx)(n.admonition,{type:"note",children:(0,l.jsxs)(n.p,{children:["TinyORM's schema builder supports all ",(0,l.jsx)(n.a,{href:"/database/getting-started#introduction",children:"supported databases"})," out of the box."]})}),"\n",(0,l.jsxs)(n.p,{children:["The following image shows what the ",(0,l.jsx)(n.code,{children:"tom"})," console application looks like. \u2728 As you can see it offers everything that is needed to generate and manage migrations and seeders and all of this is backed up with the tab completion."]}),"\n",(0,l.jsx)("img",{src:i(5848).A,alt:"TinyORM - Tom console application - Showcase",width:"760",title:"TinyORM - Tom console application - Showcase"}),"\n",(0,l.jsx)(n.h2,{id:"generating-migrations",children:"Generating Migrations"}),"\n",(0,l.jsxs)(n.p,{children:["You may use the ",(0,l.jsx)(n.code,{children:"make:migration"})," ",(0,l.jsx)(n.code,{children:"tom"})," command to generate a database migration. The new migration will be placed in your ",(0,l.jsx)(n.code,{children:"database/migrations"})," directory. Each migration filename contains a timestamp that allows ",(0,l.jsx)(n.code,{children:"tom"})," to determine the order of the migrations:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom make:migration create_posts_table\n"})}),"\n",(0,l.jsxs)(n.p,{children:["tom will use the name of the migration to attempt to guess the name of the table and whether or not the migration will be creating a new table. If ",(0,l.jsx)(n.code,{children:"tom"})," is able to determine the table name from the migration name, ",(0,l.jsx)(n.code,{children:"tom"})," will pre-fill the generated migration file with the specified table. Otherwise, you may simply specify the table in the migration file manually."]}),"\n",(0,l.jsxs)(n.p,{children:["If you would like to specify a custom path for the generated migration, you may use the ",(0,l.jsx)(n.code,{children:"--path"})," option when executing the ",(0,l.jsx)(n.code,{children:"make:migration"})," command. The given path should be relative to your ",(0,l.jsx)("abbr",{title:"Current working directory",children:"pwd"})," or you can use the ",(0,l.jsx)(n.code,{children:"--realpath"})," option and pass the absolute path to the ",(0,l.jsx)(n.code,{children:"--path"})," option."]}),"\n",(0,l.jsx)(n.h4,{id:"migrations-naming-rules",children:"Migrations naming rules"}),"\n",(0,l.jsxs)(n.p,{children:["If the migration name starts with the ",(0,l.jsx)(n.code,{children:"create_"})," string then the stub for table creation will be used and if the migration name contains ",(0,l.jsx)(n.code,{children:"_(from|to|in)_"})," then the stub for table update will be used. You can override these rules using the ",(0,l.jsx)(n.code,{children:"--create"})," and ",(0,l.jsx)(n.code,{children:"--table"})," options and specify the table name manually."]}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["You can also pass the full migration filename with the datetime prefix and extension to the ",(0,l.jsx)(n.code,{children:"make:migration"}),". This command is able to detect almost any combination of the passed value, with or without datetime prefix or extension if it is the filename; or StudlyCase, snake_case, or kebab-case if it is the classname or any combination described above. \ud83d\udc40"]})}),"\n",(0,l.jsx)(n.h2,{id:"tab-completion",children:"Tab completion"}),"\n",(0,l.jsxs)(n.p,{children:["Tab completion is available for the ",(0,l.jsx)(n.code,{children:"pwsh"})," (on Linux too), ",(0,l.jsx)(n.code,{children:"bash"}),", and ",(0,l.jsx)(n.code,{children:"zsh"})," shells. For ",(0,l.jsx)(n.code,{children:"pwsh"})," the ",(0,l.jsx)(n.code,{children:"tom.exe"})," and ",(0,l.jsx)(n.code,{children:"TinyOrm0.dll"})," library must be on the system path to work properly. With ",(0,l.jsx)(n.code,{children:"bash"})," if the ",(0,l.jsx)(n.code,{children:"tom"})," executable and ",(0,l.jsx)(n.code,{children:"libTinyOrm.so"})," library is ",(0,l.jsx)(n.strong,{children:"not"})," on the system path then it will provide less accurate completions."]}),"\n",(0,l.jsx)(n.p,{children:"You can enable it using the following commands."}),"\n",(0,l.jsxs)(o.A,{groupId:r.vf,children:[(0,l.jsx)(a.A,{value:r.b,label:r.ux,children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-powershell",children:"tom integrate pwsh\n"})})}),(0,l.jsx)(a.A,{value:r.xj,label:r.gg,children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom integrate bash\n"})})}),(0,l.jsx)(a.A,{value:r.cy,label:r.$E,children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom integrate zsh\ntom integrate zsh --path=/usr/share/zsh/site-functions\n"})})})]}),"\n",(0,l.jsxs)(n.p,{children:["Or you can enable it manually. Following actions are the same as the ",(0,l.jsx)(n.code,{children:"tom integrate"})," command does."]}),"\n",(0,l.jsxs)(n.p,{children:["For the ",(0,l.jsx)(n.code,{children:"pwsh"})," paste the following code to the pwsh profile (works on Linux or Windows)."]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-powershell",metastring:"title='~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1'",children:"Register-ArgumentCompleter -Native -CommandName tom,tom_testdata -ScriptBlock {\n Param($wordToComplete, $commandAst, $cursorPosition)\n [Console]::InputEncoding =\n [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()\n $Local:word = $wordToComplete.Replace('\"', '\\\"')\n $Local:ast = $commandAst.ToString().Replace('\"', '\\\"')\n tom complete --word=\"$Local:word\" --commandline=\"$Local:ast\" --position=$cursorPosition\n | ForEach-Object {\n $completionText, $listText, $toolTip = $_ -split ';', 3\n $listText ??= $completionText\n $toolTip ??= $completionText\n [System.Management.Automation.CompletionResult]::new(\n $completionText, $listText, 'ParameterValue', $toolTip)\n }\n}\n"})}),"\n",(0,l.jsxs)(n.p,{children:["For ",(0,l.jsx)(n.code,{children:"bash"})," you can copy or create symlink of the ",(0,l.jsx)(n.code,{children:"/tools/completions/tom.bash"})," file to the ",(0,l.jsx)(n.code,{children:"/usr/share/bash-completion/completions"})," folder."]}),"\n",(0,l.jsx)(d.A,{className:"language-bash",children:`sudo ln -s ${(0,c.OZ)(r.xj)}/TinyORM/tools/completions/tom.bash /usr/share/bash-completion/completions/tom`}),"\n",(0,l.jsxs)(n.p,{children:["And for ",(0,l.jsx)(n.code,{children:"zsh"})," you can copy or create symlink of the ",(0,l.jsx)(n.code,{children:"/tools/completions/tom.zsh"})," file to the ",(0,l.jsx)(n.code,{children:"_tom"})," file to ",(0,l.jsx)(n.code,{children:"/usr/local/share/zsh/site-functions"})," folder."]}),"\n",(0,l.jsx)(d.A,{className:"language-bash",children:`sudo ln -s ${(0,c.OZ)(r.xj)}/TinyORM/tools/completions/tom.zsh /usr/local/share/zsh/site-functions/_tom`}),"\n",(0,l.jsxs)(n.p,{children:["It will provide completions for the ",(0,l.jsx)(n.code,{children:"tom"})," commands, long and short parameters, and also for some positional arguments like namespaces for the ",(0,l.jsx)(n.code,{children:"list"})," command or commands for the ",(0,l.jsx)(n.code,{children:"help"})," command."]}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"tom integrate zsh"})," command also accepts the ",(0,l.jsx)(n.code,{children:"--path="})," option with which you can set the location, where the zsh completion file should be created."]})}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["You can also output the completion script using the ",(0,l.jsx)(n.code,{children:"--stdout"})," option eg. ",(0,l.jsx)(n.code,{children:"tom integrate bash --stdout"}),"."]})}),"\n",(0,l.jsx)(n.h3,{id:"alternative-installation-methods",children:"Alternative installation methods"}),"\n",(0,l.jsxs)(n.p,{children:["This section describes alternative installation methods for ",(0,l.jsx)(n.code,{children:"bash"})," and ",(0,l.jsx)(n.code,{children:"zsh"})," tab completions."]}),"\n",(0,l.jsx)(n.h4,{id:"static-installation",children:"Static installation"}),"\n",(0,l.jsx)(n.p,{children:"Idea is to output the tab completion to the file and then source it."}),"\n",(0,l.jsxs)(o.A,{groupId:r.vf,children:[(0,l.jsx)(a.A,{value:r.xj,label:r.gg,children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"mkdir -p ~/.local/share/tom\ntom integrate bash --stdout > ~/.local/share/tom/tom.bash\n\n# Then source this file in the ~/.bashrc\nsource $HOME/.local/share/tom/tom.bash\n"})})}),(0,l.jsx)(a.A,{value:r.cy,label:r.$E,children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"mkdir -p ~/.local/share/tom\ntom integrate zsh --stdout > ~/.local/share/tom/tom.zsh\n\n# Then source this file in the ~/.zshrc\nsource $HOME/.local/share/tom/tom.zsh\ncompdef _tom tom\n"})})})]}),"\n",(0,l.jsx)(n.h4,{id:"dynamic-installation",children:"Dynamic installation"}),"\n",(0,l.jsxs)(n.p,{children:["Idea is to ",(0,l.jsx)(n.strong,{children:"avoid"})," outputting the tab completion to the file, so you ",(0,l.jsx)(n.code,{children:"eval"})," the tab completion source code right away."]}),"\n",(0,l.jsxs)(o.A,{groupId:r.vf,children:[(0,l.jsx)(a.A,{value:r.xj,label:r.gg,children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:'# Add this eval to the ~/.bashrc\neval "$(tom integrate bash --stdout)"\n'})})}),(0,l.jsx)(a.A,{value:r.cy,label:r.$E,children:(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:'# Add this eval to the ~/.zshrc\neval "$(tom integrate zsh --stdout)"\ncompdef _tom tom\n'})})})]}),"\n",(0,l.jsx)(n.h2,{id:"migration-structure",children:"Migration Structure"}),"\n",(0,l.jsxs)(n.p,{children:["A migration class contains two methods: ",(0,l.jsx)(n.code,{children:"up"})," and ",(0,l.jsx)(n.code,{children:"down"}),". The ",(0,l.jsx)(n.code,{children:"up"})," method is used to add new tables, columns, or indexes to your database, while the ",(0,l.jsx)(n.code,{children:"down"})," method should reverse the operations performed by the ",(0,l.jsx)(n.code,{children:"up"})," method."]}),"\n",(0,l.jsxs)(n.p,{children:["Within both of these methods, you may use the TinyORM schema builder to expressively create and modify tables. To learn about all of the methods available on the ",(0,l.jsx)(n.code,{children:"Schema"})," builder, ",(0,l.jsx)(n.a,{href:"#creating-tables",children:"check out its documentation"}),". For example, the following migration creates a ",(0,l.jsx)(n.code,{children:"posts"})," table:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n\n#include <tom/migration.hpp>\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,l.jsxs)(n.p,{children:['Migration classes can be named in two formats, StudlyCase without the datetime prefix and "snake_case" with the datetime prefix. If the StudlyCase name is used then the ',(0,l.jsx)(n.code,{children:"T_MIGRATION"})," macro must also be used in the migration class."]}),"\n",(0,l.jsx)(n.p,{children:"Naming with the datetime prefix should look like this."}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"struct _2014_10_12_000000_create_posts_table : Migration\n{\n\n /*! Run the migrations. */\n void up() const override\n {\n //\n }\n\n /*! Reverse the migrations. */\n void down() const override\n {\n //\n }\n};\n"})}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["The StudlyCase naming is preferred. Also the ",(0,l.jsx)(n.code,{children:"make:migration"})," command generates migrations in this format."]})}),"\n",(0,l.jsx)(n.h4,{id:"setting-the-migration-connection",children:"Setting The Migration Connection"}),"\n",(0,l.jsxs)(n.p,{children:["If your migration will be interacting with a database connection other than your application's default database connection, you should set the ",(0,l.jsx)(n.code,{children:"connection"})," data member of your migration:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'/*! The name of the database connection to use. */\nQString connection = QStringLiteral("tinyorm_example");\n\n/*! Run the migrations. */\nvoid up() const override\n{\n //\n}\n'})}),"\n",(0,l.jsx)(n.h2,{id:"running-migrations",children:"Running Migrations"}),"\n",(0,l.jsxs)(n.p,{children:["To run all of your outstanding migrations, execute the ",(0,l.jsx)(n.code,{children:"migrate"})," Tom command:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate\n"})}),"\n",(0,l.jsxs)(n.p,{children:["If you would like to see which migrations have run thus far, you may use the ",(0,l.jsx)(n.code,{children:"migrate:status"})," tom command:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:status\n"})}),"\n",(0,l.jsxs)(n.p,{children:["If you would like to see the SQL statements that will be executed by the migrations without actually running them, you may provide the ",(0,l.jsx)(n.code,{children:"--pretend"})," flag to the ",(0,l.jsx)(n.code,{children:"migrate"})," command:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate --pretend\n"})}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["Many ",(0,l.jsx)(n.code,{children:"tom"})," commands offer variety of options, you can explore them using the ",(0,l.jsx)(n.code,{children:"tom list"})," and ",(0,l.jsx)(n.code,{children:"tom help"})," commands. In most cases, these commands and options are self-explanatory."]})}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"tom"})," command is able to guess the command name and command namespace, eg. ",(0,l.jsx)(n.code,{children:"tom mig:st"})," or ",(0,l.jsx)(n.code,{children:"tom m:rol"}),", ..."]})}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["You can pass the ",(0,l.jsx)(n.code,{children:"-vvv"})," command-line argument to any command to see all executed SQL queries. \ud83d\udc4c"]})}),"\n",(0,l.jsx)(n.admonition,{type:"note",children:(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"migrate"})," Tom command internally calls the ",(0,l.jsx)(n.code,{children:"migrate:install"})," command which installs the migration repository table. To uninstall this repository table you can call the ",(0,l.jsx)(n.code,{children:"migrate:uninstall"}),"."]})}),"\n",(0,l.jsx)(n.h4,{id:"forcing-migrations-to-run-in-production",children:"Forcing Migrations To Run In Production"}),"\n",(0,l.jsxs)(n.p,{children:["Some migration operations are destructive, which means they may cause you to lose data. In order to protect you from running these commands against your production database, you will be prompted for confirmation before the commands are executed. To force the commands to run without a prompt, use the ",(0,l.jsx)(n.code,{children:"--force"})," flag:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate --force\n"})}),"\n",(0,l.jsx)(n.h3,{id:"rolling-back-migrations",children:"Rolling Back Migrations"}),"\n",(0,l.jsxs)(n.p,{children:["To roll back the latest migration operation, you may use the ",(0,l.jsx)(n.code,{children:"rollback"}),' Tom command. This command rolls back the last "batch" of migrations, which may include multiple migration files:']}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:rollback\n"})}),"\n",(0,l.jsxs)(n.p,{children:["You may roll back a limited number of migrations by providing the ",(0,l.jsx)(n.code,{children:"step"})," option to the ",(0,l.jsx)(n.code,{children:"rollback"})," command. For example, the following command will roll back the last five migrations:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:rollback --step=5\n"})}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"migrate:reset"})," command will roll back all of your application's migrations:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:reset\n"})}),"\n",(0,l.jsxs)(n.p,{children:['You may roll back a specific "batch" of migrations by providing the ',(0,l.jsx)(n.code,{children:"batch"})," option to the ",(0,l.jsx)(n.code,{children:"rollback"})," command, where the ",(0,l.jsx)(n.code,{children:"batch"})," option corresponds to a batch value within your application's ",(0,l.jsx)(n.code,{children:"migrations"})," database table. For example, the following command will roll back all migrations in batch three:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:rollback --batch=3\n"})}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"migrate:reset"})," command will roll back all of your application's migrations:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:reset\n"})}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"migrate:uninstall"})," command will uninstall the migration repository table, it optionally accepts the ",(0,l.jsx)(n.code,{children:"--reset"})," option to roll back all of your application's migrations:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:uninstall --reset\n"})}),"\n",(0,l.jsx)(n.h4,{id:"roll-back--migrate-using-a-single-command",children:"Roll Back & Migrate Using A Single Command"}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"migrate:refresh"})," command will roll back all of your migrations and then execute the ",(0,l.jsx)(n.code,{children:"migrate"})," command. This command effectively re-creates your entire database:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:refresh\n"})}),"\n",(0,l.jsxs)(n.p,{children:["You may roll back and re-migrate a limited number of migrations by providing the ",(0,l.jsx)(n.code,{children:"step"})," option to the ",(0,l.jsx)(n.code,{children:"refresh"})," command. For example, the following command will roll back and re-migrate the last five migrations:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:refresh --step=5\n"})}),"\n",(0,l.jsx)(n.h4,{id:"drop-all-tables--migrate",children:"Drop All Tables & Migrate"}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"migrate:fresh"})," command will drop all tables from the database and then execute the ",(0,l.jsx)(n.code,{children:"migrate"})," command:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-bash",children:"tom migrate:fresh\n"})}),"\n",(0,l.jsx)(n.admonition,{type:"warning",children:(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"migrate:fresh"})," command will drop all database tables regardless of their prefix. This command should be used with caution when developing on a database that is shared with other applications."]})}),"\n",(0,l.jsx)(n.h2,{id:"tables",children:"Tables"}),"\n",(0,l.jsx)(n.h3,{id:"creating-tables",children:"Creating Tables"}),"\n",(0,l.jsxs)(n.p,{children:["To create a new database table, use the ",(0,l.jsx)(n.code,{children:"create"})," method on the ",(0,l.jsx)(n.code,{children:"Schema"})," facade. The ",(0,l.jsx)(n.code,{children:"create"})," method accepts two arguments: the first is the name of the table, while the second is a lambda expression which receives a ",(0,l.jsx)(n.code,{children:"Orm::SchemaNs::Blueprint"})," object that may be used to define the new table:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nusing Orm::Schema;\n\nSchema::create("users", [](Blueprint &table)\n{\n table.id();\n table.string("name");\n table.string("email");\n table.timestamps();\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["When creating the table, you may use any of the schema builder's ",(0,l.jsx)(n.a,{href:"#creating-columns",children:"column methods"})," to define the table's columns."]}),"\n",(0,l.jsx)(n.h4,{id:"checking-for-table--column-existence",children:"Checking For Table / Column Existence"}),"\n",(0,l.jsxs)(n.p,{children:["You may check for the existence of a table or column using the ",(0,l.jsx)(n.code,{children:"hasTable"})," and ",(0,l.jsx)(n.code,{children:"hasColumn"})," methods:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'if (Schema::hasTable("users")) {\n // The "users" table exists...\n}\n\nif (Schema::hasColumn("users", "email")) {\n // The "users" table exists and has an "email" column...\n}\n'})}),"\n",(0,l.jsx)(n.h4,{id:"database-connection--table-options",children:"Database Connection & Table Options"}),"\n",(0,l.jsxs)(n.p,{children:["If you want to perform a schema operation on a database connection that is not your application's default connection, use the ",(0,l.jsx)(n.code,{children:"connection"})," method or ",(0,l.jsx)(n.code,{children:"on"})," alias:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::connection("postgres").create("users", [](Blueprint &table)\n{\n table.id();\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["In addition, a few other data members and methods may be used to define other aspects of the table's creation. The ",(0,l.jsx)(n.code,{children:"engine"})," data member may be used to specify the table's storage engine when using MySQL:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/constants.hpp>\n\nusing Orm::Constants::InnoDB;\n\nSchema::create("users", [](Blueprint &table)\n{\n table.engine = InnoDB;\n\n // ...\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"charset"})," and ",(0,l.jsx)(n.code,{children:"collation"})," data members may be used to specify the character set and collation for the created table when using MySQL:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/constants.hpp>\n\nusing Orm::Constants::UTF8MB4;\n\nSchema::create("users", [](Blueprint &table)\n{\n table.charset = UTF8MB4;\n table.collation = "utf8mb4_unicode_ci";\n\n // ...\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"temporary"}),' method may be used to indicate that the table should be "temporary". Temporary tables are only visible to the current connection\'s database session and are dropped automatically when the connection is closed:']}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::create("calculations", [](Blueprint &table)\n{\n table.temporary();\n\n // ...\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:['If you would like to add a "comment" to a database table, you may invoke the ',(0,l.jsx)(n.code,{children:"comment"})," method on the table instance. Table comments are currently only supported by MySQL and PostgreSQL:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::create("calculations", [](Blueprint &table)\n{\n table.comment("Business calculations");\n\n // ...\n});\n'})}),"\n",(0,l.jsx)(n.h3,{id:"updating-tables",children:"Updating Tables"}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"table"})," method on the ",(0,l.jsx)(n.code,{children:"Schema"})," facade may be used to update existing tables. Like the ",(0,l.jsx)(n.code,{children:"create"})," method, the ",(0,l.jsx)(n.code,{children:"table"})," method accepts two arguments: the name of the table and a lambda expression that receives a ",(0,l.jsx)(n.code,{children:"Blueprint"})," instance you may use to add columns or indexes to the table:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.integer("votes");\n});\n'})}),"\n",(0,l.jsx)(n.h3,{id:"renaming-and-dropping-tables",children:"Renaming / Dropping Tables"}),"\n",(0,l.jsxs)(n.p,{children:["To rename an existing database table, use the ",(0,l.jsx)(n.code,{children:"rename"})," method:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nSchema::rename("from", "to");\n'})}),"\n",(0,l.jsxs)(n.p,{children:["To drop an existing table, you may use the ",(0,l.jsx)(n.code,{children:"drop"})," or ",(0,l.jsx)(n.code,{children:"dropIfExists"})," methods:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::drop("users");\n\nSchema::dropIfExists("users");\n'})}),"\n",(0,l.jsx)(n.h4,{id:"renaming-tables-with-foreign-keys",children:"Renaming Tables With Foreign Keys"}),"\n",(0,l.jsxs)(n.p,{children:["Before renaming a table, you should verify that any foreign key constraints on the table have an explicit name in your migration files instead of letting TinyORM assign a convention based name. Otherwise, the foreign key constraint ",(0,l.jsx)(n.strong,{children:"index name"})," will refer to the old table name."]}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["After renaming a table, you can re-create (drop and create again) the foreign key constraints to fix an ",(0,l.jsx)(n.strong,{children:"index name"}),", so it refers to a renamed table."]})}),"\n",(0,l.jsx)(n.h2,{id:"columns",children:"Columns"}),"\n",(0,l.jsx)(n.h3,{id:"creating-columns",children:"Creating Columns"}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"table"})," method on the ",(0,l.jsx)(n.code,{children:"Schema"})," facade may be used to update existing tables. Like the ",(0,l.jsx)(n.code,{children:"create"})," method, the ",(0,l.jsx)(n.code,{children:"table"})," method accepts two arguments: the name of the table and a lambda expression that receives a ",(0,l.jsx)(n.code,{children:"Blueprint"})," instance you may use to add columns to the table:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.integer("votes");\n});\n'})}),"\n",(0,l.jsx)(n.h3,{id:"available-column-types",children:"Available Column Types"}),"\n",(0,l.jsx)(n.p,{children:"The schema builder blueprint offers a variety of methods that correspond to the different types of columns you can add to your database tables. Each of the available methods are listed in the table below:"}),"\n",(0,l.jsx)("div",{className:"tom-column-types-list",children:(0,l.jsxs)(n.p,{children:[(0,l.jsx)(n.a,{href:"#column-method-bigIncrements",children:"bigIncrements"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-bigInteger",children:"bigInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-binary",children:"binary"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-boolean",children:"boolean"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-Char",children:"Char"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-date",children:"date"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-datetime",children:"datetime"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-datetimes",children:"datetimes"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-datetimeTz",children:"datetimeTz"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-decimal",children:"decimal"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-Double",children:"Double"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-Enum",children:"Enum"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-Float",children:"Float"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-foreignId",children:"foreignId"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-foreignIdFor",children:"foreignIdFor"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-foreignUuid",children:"foreignUuid"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-geometry",children:"geometry"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-geometryCollection",children:"geometryCollection"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-id",children:"id"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-increments",children:"increments"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-integer",children:"integer"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-ipAddress",children:"ipAddress"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-json",children:"json"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-jsonb",children:"jsonb"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-lineString",children:"lineString"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-longBinary",children:"longBinary"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-longText",children:"longText"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-macAddress",children:"macAddress"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-mediumBinary",children:"mediumBinary"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-mediumIncrements",children:"mediumIncrements"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-mediumInteger",children:"mediumInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-mediumText",children:"mediumText"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-multiLineString",children:"multiLineString"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-multiPoint",children:"multiPoint"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-multiPolygon",children:"multiPolygon"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-point",children:"point"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-polygon",children:"polygon"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-rememberToken",children:"rememberToken"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-set",children:"set"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-smallIncrements",children:"smallIncrements"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-smallInteger",children:"smallInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-softDeletes",children:"softDeletes"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-softDeletesDatetime",children:"softDeletesDatetime"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-softDeletesTz",children:"softDeletesTz"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-string",children:"string"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-text",children:"text"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-time",children:"time"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-timeTz",children:"timeTz"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-timestamp",children:"timestamp"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-timestampTz",children:"timestampTz"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-timestampsTz",children:"timestampsTz"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-timestamps",children:"timestamps"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-tinyBinary",children:"tinyBinary"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-tinyIncrements",children:"tinyIncrements"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-tinyInteger",children:"tinyInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-tinyText",children:"tinyText"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-unsignedBigInteger",children:"unsignedBigInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-unsignedDecimal",children:"unsignedDecimal"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-unsignedInteger",children:"unsignedInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-unsignedMediumInteger",children:"unsignedMediumInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-unsignedSmallInteger",children:"unsignedSmallInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-unsignedTinyInteger",children:"unsignedTinyInteger"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-uuid",children:"uuid"}),"\n",(0,l.jsx)(n.a,{href:"#column-method-year",children:"year"})]})}),"\n",(0,l.jsx)(n.admonition,{type:"info",children:(0,l.jsxs)(n.p,{children:["Names of ",(0,l.jsx)(n.code,{children:"Char"}),", ",(0,l.jsx)(n.code,{children:"Double"}),", ",(0,l.jsx)(n.code,{children:"Enum"}),", and ",(0,l.jsx)(n.code,{children:"Float"})," column methods are in the CamelCase format to avoid collisions with C++ keywords."]})}),"\n",(0,l.jsxs)("div",{className:"tom-column-types",children:[(0,l.jsx)(n.h4,{id:"column-method-bigIncrements",children:(0,l.jsx)(n.code,{children:"bigIncrements()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"bigIncrements"})," method creates an auto-incrementing ",(0,l.jsx)(n.code,{children:"UNSIGNED BIGINT"})," (primary key) equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"#include <orm/constants.hpp>\n\ntable.bigIncrements(Orm::ID);\n"})}),(0,l.jsx)(n.h4,{id:"column-method-bigInteger",children:(0,l.jsx)(n.code,{children:"bigInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"bigInteger"})," method creates a ",(0,l.jsx)(n.code,{children:"BIGINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.bigInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-binary",children:(0,l.jsx)(n.code,{children:"binary()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"binary"})," method creates a ",(0,l.jsx)(n.code,{children:"BLOB"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.binary("photo");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-boolean",children:(0,l.jsx)(n.code,{children:"boolean()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"boolean"})," method creates a ",(0,l.jsx)(n.code,{children:"BOOLEAN"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.boolean("confirmed");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-Char",children:(0,l.jsx)(n.code,{children:"Char()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"Char"})," method creates a ",(0,l.jsx)(n.code,{children:"CHAR"})," equivalent column with of a given length:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"#include <orm/constants.hpp>\n\ntable.Char(Orm::NAME, 100);\n"})}),(0,l.jsx)(n.h4,{id:"column-method-date",children:(0,l.jsx)(n.code,{children:"date()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"date"})," method creates a ",(0,l.jsx)(n.code,{children:"DATE"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.date("created_at");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-datetime",children:(0,l.jsx)(n.code,{children:"datetime()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"datetime"})," method creates a ",(0,l.jsx)(n.code,{children:"DATETIME"})," equivalent column with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.datetime("created_at", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-datetimes",children:(0,l.jsx)(n.code,{children:"datetimes()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"datetimes"})," method creates ",(0,l.jsx)(n.code,{children:"created_at"})," and ",(0,l.jsx)(n.code,{children:"updated_at"})," ",(0,l.jsx)(n.code,{children:"DATETIME"})," equivalent columns with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"table.datetimes(precision = 0);\n"})}),(0,l.jsx)(n.h4,{id:"column-method-datetimeTz",children:(0,l.jsx)(n.code,{children:"datetimeTz()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"datetimeTz"})," method creates a ",(0,l.jsx)(n.code,{children:"DATETIME"})," (with timezone) equivalent column with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"#include <orm/constants.hpp>\n\ntable.datetimeTz(Orm::CREATED_AT, precision = 0);\n"})}),(0,l.jsx)(n.h4,{id:"column-method-decimal",children:(0,l.jsx)(n.code,{children:"decimal()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"decimal"})," method creates a ",(0,l.jsx)(n.code,{children:"DECIMAL"})," equivalent column with the given precision (total digits) and scale (decimal digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.decimal("amount", precision = 8, scale = 2);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-Double",children:(0,l.jsx)(n.code,{children:"Double()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"Double"})," method creates a ",(0,l.jsx)(n.code,{children:"DOUBLE"})," equivalent column with the given precision (total digits) and scale (decimal digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.Double("amount", 8, 2);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-Enum",children:(0,l.jsx)(n.code,{children:"Enum()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"Enum"})," method creates a ",(0,l.jsx)(n.code,{children:"ENUM"})," equivalent column with the given valid values:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.Enum("difficulty", {"easy", "hard"});\n'})}),(0,l.jsx)(n.h4,{id:"column-method-Float",children:(0,l.jsx)(n.code,{children:"Float()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"Float"})," method creates a ",(0,l.jsx)(n.code,{children:"FLOAT"})," equivalent column with the given precision (total digits) and scale (decimal digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.Float("amount", 8, 2);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-foreignId",children:(0,l.jsx)(n.code,{children:"foreignId()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"foreignId"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED BIGINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.foreignId("user_id");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-foreignIdFor",children:(0,l.jsx)(n.code,{children:"foreignIdFor()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"foreignIdFor"})," method adds a ",(0,l.jsx)(n.code,{children:"{column}_id UNSIGNED BIGINT"})," equivalent column for a given model class:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nModels::User user;\n\ntable.foreignIdFor(User);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-foreignUuid",children:(0,l.jsx)(n.code,{children:"foreignUuid()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"foreignUuid"})," method creates a ",(0,l.jsx)(n.code,{children:"UUID"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.foreignUuid("user_id");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-geometry",children:(0,l.jsx)(n.code,{children:"geometry()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"geometry"})," method creates a ",(0,l.jsx)(n.code,{children:"GEOMETRY"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.geometry("positions");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-geometryCollection",children:(0,l.jsx)(n.code,{children:"geometryCollection()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"geometryCollection"})," method creates a ",(0,l.jsx)(n.code,{children:"GEOMETRYCOLLECTION"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.geometryCollection("positions");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-id",children:(0,l.jsx)(n.code,{children:"id()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"id"})," method is an alias of the ",(0,l.jsx)(n.code,{children:"bigIncrements"})," method. By default, the method will create an ",(0,l.jsx)(n.code,{children:"id"})," column; however, you may pass a column name if you would like to assign a different name to the column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"table.id();\n"})}),(0,l.jsx)(n.h4,{id:"column-method-increments",children:(0,l.jsx)(n.code,{children:"increments()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"increments"})," method creates an auto-incrementing ",(0,l.jsx)(n.code,{children:"UNSIGNED INTEGER"})," equivalent column as a primary key:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.increments("id");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-integer",children:(0,l.jsx)(n.code,{children:"integer()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"integer"})," method creates an ",(0,l.jsx)(n.code,{children:"INTEGER"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.integer("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-ipAddress",children:(0,l.jsx)(n.code,{children:"ipAddress()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"ipAddress"})," method creates a ",(0,l.jsx)(n.code,{children:"VARCHAR(45)"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.ipAddress("visitor");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-json",children:(0,l.jsx)(n.code,{children:"json()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"json"})," method creates a ",(0,l.jsx)(n.code,{children:"JSON"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.json("options");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-jsonb",children:(0,l.jsx)(n.code,{children:"jsonb()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"jsonb"})," method creates a ",(0,l.jsx)(n.code,{children:"JSONB"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.jsonb("options");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-lineString",children:(0,l.jsx)(n.code,{children:"lineString()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"lineString"})," method creates a ",(0,l.jsx)(n.code,{children:"LINESTRING"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.lineString("positions");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-longBinary",children:(0,l.jsx)(n.code,{children:"longBinary()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"longBinary"})," method creates a ",(0,l.jsx)(n.code,{children:"LONGBLOB"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.longBinary("photo");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-longText",children:(0,l.jsx)(n.code,{children:"longText()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"longText"})," method creates a ",(0,l.jsx)(n.code,{children:"LONGTEXT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.longText("description");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-macAddress",children:(0,l.jsx)(n.code,{children:"macAddress()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"macAddress"})," method creates a column that is intended to hold a MAC address. Some database systems, such as PostgreSQL, have a dedicated column type for this type of data. Other database systems will use a string equivalent ",(0,l.jsx)(n.code,{children:"VARCHAR(17)"})," column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.macAddress("device");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-mediumBinary",children:(0,l.jsx)(n.code,{children:"mediumBinary()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"mediumBinary"})," method creates a ",(0,l.jsx)(n.code,{children:"MEDIUMBLOB"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.mediumBinary("photo");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-mediumIncrements",children:(0,l.jsx)(n.code,{children:"mediumIncrements()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"mediumIncrements"})," method creates an auto-incrementing ",(0,l.jsx)(n.code,{children:"UNSIGNED MEDIUMINT"})," equivalent column as a primary key:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.mediumIncrements("id");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-mediumInteger",children:(0,l.jsx)(n.code,{children:"mediumInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"mediumInteger"})," method creates a ",(0,l.jsx)(n.code,{children:"MEDIUMINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.mediumInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-mediumText",children:(0,l.jsx)(n.code,{children:"mediumText()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"mediumText"})," method creates a ",(0,l.jsx)(n.code,{children:"MEDIUMTEXT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.mediumText("description");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-multiLineString",children:(0,l.jsx)(n.code,{children:"multiLineString()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"multiLineString"})," method creates a ",(0,l.jsx)(n.code,{children:"MULTILINESTRING"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.multiLineString("positions");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-multiPoint",children:(0,l.jsx)(n.code,{children:"multiPoint()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"multiPoint"})," method creates a ",(0,l.jsx)(n.code,{children:"MULTIPOINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.multiPoint("positions");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-multiPolygon",children:(0,l.jsx)(n.code,{children:"multiPolygon()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"multiPolygon"})," method creates a ",(0,l.jsx)(n.code,{children:"MULTIPOLYGON"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.multiPolygon("positions");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-point",children:(0,l.jsx)(n.code,{children:"point()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"point"})," method creates a ",(0,l.jsx)(n.code,{children:"POINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.point("position");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-polygon",children:(0,l.jsx)(n.code,{children:"polygon()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"polygon"})," method creates a ",(0,l.jsx)(n.code,{children:"POLYGON"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.polygon("position");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-rememberToken",children:(0,l.jsx)(n.code,{children:"rememberToken()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"rememberToken"})," method creates a nullable, ",(0,l.jsx)(n.code,{children:"VARCHAR(100)"}),' equivalent column that is intended to store the current "remember me" authentication token:']}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"table.rememberToken();\n"})}),(0,l.jsx)(n.h4,{id:"column-method-set",children:(0,l.jsx)(n.code,{children:"set()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"set"})," method creates a ",(0,l.jsx)(n.code,{children:"SET"})," equivalent column with the given list of valid values:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.set("flavors", {"strawberry", "vanilla"});\n'})}),(0,l.jsx)(n.h4,{id:"column-method-smallIncrements",children:(0,l.jsx)(n.code,{children:"smallIncrements()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"smallIncrements"})," method creates an auto-incrementing ",(0,l.jsx)(n.code,{children:"UNSIGNED SMALLINT"})," equivalent column as a primary key:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.smallIncrements("id");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-smallInteger",children:(0,l.jsx)(n.code,{children:"smallInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"smallInteger"})," method creates a ",(0,l.jsx)(n.code,{children:"SMALLINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.smallInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-softDeletes",children:(0,l.jsx)(n.code,{children:"softDeletes()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"softDeletes"})," method adds a nullable ",(0,l.jsx)(n.code,{children:"deleted_at"})," ",(0,l.jsx)(n.code,{children:"TIMESTAMP"})," equivalent column with an optional precision (total digits). This column is intended to store the ",(0,l.jsx)(n.code,{children:"deleted_at"}),' timestamp needed for TinyORM\'s "soft delete" functionality:']}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.softDeletes("deleted_at", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-softDeletesDatetime",children:(0,l.jsx)(n.code,{children:"softDeletesDatetime()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"softDeletesDatetime"})," method adds a nullable ",(0,l.jsx)(n.code,{children:"deleted_at"})," ",(0,l.jsx)(n.code,{children:"DATETIME"})," equivalent column with an optional precision (total digits). This column is intended to store the ",(0,l.jsx)(n.code,{children:"deleted_at"}),' timestamp needed for TinyORM\'s "soft delete" functionality:']}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.softDeletesDatetime("deleted_at", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-softDeletesTz",children:(0,l.jsx)(n.code,{children:"softDeletesTz()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"softDeletesTz"})," method adds a nullable ",(0,l.jsx)(n.code,{children:"deleted_at"})," ",(0,l.jsx)(n.code,{children:"TIMESTAMP"})," (with timezone) equivalent column with an optional precision (total digits). This column is intended to store the ",(0,l.jsx)(n.code,{children:"deleted_at"}),' timestamp needed for TinyORM\'s "soft delete" functionality:']}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.softDeletesTz("deleted_at", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-string",children:(0,l.jsx)(n.code,{children:"string()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"string"})," method creates a ",(0,l.jsx)(n.code,{children:"VARCHAR"})," equivalent column of the given length:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"#include <orm/constants.hpp>\n\ntable.string(Orm::NAME, 100);\n"})}),(0,l.jsx)(n.h4,{id:"column-method-text",children:(0,l.jsx)(n.code,{children:"text()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"text"})," method creates a ",(0,l.jsx)(n.code,{children:"TEXT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.text("description");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-time",children:(0,l.jsx)(n.code,{children:"time()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"time"})," method creates a ",(0,l.jsx)(n.code,{children:"TIME"})," equivalent column with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.time("sunrise", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-timeTz",children:(0,l.jsx)(n.code,{children:"timeTz()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"timeTz"})," method creates a ",(0,l.jsx)(n.code,{children:"TIME"})," (with timezone) equivalent column with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.timeTz("sunrise", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-timestamp",children:(0,l.jsx)(n.code,{children:"timestamp()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"timestamp"})," method creates a ",(0,l.jsx)(n.code,{children:"TIMESTAMP"})," equivalent column with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.timestamp("added_at", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-timestampTz",children:(0,l.jsx)(n.code,{children:"timestampTz()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"timestampTz"})," method creates a ",(0,l.jsx)(n.code,{children:"TIMESTAMP"})," (with timezone) equivalent column with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.timestampTz("added_at", precision = 0);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-timestampsTz",children:(0,l.jsx)(n.code,{children:"timestampsTz()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"timestampsTz"})," method creates ",(0,l.jsx)(n.code,{children:"created_at"})," and ",(0,l.jsx)(n.code,{children:"updated_at"})," ",(0,l.jsx)(n.code,{children:"TIMESTAMP"})," (with timezone) equivalent columns with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"table.timestampsTz(precision = 0);\n"})}),(0,l.jsx)(n.h4,{id:"column-method-timestamps",children:(0,l.jsx)(n.code,{children:"timestamps()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"timestamps"})," method creates ",(0,l.jsx)(n.code,{children:"created_at"})," and ",(0,l.jsx)(n.code,{children:"updated_at"})," ",(0,l.jsx)(n.code,{children:"TIMESTAMP"})," equivalent columns with an optional precision (total digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"table.timestamps(precision = 0);\n"})}),(0,l.jsx)(n.h4,{id:"column-method-tinyBinary",children:(0,l.jsx)(n.code,{children:"tinyBinary()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"tinyBinary"})," method creates a ",(0,l.jsx)(n.code,{children:"TINYBLOB"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.tinyBinary("photo");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-tinyIncrements",children:(0,l.jsx)(n.code,{children:"tinyIncrements()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"tinyIncrements"})," method creates an auto-incrementing ",(0,l.jsx)(n.code,{children:"UNSIGNED TINYINT"})," equivalent column as a primary key:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.tinyIncrements("id");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-tinyInteger",children:(0,l.jsx)(n.code,{children:"tinyInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"tinyInteger"})," method creates a ",(0,l.jsx)(n.code,{children:"TINYINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.tinyInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-tinyText",children:(0,l.jsx)(n.code,{children:"tinyText()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"tinyText"})," method creates a ",(0,l.jsx)(n.code,{children:"TINYTEXT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.tinyText("notes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-unsignedBigInteger",children:(0,l.jsx)(n.code,{children:"unsignedBigInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"unsignedBigInteger"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED BIGINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unsignedBigInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-unsignedDecimal",children:(0,l.jsx)(n.code,{children:"unsignedDecimal()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"unsignedDecimal"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED DECIMAL"})," equivalent column with an optional precision (total digits) and scale (decimal digits):"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unsignedDecimal("amount", precision = 8, scale = 2);\n'})}),(0,l.jsx)(n.h4,{id:"column-method-unsignedInteger",children:(0,l.jsx)(n.code,{children:"unsignedInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"unsignedInteger"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED INTEGER"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unsignedInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-unsignedMediumInteger",children:(0,l.jsx)(n.code,{children:"unsignedMediumInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"unsignedMediumInteger"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED MEDIUMINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unsignedMediumInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-unsignedSmallInteger",children:(0,l.jsx)(n.code,{children:"unsignedSmallInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"unsignedSmallInteger"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED SMALLINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unsignedSmallInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-unsignedTinyInteger",children:(0,l.jsx)(n.code,{children:"unsignedTinyInteger()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"unsignedTinyInteger"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED TINYINT"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unsignedTinyInteger("votes");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-uuid",children:(0,l.jsx)(n.code,{children:"uuid()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"uuid"})," method creates a ",(0,l.jsx)(n.code,{children:"UUID"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.uuid("id");\n'})}),(0,l.jsx)(n.h4,{id:"column-method-year",children:(0,l.jsx)(n.code,{children:"year()"})}),(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"year"})," method creates a ",(0,l.jsx)(n.code,{children:"YEAR"})," equivalent column:"]}),(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.year("birth_year");\n'})})]}),"\n",(0,l.jsx)(n.h3,{id:"column-modifiers",children:"Column Modifiers"}),"\n",(0,l.jsxs)(n.p,{children:['In addition to the column types listed above, there are several column "modifiers" you may use when adding a column to a database table. For example, to make the column "nullable", you may use the ',(0,l.jsx)(n.code,{children:"nullable"})," method:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.string("email").nullable();\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["The following table contains all of the available column modifiers. This list does not include ",(0,l.jsx)(n.a,{href:"#creating-indexes",children:"index modifiers"}),":"]}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Modifier"}),(0,l.jsx)(n.th,{children:"Description"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'.after("column")'})}),(0,l.jsxs)(n.td,{children:['Place the column "after" another column ',(0,l.jsx)("small",{children:"(MySQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".autoIncrement()"})}),(0,l.jsx)(n.td,{children:"Set INTEGER columns as auto-incrementing (primary key)."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'.charset("utf8mb4")'})}),(0,l.jsxs)(n.td,{children:["Specify a character set for the column ",(0,l.jsx)("small",{children:"(MySQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)("small",{children:(0,l.jsx)(n.code,{children:'.collation("utf8mb4_unicode_ci")'})})}),(0,l.jsxs)(n.td,{children:["Specify a collation for the column ",(0,l.jsx)("small",{children:"(MySQL/PostgreSQL/SQL Server)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'.comment("my comment")'})}),(0,l.jsxs)(n.td,{children:["Add a comment to a column ",(0,l.jsx)("small",{children:"(MySQL / PostgreSQL)"}),".",(0,l.jsx)("br",{}),(0,l.jsx)("small",{children:"Special characters are escaped."})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".defaultValue(value)"})}),(0,l.jsxs)(n.td,{children:['Specify a "default" value for the column.',(0,l.jsx)("br",{}),(0,l.jsx)("small",{children:"Special characters are escaped."})]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".first()"})}),(0,l.jsxs)(n.td,{children:['Place the column "first" in the table ',(0,l.jsx)("small",{children:"(MySQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".from(integer)"})}),(0,l.jsxs)(n.td,{children:["Set the starting value of an auto-incrementing field, an alias for ",(0,l.jsx)(n.code,{children:"startingValue()"})," ",(0,l.jsx)("small",{children:"(MySQL / PostgreSQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".invisible()"})}),(0,l.jsxs)(n.td,{children:['Make the column "invisible" to ',(0,l.jsx)(n.code,{children:"SELECT *"})," queries ",(0,l.jsx)("small",{children:"(MySQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".nullable(value = true)"})}),(0,l.jsx)(n.td,{children:"Allow NULL values to be inserted into the column."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".startingValue(integer)"})}),(0,l.jsxs)(n.td,{children:["Set the starting value of an auto-incrementing field ",(0,l.jsx)("small",{children:"(MySQL / PostgreSQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".storedAs(expression)"})}),(0,l.jsxs)(n.td,{children:["Create a stored generated column ",(0,l.jsx)("small",{children:"(MySQL / PostgreSQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".unsigned()"})}),(0,l.jsxs)(n.td,{children:["Set INTEGER columns as UNSIGNED ",(0,l.jsx)("small",{children:"(MySQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".useCurrent()"})}),(0,l.jsx)(n.td,{children:"Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".useCurrentOnUpdate()"})}),(0,l.jsx)(n.td,{children:"Set TIMESTAMP columns to use CURRENT_TIMESTAMP when a record is updated."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".virtualAs(expression)"})}),(0,l.jsxs)(n.td,{children:["Create a virtual generated column ",(0,l.jsx)("small",{children:"(MySQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".generatedAs(expression)"})}),(0,l.jsxs)(n.td,{children:["Create an identity column with specified sequence options ",(0,l.jsx)("small",{children:"(PostgreSQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".always()"})}),(0,l.jsxs)(n.td,{children:["Defines the precedence of sequence values over input for an identity column ",(0,l.jsx)("small",{children:"(PostgreSQL)"}),"."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:".isGeometry()"})}),(0,l.jsxs)(n.td,{children:["Set spatial column type to ",(0,l.jsx)(n.code,{children:"geometry"})," - the default type is ",(0,l.jsx)(n.code,{children:"geography"})," ",(0,l.jsx)("small",{children:"(PostgreSQL)"}),"."]})]})]})]}),"\n",(0,l.jsx)(n.h4,{id:"default-expressions",children:"Default Expressions"}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"defaultValue"})," modifier accepts a value or an ",(0,l.jsx)(n.code,{children:"Orm::Query::Expression"})," instance. Using an ",(0,l.jsx)(n.code,{children:"Expression"})," instance will prevent TinyORM from wrapping the value in quotes and allow you to use database-specific functions. One situation where this is particularly useful is when you need to assign default values to JSON columns:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nusing Orm::Query::Expression;\n\nSchema::create("flights", [](Blueprint &table)\n{\n table.id();\n table.json("detail").defaultValue(Expression("(JSON_ARRAY(\'none\'))"));\n table.timestamps();\n});\n'})}),"\n",(0,l.jsx)(n.admonition,{type:"note",children:(0,l.jsx)(n.p,{children:"Support for default expressions depends on your database driver, database version, and the field type. Please refer to your database's documentation."})}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["You can obtain an ",(0,l.jsx)(n.code,{children:"Orm::Query::Expression"})," using the ",(0,l.jsx)(n.a,{href:"/database/query-builder#raw-expressions",children:(0,l.jsx)(n.code,{children:"DB::raw"})})," method if you have access to the ",(0,l.jsx)(n.code,{children:"DB"})," facade."]})}),"\n",(0,l.jsx)(n.h4,{id:"column-order",children:"Column Order"}),"\n",(0,l.jsxs)(n.p,{children:["When using the MySQL database, the ",(0,l.jsx)(n.code,{children:"after"})," method may be used to add columns after an existing column in the schema:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.after("password", [](Blueprint &table)\n{\n table.string("address_line1");\n table.string("address_line2");\n table.string("city");\n});\n'})}),"\n",(0,l.jsx)(n.h3,{id:"modifying-columns",children:"Modifying Columns"}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"change"})," method allows you to modify the type and attributes of existing columns. For example, you may wish to increase the size of a ",(0,l.jsx)(n.code,{children:"string"})," column. To see the ",(0,l.jsx)(n.code,{children:"change"})," method in action, let's increase the size of the ",(0,l.jsx)(n.code,{children:"name"})," column from 25 to 50. To accomplish this, we simply define the new state of the column and then call the ",(0,l.jsx)(n.code,{children:"change"})," method:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.string("name", 50).change();\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["When modifying a column, you must explicitly include all of the modifiers you want to keep on the column definition - any missing attribute will be dropped. For example, to retain the ",(0,l.jsx)(n.code,{children:"unsigned"}),", ",(0,l.jsx)(n.code,{children:"default"}),", and ",(0,l.jsx)(n.code,{children:"comment"})," attributes, you must call each modifier explicitly when changing the column:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::table("users", [](Blueprint &table)\n{\n table.integer("votes").isUnsigned().defaultValue(1).comment("my comment").change();\n});\n'})}),"\n",(0,l.jsx)(n.admonition,{type:"info",children:(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"change"})," method and modifying columns is not implemented for the ",(0,l.jsx)(n.code,{children:"SQLite"})," database because it doesn't support modifying columns out of the box."]})}),"\n",(0,l.jsx)(n.h4,{id:"renaming-columns",children:"Renaming Columns"}),"\n",(0,l.jsxs)(n.p,{children:["To rename a column, you may use the ",(0,l.jsx)(n.code,{children:"renameColumn"})," method provided by the schema builder blueprint:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::table("users", [](Blueprint &table)\n{\n table.renameColumn("from", "to");\n});\n'})}),"\n",(0,l.jsx)(n.h4,{id:"renaming-columns-on-legacy-databases",children:"Renaming Columns On Legacy Databases"}),"\n",(0,l.jsx)(n.p,{children:"Renaming columns is not supported if you are running a database installation older than one of the following releases:"}),"\n",(0,l.jsxs)(n.ul,{children:["\n",(0,l.jsxs)(n.li,{children:["MySQL ",(0,l.jsx)(n.code,{children:"<8.0.3"})]}),"\n",(0,l.jsxs)(n.li,{children:["MariaDB ",(0,l.jsx)(n.code,{children:"<10.5.2"})]}),"\n",(0,l.jsxs)(n.li,{children:["SQLite ",(0,l.jsx)(n.code,{children:"<3.25.0"})]}),"\n"]}),"\n",(0,l.jsx)(n.h3,{id:"dropping-columns",children:"Dropping Columns"}),"\n",(0,l.jsxs)(n.p,{children:["To drop a column, you may use the ",(0,l.jsx)(n.code,{children:"dropColumn"})," method on the schema builder blueprint:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::table("users", [](Blueprint &table)\n{\n table.dropColumn("votes");\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["You may drop multiple columns from a table by passing a ",(0,l.jsx)(n.code,{children:"QVector<QString>"})," of column names to the ",(0,l.jsx)(n.code,{children:"dropColumns"})," method, the ",(0,l.jsx)(n.code,{children:"dropColumns"})," method also provides parameter pack overload:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::table("users", [](Blueprint &table)\n{\n table.dropColumns({"votes", "avatar", "location"});\n // Parameter pack overload\n table.dropColumns("votes", "avatar", "location");\n});\n'})}),"\n",(0,l.jsx)(n.admonition,{type:"warning",children:(0,l.jsxs)(n.p,{children:["The SQLite prior to ",(0,l.jsx)(n.code,{children:"v3.35.0"})," doesn't support dropping columns using the ",(0,l.jsx)(n.code,{children:"ALTER TABLE DROP COLUMN"}),", dropping columns was added in the SQLite ",(0,l.jsx)(n.code,{children:"v3.35.0"})," as is described in the ",(0,l.jsx)(n.a,{href:"https://www.sqlite.org/releaselog/3_35_0.html",children:"release notes"}),"."]})}),"\n",(0,l.jsx)(n.h4,{id:"available-command-aliases",children:"Available Command Aliases"}),"\n",(0,l.jsx)(n.p,{children:"TinyORM provides several convenient methods related to dropping common types of columns. Each of these methods is described in the table below:"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Command"}),(0,l.jsx)(n.th,{children:"Description"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.dropRememberToken();"})}),(0,l.jsxs)(n.td,{children:["Drop the ",(0,l.jsx)(n.code,{children:"remember_token"})," column."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.dropSoftDeletes();"})}),(0,l.jsxs)(n.td,{children:["Drop the ",(0,l.jsx)(n.code,{children:"deleted_at"})," column."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.dropSoftDeletesDatetime();"})}),(0,l.jsxs)(n.td,{children:["Alias of ",(0,l.jsx)(n.code,{children:"dropSoftDeletes()"})," method."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.dropSoftDeletesTz();"})}),(0,l.jsxs)(n.td,{children:["Alias of ",(0,l.jsx)(n.code,{children:"dropSoftDeletes()"})," method."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.dropTimestamps();"})}),(0,l.jsxs)(n.td,{children:["Drop the ",(0,l.jsx)(n.code,{children:"created_at"})," and ",(0,l.jsx)(n.code,{children:"updated_at"})," columns."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.dropTimestampsTz();"})}),(0,l.jsxs)(n.td,{children:["Alias of ",(0,l.jsx)(n.code,{children:"dropTimestamps()"})," method."]})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.dropDatetimes();"})}),(0,l.jsxs)(n.td,{children:["Alias of ",(0,l.jsx)(n.code,{children:"dropTimestamps()"})," method."]})]})]})]}),"\n",(0,l.jsx)(n.h2,{id:"indexes",children:"Indexes"}),"\n",(0,l.jsx)(n.h3,{id:"creating-indexes",children:"Creating Indexes"}),"\n",(0,l.jsxs)(n.p,{children:["The TinyORM schema builder supports several types of indexes. The following example creates a new ",(0,l.jsx)(n.code,{children:"email"})," column and specifies that its values should be unique. To create the index, we can chain the ",(0,l.jsx)(n.code,{children:"unique"})," method onto the column definition:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.string("email").unique();\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["Alternatively, you may create the index after defining the column. To do so, you should call the ",(0,l.jsx)(n.code,{children:"unique"})," method on the schema builder blueprint. This method accepts the name of the column that should receive a unique index:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unique("email");\n'})}),"\n",(0,l.jsxs)(n.p,{children:["You may even pass a ",(0,l.jsx)(n.code,{children:"QVector<QString>"})," of columns to an index method to create a compound (or composite) index:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.index({"account_id", "created_at"});\n'})}),"\n",(0,l.jsx)(n.p,{children:"When creating an index, TinyORM will automatically generate an index name based on the table, column names, and the index type (eg. users_email_unique), but you may pass a second argument to the method to specify the index name yourself:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.unique("email", "unique_email");\n'})}),"\n",(0,l.jsx)(n.h4,{id:"available-index-types",children:"Available Index Types"}),"\n",(0,l.jsx)(n.p,{children:"TinyORM's schema builder blueprint class provides methods for creating each type of index supported by TinyORM. Each index method accepts an optional second argument to specify the name of the index. If omitted, the name will be derived from the names of the table and column(s) used for the index, as well as the index type (eg. users_email_fulltext). Each of the available index methods is described in the table below:"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Command"}),(0,l.jsx)(n.th,{children:"Description"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.primary("id");'})}),(0,l.jsx)(n.td,{children:"Adds a primary key."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.primary({"id", "parent_id"});'})}),(0,l.jsx)(n.td,{children:"Adds composite keys."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.unique("email");'})}),(0,l.jsx)(n.td,{children:"Adds a unique index."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.index("state");'})}),(0,l.jsx)(n.td,{children:"Adds an index."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.fullText("body");'})}),(0,l.jsx)(n.td,{children:"Adds a full text index (MySQL/PostgreSQL)."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)("small",{children:(0,l.jsx)(n.code,{children:'table.fullText("body").language("english");'})})}),(0,l.jsx)(n.td,{children:"Adds a full text index of the specified language (PostgreSQL)."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.spatialIndex("location");'})}),(0,l.jsx)(n.td,{children:"Adds a spatial index (except SQLite)."})]})]})]}),"\n",(0,l.jsx)(n.h4,{id:"index-lengths--mysql--mariadb",children:"Index Lengths & MySQL / MariaDB"}),"\n",(0,l.jsxs)(n.p,{children:["By default, TinyORM uses the ",(0,l.jsx)(n.code,{children:"utf8mb4"})," character set. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure the default string length by calling the ",(0,l.jsx)(n.code,{children:"Schema::defaultStringLength"})," method:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"#include <orm/schema.hpp>\n\nSchema::defaultStringLength(191);\n"})}),"\n",(0,l.jsx)(n.admonition,{type:"tip",children:(0,l.jsxs)(n.p,{children:["Alternatively, you may enable the ",(0,l.jsx)(n.code,{children:"innodb_large_prefix"})," option for your database (enabled by default in >=MySQL 5.7.7). Refer to your database's documentation for instructions on how to properly enable this option."]})}),"\n",(0,l.jsx)(n.h3,{id:"renaming-indexes",children:"Renaming Indexes"}),"\n",(0,l.jsxs)(n.p,{children:["To rename an index, you may use the ",(0,l.jsx)(n.code,{children:"renameIndex"})," method provided by the schema builder blueprint. This method accepts the current index name as its first argument and the desired name as its second argument:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.renameIndex("from", "to");\n'})}),"\n",(0,l.jsx)(n.h3,{id:"dropping-indexes",children:"Dropping Indexes"}),"\n",(0,l.jsx)(n.p,{children:"To drop an index, you must specify the index's name. By default, TinyORM automatically assigns an index name based on the table name, the name of the indexed column, and the index type (eg. users_email_unique). Here are some examples:"}),"\n",(0,l.jsx)("div",{id:"apitable-dropping-indexes",children:(0,l.jsx)(s.A,{children:(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Command"}),(0,l.jsx)(n.th,{children:"Description"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.dropPrimary("users_id_primary");'})}),(0,l.jsx)(n.td,{children:'Drop a primary key from the "users" table.'})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.dropUnique("users_email_unique");'})}),(0,l.jsx)(n.td,{children:'Drop a unique index from the "users" table.'})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:'table.dropIndex("geo_state_index");'})}),(0,l.jsx)(n.td,{children:'Drop a basic index from the "geo" table.'})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)("small",{children:(0,l.jsx)(n.code,{children:'table.dropFullText("posts_body_fulltext");'})})}),(0,l.jsx)(n.td,{children:'Drop a full text index from the "posts" table.'})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)("small",{children:(0,l.jsx)(n.code,{children:'.dropSpatialIndex("geo_location_spatialindex");'})})}),(0,l.jsx)(n.td,{children:'Drop a spatial index from the "geo" table (except SQLite).'})]})]})]})})}),"\n",(0,l.jsxs)(n.p,{children:["I may also drop indexes by a column name or column names for composite keys, if you pass a ",(0,l.jsx)(n.code,{children:"QVector<QString>"})," of columns into a method that drops indexes, the conventional index name will be generated based on the table name, columns, and index type:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::table("geo", [](Blueprint &table)\n{\n table.dropIndex({"state"}); // Drops index \'geo_state_index\'\n});\n'})}),"\n",(0,l.jsx)(n.h3,{id:"foreign-key-constraints",children:"Foreign Key Constraints"}),"\n",(0,l.jsxs)(n.p,{children:["TinyORM also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a ",(0,l.jsx)(n.code,{children:"user_id"})," column on the ",(0,l.jsx)(n.code,{children:"posts"})," table that references the ",(0,l.jsx)(n.code,{children:"id"})," column on a ",(0,l.jsx)(n.code,{children:"users"})," table:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/schema.hpp>\n\nusing Orm::Constants::ID;\n\nSchema::table("posts", [](Blueprint &table)\n{\n table.unsignedBigInteger("user_id");\n\n table.foreign("user_id").references(ID).on("users");\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["Since this syntax is rather verbose, TinyORM provides additional, terser methods that use conventions to provide a better developer experience. When using the ",(0,l.jsx)(n.code,{children:"foreignId"})," method to create your column, the example above can be rewritten like so:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::table("posts", [](Blueprint &table)\n{\n table.foreignId("user_id").constrained();\n});\n'})}),"\n",(0,l.jsxs)(n.p,{children:["The ",(0,l.jsx)(n.code,{children:"foreignId"})," method creates an ",(0,l.jsx)(n.code,{children:"UNSIGNED BIGINT"})," equivalent column, while the ",(0,l.jsx)(n.code,{children:"constrained"})," method will use conventions to determine the table and column name being referenced. If your table name does not match TinyORM's conventions, you may specify the table name by passing it as an argument to the ",(0,l.jsx)(n.code,{children:"constrained"})," method:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'Schema::table("posts", [](Blueprint &table)\n{\n table.foreignId("user_id").constrained("users");\n});\n'})}),"\n",(0,l.jsx)(n.p,{children:'You may also specify the desired action for the "on delete" and "on update" properties of the constraint:'}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'#include <orm/constants.hpp>\n\nusing Orm::SchemaNs::Constants::Cascade;\n\ntable.foreignId("user_id")\n .constrained()\n .onUpdate("cascade")\n .onDelete(Cascade);\n'})}),"\n",(0,l.jsx)(n.p,{children:"An alternative, expressive syntax is also provided for these actions:"}),"\n",(0,l.jsxs)(n.table,{children:[(0,l.jsx)(n.thead,{children:(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.th,{children:"Method"}),(0,l.jsx)(n.th,{children:"Description"})]})}),(0,l.jsxs)(n.tbody,{children:[(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.cascadeOnUpdate();"})}),(0,l.jsx)(n.td,{children:"Updates should cascade."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.restrictOnUpdate();"})}),(0,l.jsx)(n.td,{children:"Updates should be restricted."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.cascadeOnDelete();"})}),(0,l.jsx)(n.td,{children:"Deletes should cascade."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.restrictOnDelete();"})}),(0,l.jsx)(n.td,{children:"Deletes should be restricted."})]}),(0,l.jsxs)(n.tr,{children:[(0,l.jsx)(n.td,{children:(0,l.jsx)(n.code,{children:"table.nullOnDelete();"})}),(0,l.jsx)(n.td,{children:"Deletes should set the foreign key value to null."})]})]})]}),"\n",(0,l.jsxs)(n.p,{children:["Any additional ",(0,l.jsx)(n.a,{href:"#column-modifiers",children:"column modifiers"})," must be called before the ",(0,l.jsx)(n.code,{children:"constrained"})," method:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.foreignId("user_id")\n .nullable()\n .constrained();\n'})}),"\n",(0,l.jsx)(n.h4,{id:"dropping-foreign-keys",children:"Dropping Foreign Keys"}),"\n",(0,l.jsxs)(n.p,{children:["To drop a foreign key, you may use the ",(0,l.jsx)(n.code,{children:"dropForeign"}),' method, passing the name of the foreign key constraint to be deleted as an argument. Foreign key constraints use the same naming convention as indexes. In other words, the foreign key constraint name is based on the name of the table and the columns in the constraint, followed by a "_foreign" suffix:']}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.dropForeign("posts_user_id_foreign");\n'})}),"\n",(0,l.jsxs)(n.p,{children:["Alternatively, you may pass a ",(0,l.jsx)(n.code,{children:"QVector<QString>"})," containing the column name that holds the foreign key to the ",(0,l.jsx)(n.code,{children:"dropForeign"})," method. The ",(0,l.jsx)(n.code,{children:"QVector"})," will be converted to a foreign key constraint name using TinyORM's constraint naming conventions:"]}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:'table.dropForeign({"user_id"});\n'})}),"\n",(0,l.jsx)(n.h4,{id:"toggling-foreign-key-constraints",children:"Toggling Foreign Key Constraints"}),"\n",(0,l.jsx)(n.p,{children:"You may enable or disable foreign key constraints within your migrations by using the following methods:"}),"\n",(0,l.jsx)(n.pre,{children:(0,l.jsx)(n.code,{className:"language-cpp",children:"Schema::enableForeignKeyConstraints();\n\nSchema::disableForeignKeyConstraints();\n\nSchema::withoutForeignKeyConstraints([]\n{\n // Constraints disabled within this lambda expression...\n});\n"})}),"\n",(0,l.jsx)(n.admonition,{type:"warning",children:(0,l.jsxs)(n.p,{children:["The SQLite disables foreign key constraints by default. When using SQLite, make sure to ",(0,l.jsx)(n.a,{href:"/database/getting-started#sqlite-configuration",children:"enable foreign key support"})," in your database configuration before attempting to create them in your migrations. In addition, SQLite only supports creating foreign keys when creating tables and ",(0,l.jsx)(n.a,{href:"https://www.sqlite.org/omitted.html",children:"not when tables are altered"}),"."]})})]})}function g(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,l.jsx)(n,{...e,children:(0,l.jsx)(j,{...e})}):j(e)}},9365:(e,n,i)=>{i.d(n,{A:()=>d});i(6540);var l=i(4164);const t={tabItem:"tabItem_Ymn6"};var s=i(4848);function d(e){let{children:n,hidden:i,className:d}=e;return(0,s.jsx)("div",{role:"tabpanel",className:(0,l.A)(t.tabItem,d),hidden:i,children:n})}},1470:(e,n,i)=>{i.d(n,{A:()=>T});var l=i(6540),t=i(4164),s=i(3104),d=i(6347),a=i(205),o=i(7485),r=i(1682),c=i(9466);function h(e){return l.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,l.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 <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function m(e){const{values:n,children:i}=e;return(0,l.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:i,attributes:l,default:t}}=e;return{value:n,label:i,attributes:l,default:t}}))}(i);return function(e){const n=(0,r.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 <Tabs>. Every value needs to be unique.`)}(e),e}),[n,i])}function u(e){let{value:n,tabValues:i}=e;return i.some((e=>e.value===n))}function x(e){let{queryString:n=!1,groupId:i}=e;const t=(0,d.W6)(),s=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 <Tabs> 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)(s),(0,l.useCallback)((e=>{if(!s)return;const n=new URLSearchParams(t.location.search);n.set(s,e),t.replace({...t.location,search:n.toString()})}),[s,t])]}function p(e){const{defaultValue:n,queryString:i=!1,groupId:t}=e,s=m(e),[d,o]=(0,l.useState)((()=>function(e){let{defaultValue:n,tabValues:i}=e;if(0===i.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(n){if(!u({value:n,tabValues:i}))throw new Error(`Docusaurus error: The <Tabs> 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 l=i.find((e=>e.default))??i[0];if(!l)throw new Error("Unexpected error: 0 tabValues");return l.value}({defaultValue:n,tabValues:s}))),[r,h]=x({queryString:i,groupId:t}),[p,j]=function(e){let{groupId:n}=e;const i=function(e){return e?`docusaurus.tab.${e}`:null}(n),[t,s]=(0,c.Dv)(i);return[t,(0,l.useCallback)((e=>{i&&s.set(e)}),[i,s])]}({groupId:t}),g=(()=>{const e=r??p;return u({value:e,tabValues:s})?e:null})();(0,a.A)((()=>{g&&o(g)}),[g]);return{selectedValue:d,selectValue:(0,l.useCallback)((e=>{if(!u({value:e,tabValues:s}))throw new Error(`Can't select invalid tab value=${e}`);o(e),h(e),j(e)}),[h,j,s]),tabValues:s}}var j=i(2303);const g={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var b=i(4848);function f(e){let{className:n,block:i,selectedValue:l,selectValue:d,tabValues:a}=e;const o=[],{blockElementScrollPositionUntilNextRender:r}=(0,s.a_)(),c=e=>{const n=e.currentTarget,i=o.indexOf(n),t=a[i].value;t!==l&&(r(n),d(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:a.map((e=>{let{value:n,label:i,attributes:s}=e;return(0,b.jsx)("li",{role:"tab",tabIndex:l===n?0:-1,"aria-selected":l===n,ref:e=>o.push(e),onKeyDown:h,onClick:c,...s,className:(0,t.A)("tabs__item",g.tabItem,s?.className,{"tabs__item--active":l===n}),children:i??n},n)}))})}function y(e){let{lazy:n,children:i,selectedValue:t}=e;const s=(Array.isArray(i)?i:[i]).filter(Boolean);if(n){const e=s.find((e=>e.props.value===t));return e?(0,l.cloneElement)(e,{className:"margin-top--md"}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:s.map(((e,n)=>(0,l.cloneElement)(e,{key:n,hidden:e.props.value!==t})))})}function v(e){const n=p(e);return(0,b.jsxs)("div",{className:(0,t.A)("tabs-container",g.tabList),children:[(0,b.jsx)(f,{...n,...e}),(0,b.jsx)(y,{...n,...e})]})}function T(e){const n=(0,j.A)();return(0,b.jsx)(v,{...e,children:h(e.children)},String(n))}},6684:(e,n,i)=>{i.d(n,{A:()=>c});var l=i(6540),t=i(3427),s=i(6347);const d={apiTable:"apiTable_flxF"};var a=i(4848);function o(e,n){let{name:i,children:d}=e;const o=function(e){let n=e;for(;(0,l.isValidElement)(n);)[n]=l.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}(d),r=i?`${i}-${o}`:o,c=`#${r}`,h=(0,s.W6)();return(0,t.A)().collectAnchor(r),(0,a.jsx)("tr",{id:r,tabIndex:0,ref:h.location.hash===c?n:void 0,onClick:e=>{const n=e.target;[n,n.parentElement].some((e=>"A"===e?.tagName.toUpperCase()))||h.push(c)},onKeyDown:e=>{"Enter"===e.key&&h.push(c)},children:d.props.children})}const r=l.forwardRef(o);function c(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[t,s]=l.Children.toArray(n.props.children),o=(0,l.useRef)(null);(0,l.useEffect)((()=>{o.current?.focus()}),[o]);const c=l.Children.map(s.props.children,(e=>(0,a.jsx)(r,{name:i,ref:o,children:e})));return(0,a.jsxs)("table",{className:d.apiTable,children:[t,(0,a.jsx)("tbody",{children:c})]})}},7324:(e,n,i)=>{i.d(n,{$E:()=>j,A3:()=>b,CW:()=>g,Dx:()=>c,F4:()=>m,Fi:()=>r,J_:()=>T,LQ:()=>f,Lf:()=>I,OO:()=>t,Q7:()=>y,b:()=>a,cy:()=>o,gg:()=>x,kl:()=>u,os:()=>h,pW:()=>s,ux:()=>p,vf:()=>l,xj:()=>d,xt:()=>v});const l="shell",t="database",s="application",d="bash",a="pwsh",o="zsh",r="maria",c="mysql",h="postgres",m="sqlite",u="application",x="bash",p="pwsh",j="zsh",g="MariaDB",b="MySQL",f="PostgreSQL",y="SQLite",v="tinyorm.org",T="$HOME/Code/c/",I="$env:USERPROFILE\\Code\\c\\"},6362:(e,n,i)=>{i.d(n,{A:()=>s});var l=i(6540),t=i(1838);function s(){const e=(0,l.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:()=>d,T3:()=>c,bw:()=>r,nC:()=>h,np:()=>a});var l=i(6362),t=i(2303),s=i(7324);const d=function(e,n){return void 0===n&&(n=!0),m((0,l.A)().rootFolder[e]??r(e),e,n)},a=()=>(0,l.A)().rootFolder[s.pW]??r(s.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!==s.b?"/":"\\";return m(d(e)+i+a(),e,n)};function r(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,t.A)())return"";switch(e){case s.b:return s.Lf;case s.xj:return s.J_;case s.pW:return s.xt;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function c(e){return e===s.pW}function h(e,n){if(null==n||""===n)return n;const i="$ENV{$1}$2";switch(e){case s.b:return x(n).replace(/\$env:(.+?)(\/.*)/,i);case s.xj:return n.replace(/\$(.+?)(\/.*)/,i);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function m(e,n,i){if(void 0===i&&(i=!0),null==e||""===e)return e;if(n!==s.b)return u(e);const l=u(e);return i?x(l):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(l)}function u(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function x(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},5848:(e,n,i)=>{i.d(n,{A:()=>l});const l=i.p+"assets/images/tom_cli-402f7dd4dfe7dbd0b20dfe5fb61838a2.png"}}]); \ No newline at end of file diff --git a/assets/js/21dc2778.9ec72537.js b/assets/js/21dc2778.9ec72537.js deleted file mode 100644 index f4702c513..000000000 --- a/assets/js/21dc2778.9ec72537.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[291],{5162:(e,t,n)=>{n.d(t,{Z:()=>o});var a=n(7294),i=n(6010);const l={tabItem:"tabItem_Ymn6"};function o(e){let{children:t,hidden:n,className:o}=e;return a.createElement("div",{role:"tabpanel",className:(0,i.Z)(l.tabItem,o),hidden:n},t)}},4866:(e,t,n)=>{n.d(t,{Z:()=>C});var a=n(7462),i=n(7294),l=n(6010),o=n(2466),r=n(6550),m=n(1980),d=n(7392),p=n(12);function s(e){return function(e){return i.Children.map(e,(e=>{if(!e||(0,i.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(e).map((e=>{let{props:{value:t,label:n,attributes:a,default:i}}=e;return{value:t,label:n,attributes:a,default:i}}))}function u(e){const{values:t,children:n}=e;return(0,i.useMemo)((()=>{const e=t??s(n);return function(e){const t=(0,d.l)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e}),[t,n])}function c(e){let{value:t,tabValues:n}=e;return n.some((e=>e.value===t))}function h(e){let{queryString:t=!1,groupId:n}=e;const a=(0,r.k6)(),l=function(e){let{queryString:t=!1,groupId:n}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!n)throw new Error('Docusaurus error: The <Tabs> 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 n??null}({queryString:t,groupId:n});return[(0,m._X)(l),(0,i.useCallback)((e=>{if(!l)return;const t=new URLSearchParams(a.location.search);t.set(l,e),a.replace({...a.location,search:t.toString()})}),[l,a])]}function k(e){const{defaultValue:t,queryString:n=!1,groupId:a}=e,l=u(e),[o,r]=(0,i.useState)((()=>function(e){let{defaultValue:t,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(t){if(!c({value:t,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const a=n.find((e=>e.default))??n[0];if(!a)throw new Error("Unexpected error: 0 tabValues");return a.value}({defaultValue:t,tabValues:l}))),[m,d]=h({queryString:n,groupId:a}),[s,k]=function(e){let{groupId:t}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(t),[a,l]=(0,p.Nk)(n);return[a,(0,i.useCallback)((e=>{n&&l.set(e)}),[n,l])]}({groupId:a}),g=(()=>{const e=m??s;return c({value:e,tabValues:l})?e:null})();(0,i.useLayoutEffect)((()=>{g&&r(g)}),[g]);return{selectedValue:o,selectValue:(0,i.useCallback)((e=>{if(!c({value:e,tabValues:l}))throw new Error(`Can't select invalid tab value=${e}`);r(e),d(e),k(e)}),[d,k,l]),tabValues:l}}var g=n(2389);const N={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function b(e){let{className:t,block:n,selectedValue:r,selectValue:m,tabValues:d}=e;const p=[],{blockElementScrollPositionUntilNextRender:s}=(0,o.o5)(),u=e=>{const t=e.currentTarget,n=p.indexOf(t),a=d[n].value;a!==r&&(s(t),m(a))},c=e=>{let t=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{const n=p.indexOf(e.currentTarget)+1;t=p[n]??p[0];break}case"ArrowLeft":{const n=p.indexOf(e.currentTarget)-1;t=p[n]??p[p.length-1];break}}t?.focus()};return i.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,l.Z)("tabs",{"tabs--block":n},t)},d.map((e=>{let{value:t,label:n,attributes:o}=e;return i.createElement("li",(0,a.Z)({role:"tab",tabIndex:r===t?0:-1,"aria-selected":r===t,key:t,ref:e=>p.push(e),onKeyDown:c,onClick:u},o,{className:(0,l.Z)("tabs__item",N.tabItem,o?.className,{"tabs__item--active":r===t})}),n??t)})))}function f(e){let{lazy:t,children:n,selectedValue:a}=e;const l=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){const e=l.find((e=>e.props.value===a));return e?(0,i.cloneElement)(e,{className:"margin-top--md"}):null}return i.createElement("div",{className:"margin-top--md"},l.map(((e,t)=>(0,i.cloneElement)(e,{key:t,hidden:e.props.value!==a}))))}function y(e){const t=k(e);return i.createElement("div",{className:(0,l.Z)("tabs-container",N.tabList)},i.createElement(b,(0,a.Z)({},e,t)),i.createElement(f,(0,a.Z)({},e,t)))}function C(e){const t=(0,g.Z)();return i.createElement(y,(0,a.Z)({key:String(t)},e))}},5178:(e,t,n)=>{n.d(t,{Z:()=>m});var a=n(7294),i=n(6550);const l={apiTable:"apiTable_flxF"};function o(e,t){let{name:n,children:l}=e;const o=function(e){let t=e;for(;(0,a.isValidElement)(t);)[t]=a.Children.toArray(t.props.children);if("string"!=typeof t)throw new Error(`Could not extract APITable row name from JSX tree:\n${JSON.stringify(e,null,2)}`);return t}(l),r=n?`${n}-${o}`:o,m=`#${r}`,d=(0,i.k6)();return a.createElement("tr",{id:r,tabIndex:0,ref:d.location.hash===m?t:void 0,onClick:e=>{const t=e.target;"A"===t.tagName.toUpperCase()||"A"===t.parentElement?.tagName.toUpperCase()||d.push(m)},onKeyDown:e=>{"Enter"===e.key&&d.push(m)}},l.props.children)}const r=a.forwardRef(o);function m(e){let{children:t,name:n}=e;const[i,o]=a.Children.toArray(t.props.children),m=(0,a.useRef)(null);(0,a.useEffect)((()=>{m.current?.focus()}),[m]);const d=a.Children.map(o.props.children,(e=>a.createElement(r,{name:n,ref:m},e)));return a.createElement("table",{className:l.apiTable},i,a.createElement("tbody",null,d))}},2044:(e,t,n)=>{n.d(t,{$t:()=>s,Ae:()=>g,C:()=>h,DK:()=>N,Fo:()=>r,Fs:()=>i,IM:()=>k,IZ:()=>a,RS:()=>T,VE:()=>b,Wg:()=>y,_A:()=>d,al:()=>v,jk:()=>c,js:()=>m,of:()=>p,q5:()=>o,qb:()=>C,vk:()=>u,wU:()=>l,zg:()=>f});const a="shell",i="database",l="application",o="bash",r="pwsh",m="zsh",d="maria",p="mysql",s="postgres",u="sqlite",c="application",h="bash",k="pwsh",g="zsh",N="MariaDB",b="MySQL",f="PostgreSQL",y="SQLite",C="tinyorm.org",v="$HOME/Code/c/",T="$env:USERPROFILE\\Code\\c\\"},4355:(e,t,n)=>{n.d(t,{Z:()=>l});var a=n(7294),i=n(9482);function l(){const e=(0,a.useContext)(i.Z);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6005:(e,t,n)=>{n.d(t,{AE:()=>r,EA:()=>o,em:()=>d,go:()=>m,mT:()=>p,we:()=>s});var a=n(4355),i=n(2389),l=n(2044);const o=function(e,t){return void 0===t&&(t=!0),u((0,a.Z)().rootFolder[e]??d(e),e,t)},r=()=>(0,a.Z)().rootFolder[l.wU]??d(l.wU),m=function(e,t){if(void 0===t&&(t=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const n=t||e!==l.Fo?"/":"\\";return u(o(e)+n+r(),e,t)};function d(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,i.Z)())return"";switch(e){case l.Fo:return l.RS;case l.q5:return l.al;case l.wU:return l.qb;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function p(e){return e===l.wU}function s(e,t){if(null==t||""===t)return t;const n="$ENV{$1}$2";switch(e){case l.Fo:return h(t).replace(/\$env:(.+?)(\/.*)/,n);case l.q5:return t.replace(/\$(.+?)(\/.*)/,n);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function u(e,t,n){if(void 0===n&&(n=!0),null==e||""===e)return e;if(t!==l.Fo)return c(e);const a=c(e);return n?h(a):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(a)}function c(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function h(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},6122:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>h,contentTitle:()=>u,default:()=>b,frontMatter:()=>s,metadata:()=>c,toc:()=>k});var a=n(7462),i=(n(7294),n(3905)),l=n(5178),o=n(7693),r=n(5162),m=n(4866),d=n(2044),p=n(6005);const s={sidebar_position:2,sidebar_label:"Migrations",description:"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems.",keywords:["c++ orm","database","migrations","tinyorm"]},u="Database: Migrations",c={unversionedId:"database/migrations",id:"database/migrations",title:"Database: Migrations",description:"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems.",source:"@site/docs/database/migrations.mdx",sourceDirName:"database",slug:"/database/migrations",permalink:"/database/migrations",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/database/migrations.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Migrations",description:"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems.",keywords:["c++ orm","database","migrations","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Query Builder",permalink:"/database/query-builder"},next:{title:"Seeding",permalink:"/database/seeding"}},h={},k=[{value:"Introduction",id:"introduction",level:2},{value:"Generating Migrations",id:"generating-migrations",level:2},{value:"Migrations naming rules",id:"migrations-naming-rules",level:4},{value:"Tab completion",id:"tab-completion",level:2},{value:"Alternative installation methods",id:"alternative-installation-methods",level:3},{value:"Static installation",id:"static-installation",level:4},{value:"Dynamic installation",id:"dynamic-installation",level:4},{value:"Migration Structure",id:"migration-structure",level:2},{value:"Setting The Migration Connection",id:"setting-the-migration-connection",level:4},{value:"Running Migrations",id:"running-migrations",level:2},{value:"Forcing Migrations To Run In Production",id:"forcing-migrations-to-run-in-production",level:4},{value:"Rolling Back Migrations",id:"rolling-back-migrations",level:3},{value:"Roll Back & Migrate Using A Single Command",id:"roll-back--migrate-using-a-single-command",level:4},{value:"Drop All Tables & Migrate",id:"drop-all-tables--migrate",level:4},{value:"Tables",id:"tables",level:2},{value:"Creating Tables",id:"creating-tables",level:3},{value:"Checking For Table / Column Existence",id:"checking-for-table--column-existence",level:4},{value:"Database Connection & Table Options",id:"database-connection--table-options",level:4},{value:"Updating Tables",id:"updating-tables",level:3},{value:"Renaming / Dropping Tables",id:"renaming-and-dropping-tables",level:3},{value:"Renaming Tables With Foreign Keys",id:"renaming-tables-with-foreign-keys",level:4},{value:"Columns",id:"columns",level:2},{value:"Creating Columns",id:"creating-columns",level:3},{value:"Available Column Types",id:"available-column-types",level:3},{value:"<code>bigIncrements()</code>",id:"column-method-bigIncrements",level:4},{value:"<code>bigInteger()</code>",id:"column-method-bigInteger",level:4},{value:"<code>binary()</code>",id:"column-method-binary",level:4},{value:"<code>boolean()</code>",id:"column-method-boolean",level:4},{value:"<code>Char()</code>",id:"column-method-Char",level:4},{value:"<code>date()</code>",id:"column-method-date",level:4},{value:"<code>datetime()</code>",id:"column-method-datetime",level:4},{value:"<code>datetimes()</code>",id:"column-method-datetimes",level:4},{value:"<code>datetimeTz()</code>",id:"column-method-datetimeTz",level:4},{value:"<code>decimal()</code>",id:"column-method-decimal",level:4},{value:"<code>Double()</code>",id:"column-method-Double",level:4},{value:"<code>Enum()</code>",id:"column-method-Enum",level:4},{value:"<code>Float()</code>",id:"column-method-Float",level:4},{value:"<code>foreignId()</code>",id:"column-method-foreignId",level:4},{value:"<code>foreignIdFor()</code>",id:"column-method-foreignIdFor",level:4},{value:"<code>foreignUuid()</code>",id:"column-method-foreignUuid",level:4},{value:"<code>geometry()</code>",id:"column-method-geometry",level:4},{value:"<code>geometryCollection()</code>",id:"column-method-geometryCollection",level:4},{value:"<code>id()</code>",id:"column-method-id",level:4},{value:"<code>increments()</code>",id:"column-method-increments",level:4},{value:"<code>integer()</code>",id:"column-method-integer",level:4},{value:"<code>ipAddress()</code>",id:"column-method-ipAddress",level:4},{value:"<code>json()</code>",id:"column-method-json",level:4},{value:"<code>jsonb()</code>",id:"column-method-jsonb",level:4},{value:"<code>lineString()</code>",id:"column-method-lineString",level:4},{value:"<code>longBinary()</code>",id:"column-method-longBinary",level:4},{value:"<code>longText()</code>",id:"column-method-longText",level:4},{value:"<code>macAddress()</code>",id:"column-method-macAddress",level:4},{value:"<code>mediumBinary()</code>",id:"column-method-mediumBinary",level:4},{value:"<code>mediumIncrements()</code>",id:"column-method-mediumIncrements",level:4},{value:"<code>mediumInteger()</code>",id:"column-method-mediumInteger",level:4},{value:"<code>mediumText()</code>",id:"column-method-mediumText",level:4},{value:"<code>multiLineString()</code>",id:"column-method-multiLineString",level:4},{value:"<code>multiPoint()</code>",id:"column-method-multiPoint",level:4},{value:"<code>multiPolygon()</code>",id:"column-method-multiPolygon",level:4},{value:"<code>point()</code>",id:"column-method-point",level:4},{value:"<code>polygon()</code>",id:"column-method-polygon",level:4},{value:"<code>rememberToken()</code>",id:"column-method-rememberToken",level:4},{value:"<code>set()</code>",id:"column-method-set",level:4},{value:"<code>smallIncrements()</code>",id:"column-method-smallIncrements",level:4},{value:"<code>smallInteger()</code>",id:"column-method-smallInteger",level:4},{value:"<code>softDeletes()</code>",id:"column-method-softDeletes",level:4},{value:"<code>softDeletesDatetime()</code>",id:"column-method-softDeletesDatetime",level:4},{value:"<code>softDeletesTz()</code>",id:"column-method-softDeletesTz",level:4},{value:"<code>string()</code>",id:"column-method-string",level:4},{value:"<code>text()</code>",id:"column-method-text",level:4},{value:"<code>time()</code>",id:"column-method-time",level:4},{value:"<code>timeTz()</code>",id:"column-method-timeTz",level:4},{value:"<code>timestamp()</code>",id:"column-method-timestamp",level:4},{value:"<code>timestampTz()</code>",id:"column-method-timestampTz",level:4},{value:"<code>timestampsTz()</code>",id:"column-method-timestampsTz",level:4},{value:"<code>timestamps()</code>",id:"column-method-timestamps",level:4},{value:"<code>tinyBinary()</code>",id:"column-method-tinyBinary",level:4},{value:"<code>tinyIncrements()</code>",id:"column-method-tinyIncrements",level:4},{value:"<code>tinyInteger()</code>",id:"column-method-tinyInteger",level:4},{value:"<code>tinyText()</code>",id:"column-method-tinyText",level:4},{value:"<code>unsignedBigInteger()</code>",id:"column-method-unsignedBigInteger",level:4},{value:"<code>unsignedDecimal()</code>",id:"column-method-unsignedDecimal",level:4},{value:"<code>unsignedInteger()</code>",id:"column-method-unsignedInteger",level:4},{value:"<code>unsignedMediumInteger()</code>",id:"column-method-unsignedMediumInteger",level:4},{value:"<code>unsignedSmallInteger()</code>",id:"column-method-unsignedSmallInteger",level:4},{value:"<code>unsignedTinyInteger()</code>",id:"column-method-unsignedTinyInteger",level:4},{value:"<code>uuid()</code>",id:"column-method-uuid",level:4},{value:"<code>year()</code>",id:"column-method-year",level:4},{value:"Column Modifiers",id:"column-modifiers",level:3},{value:"Default Expressions",id:"default-expressions",level:4},{value:"Column Order",id:"column-order",level:4},{value:"Modifying Columns",id:"modifying-columns",level:3},{value:"Renaming Columns",id:"renaming-columns",level:4},{value:"Renaming Columns On Legacy Databases",id:"renaming-columns-on-legacy-databases",level:4},{value:"Dropping Columns",id:"dropping-columns",level:3},{value:"Available Command Aliases",id:"available-command-aliases",level:4},{value:"Indexes",id:"indexes",level:2},{value:"Creating Indexes",id:"creating-indexes",level:3},{value:"Available Index Types",id:"available-index-types",level:4},{value:"Index Lengths & MySQL / MariaDB",id:"index-lengths--mysql--mariadb",level:4},{value:"Renaming Indexes",id:"renaming-indexes",level:3},{value:"Dropping Indexes",id:"dropping-indexes",level:3},{value:"Foreign Key Constraints",id:"foreign-key-constraints",level:3},{value:"Dropping Foreign Keys",id:"dropping-foreign-keys",level:4},{value:"Toggling Foreign Key Constraints",id:"toggling-foreign-key-constraints",level:4}],g={toc:k},N="wrapper";function b(e){let{components:t,...s}=e;return(0,i.kt)(N,(0,a.Z)({},g,s,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"database-migrations"},"Database: Migrations"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#generating-migrations"},"Generating Migrations")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#tab-completion"},"Tab completion"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#alternative-installation-methods"},"Alternative installation methods")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#migration-structure"},"Migration Structure")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#running-migrations"},"Running Migrations"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#rolling-back-migrations"},"Rolling Back Migrations")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#tables"},"Tables"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#creating-tables"},"Creating Tables")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#updating-tables"},"Updating Tables")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#renaming-and-dropping-tables"},"Renaming / Dropping Tables")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#columns"},"Columns"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#creating-columns"},"Creating Columns")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#available-column-types"},"Available Column Types")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#column-modifiers"},"Column Modifiers")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#modifying-columns"},"Modifying Columns")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#dropping-columns"},"Dropping Columns")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#indexes"},"Indexes"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#creating-indexes"},"Creating Indexes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#renaming-indexes"},"Renaming Indexes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#dropping-indexes"},"Dropping Indexes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#foreign-key-constraints"},"Foreign Key Constraints"))))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,"Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. If you have ever had to tell a teammate to manually add a column to their local database schema after pulling in your changes from source control, you've faced the problem that database migrations solve."),(0,i.kt)("p",null,"The TinyORM ",(0,i.kt)("inlineCode",{parentName:"p"},"Schema")," facade provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems. Typically, migrations will use this facade to create and modify database tables and columns."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," migrations is a small console application that depends on the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. All migrations logic is compiled so recompilation is needed after adding a new migration class."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations#tables"},(0,i.kt)("inlineCode",{parentName:"a"},"schema builder"))," and ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations"},(0,i.kt)("inlineCode",{parentName:"a"},"migrations"))," don't support ",(0,i.kt)("a",{parentName:"p",href:"/database/getting-started#multi-threading-support"},"multi-threading"),".")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"TinyORM's schema builder supports all ",(0,i.kt)("a",{parentName:"p",href:"/database/getting-started#introduction"},"supported databases")," out of the box.")),(0,i.kt)("p",null,"The following image shows what the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," console application looks like. \u2728 As you can see it offers everything that is needed to generate and manage migrations and seeders and all of this is backed up with the tab completion."),(0,i.kt)("img",{src:n(9566).Z,alt:"TinyORM - Tom console application - Showcase",width:"760",title:"TinyORM - Tom console application - Showcase"}),(0,i.kt)("h2",{id:"generating-migrations"},"Generating Migrations"),(0,i.kt)("p",null,"You may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"make:migration")," ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," command to generate a database migration. The new migration will be placed in your ",(0,i.kt)("inlineCode",{parentName:"p"},"database/migrations")," directory. Each migration filename contains a timestamp that allows ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," to determine the order of the migrations:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:migration create_posts_table\n")),(0,i.kt)("p",null,"tom will use the name of the migration to attempt to guess the name of the table and whether or not the migration will be creating a new table. If ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," is able to determine the table name from the migration name, ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," will pre-fill the generated migration file with the specified table. Otherwise, you may simply specify the table in the migration file manually."),(0,i.kt)("p",null,"If you would like to specify a custom path for the generated migration, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"--path")," option when executing the ",(0,i.kt)("inlineCode",{parentName:"p"},"make:migration")," command. The given path should be relative to your ",(0,i.kt)("abbr",{title:"Current working directory"},"pwd")," or you can use the ",(0,i.kt)("inlineCode",{parentName:"p"},"--realpath")," option and pass the absolute path to the ",(0,i.kt)("inlineCode",{parentName:"p"},"--path")," option."),(0,i.kt)("h4",{id:"migrations-naming-rules"},"Migrations naming rules"),(0,i.kt)("p",null,"If the migration name starts with the ",(0,i.kt)("inlineCode",{parentName:"p"},"create_")," string then the stub for table creation will be used and if the migration name contains ",(0,i.kt)("inlineCode",{parentName:"p"},"_(from|to|in)_")," then the stub for table update will be used. You can override these rules using the ",(0,i.kt)("inlineCode",{parentName:"p"},"--create")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"--table")," options and specify the table name manually."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can also pass the full migration filename with the datetime prefix and extension to the ",(0,i.kt)("inlineCode",{parentName:"p"},"make:migration"),". This command is able to detect almost any combination of the passed value, with or without datetime prefix or extension if it is the filename; or StudlyCase, snake_case, or kebab-case if it is the classname or any combination described above. \ud83d\udc40")),(0,i.kt)("h2",{id:"tab-completion"},"Tab completion"),(0,i.kt)("p",null,"Tab completion is available for the ",(0,i.kt)("inlineCode",{parentName:"p"},"pwsh")," (on Linux too), ",(0,i.kt)("inlineCode",{parentName:"p"},"bash"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"zsh")," shells. For ",(0,i.kt)("inlineCode",{parentName:"p"},"pwsh")," the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom.exe")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyOrm0.dll")," library must be on the system path to work properly. With ",(0,i.kt)("inlineCode",{parentName:"p"},"bash")," if the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," executable and ",(0,i.kt)("inlineCode",{parentName:"p"},"libTinyOrm.so")," library is ",(0,i.kt)("strong",{parentName:"p"},"not")," on the system path then it will provide less accurate completions."),(0,i.kt)("p",null,"You can enable it using the following commands."),(0,i.kt)(m.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-powershell"},"tom integrate pwsh\n"))),(0,i.kt)(r.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom integrate bash\n"))),(0,i.kt)(r.Z,{value:d.js,label:d.Ae,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom integrate zsh\ntom integrate zsh --path=/usr/share/zsh/site-functions\n")))),(0,i.kt)("p",null,"Or you can enable it manually. Following actions are the same as the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom integrate")," command does."),(0,i.kt)("p",null,"For the ",(0,i.kt)("inlineCode",{parentName:"p"},"pwsh")," paste the following code to the pwsh profile (works on Linux or Windows)."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-powershell",metastring:"title='~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1'",title:"'~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1'"},"Register-ArgumentCompleter -Native -CommandName tom,tom_testdata -ScriptBlock {\n Param($wordToComplete, $commandAst, $cursorPosition)\n [Console]::InputEncoding =\n [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()\n $Local:word = $wordToComplete.Replace('\"', '\\\"')\n $Local:ast = $commandAst.ToString().Replace('\"', '\\\"')\n tom complete --word=\"$Local:word\" --commandline=\"$Local:ast\" --position=$cursorPosition\n | ForEach-Object {\n $completionText, $listText, $toolTip = $_ -split ';', 3\n $listText ??= $completionText\n $toolTip ??= $completionText\n [System.Management.Automation.CompletionResult]::new(\n $completionText, $listText, 'ParameterValue', $toolTip)\n }\n}\n")),(0,i.kt)("p",null,"For ",(0,i.kt)("inlineCode",{parentName:"p"},"bash")," you can copy or create symlink of the ",(0,i.kt)("inlineCode",{parentName:"p"},"/tools/completions/tom.bash")," file to the ",(0,i.kt)("inlineCode",{parentName:"p"},"/usr/share/bash-completion/completions")," folder."),(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`sudo ln -s ${(0,p.go)(d.q5)}/TinyORM/tools/completions/tom.bash /usr/share/bash-completion/completions/tom`),(0,i.kt)("p",null,"And for ",(0,i.kt)("inlineCode",{parentName:"p"},"zsh")," you can copy or create symlink of the ",(0,i.kt)("inlineCode",{parentName:"p"},"/tools/completions/tom.zsh")," file to the ",(0,i.kt)("inlineCode",{parentName:"p"},"_tom")," file to ",(0,i.kt)("inlineCode",{parentName:"p"},"/usr/local/share/zsh/site-functions")," folder."),(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`sudo ln -s ${(0,p.go)(d.q5)}/TinyORM/tools/completions/tom.zsh /usr/local/share/zsh/site-functions/_tom`),(0,i.kt)("p",null,"It will provide completions for the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," commands, long and short parameters, and also for some positional arguments like namespaces for the ",(0,i.kt)("inlineCode",{parentName:"p"},"list")," command or commands for the ",(0,i.kt)("inlineCode",{parentName:"p"},"help")," command."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tom integrate zsh")," command also accepts the ",(0,i.kt)("inlineCode",{parentName:"p"},"--path=")," option with which you can set the location, where the zsh completion file should be created.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can also output the completion script using the ",(0,i.kt)("inlineCode",{parentName:"p"},"--stdout")," option eg. ",(0,i.kt)("inlineCode",{parentName:"p"},"tom integrate bash --stdout"),".")),(0,i.kt)("h3",{id:"alternative-installation-methods"},"Alternative installation methods"),(0,i.kt)("p",null,"This section describes alternative installation methods for ",(0,i.kt)("inlineCode",{parentName:"p"},"bash")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"zsh")," tab completions."),(0,i.kt)("h4",{id:"static-installation"},"Static installation"),(0,i.kt)("p",null,"Idea is to output the tab completion to the file and then source it."),(0,i.kt)(m.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p ~/.local/share/tom\ntom integrate bash --stdout > ~/.local/share/tom/tom.bash\n\n# Then source this file in the ~/.bashrc\nsource $HOME/.local/share/tom/tom.bash\n"))),(0,i.kt)(r.Z,{value:d.js,label:d.Ae,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p ~/.local/share/tom\ntom integrate zsh --stdout > ~/.local/share/tom/tom.zsh\n\n# Then source this file in the ~/.zshrc\nsource $HOME/.local/share/tom/tom.zsh\ncompdef _tom tom\n")))),(0,i.kt)("h4",{id:"dynamic-installation"},"Dynamic installation"),(0,i.kt)("p",null,"Idea is to ",(0,i.kt)("strong",{parentName:"p"},"avoid")," outputting the tab completion to the file, so you ",(0,i.kt)("inlineCode",{parentName:"p"},"eval")," the tab completion source code right away."),(0,i.kt)(m.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'# Add this eval to the ~/.bashrc\neval "$(tom integrate bash --stdout)"\n'))),(0,i.kt)(r.Z,{value:d.js,label:d.Ae,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'# Add this eval to the ~/.zshrc\neval "$(tom integrate zsh --stdout)"\ncompdef _tom tom\n')))),(0,i.kt)("h2",{id:"migration-structure"},"Migration Structure"),(0,i.kt)("p",null,"A migration class contains two methods: ",(0,i.kt)("inlineCode",{parentName:"p"},"up")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"down"),". The ",(0,i.kt)("inlineCode",{parentName:"p"},"up")," method is used to add new tables, columns, or indexes to your database, while the ",(0,i.kt)("inlineCode",{parentName:"p"},"down")," method should reverse the operations performed by the ",(0,i.kt)("inlineCode",{parentName:"p"},"up")," method."),(0,i.kt)("p",null,"Within both of these methods, you may use the TinyORM schema builder to expressively create and modify tables. To learn about all of the methods available on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Schema")," builder, ",(0,i.kt)("a",{parentName:"p",href:"#creating-tables"},"check out its documentation"),". For example, the following migration creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"posts")," table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#pragma once\n\n#include <tom/migration.hpp>\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')),(0,i.kt)("p",null,'Migration classes can be named in two formats, StudlyCase without the datetime prefix and "snake_case" with the datetime prefix. If the StudlyCase name is used then the ',(0,i.kt)("inlineCode",{parentName:"p"},"T_MIGRATION")," macro must also be used in the migration class."),(0,i.kt)("p",null,"Naming with the datetime prefix should look like this."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"struct _2014_10_12_000000_create_posts_table : Migration\n{\n\n /*! Run the migrations. */\n void up() const override\n {\n //\n }\n\n /*! Reverse the migrations. */\n void down() const override\n {\n //\n }\n};\n")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The StudlyCase naming is preferred. Also the ",(0,i.kt)("inlineCode",{parentName:"p"},"make:migration")," command generates migrations in this format.")),(0,i.kt)("h4",{id:"setting-the-migration-connection"},"Setting The Migration Connection"),(0,i.kt)("p",null,"If your migration will be interacting with a database connection other than your application's default database connection, you should set the ",(0,i.kt)("inlineCode",{parentName:"p"},"connection")," data member of your migration:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'/*! The name of the database connection to use. */\nQString connection = QStringLiteral("tinyorm_example");\n\n/*! Run the migrations. */\nvoid up() const override\n{\n //\n}\n')),(0,i.kt)("h2",{id:"running-migrations"},"Running Migrations"),(0,i.kt)("p",null,"To run all of your outstanding migrations, execute the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate")," Tom command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate\n")),(0,i.kt)("p",null,"If you would like to see which migrations have run thus far, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:status")," tom command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:status\n")),(0,i.kt)("p",null,"If you would like to see the SQL statements that will be executed by the migrations without actually running them, you may provide the ",(0,i.kt)("inlineCode",{parentName:"p"},"--pretend")," flag to the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate")," command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate --pretend\n")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Many ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," commands offer variety of options, you can explore them using the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom list")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"tom help")," commands. In most cases, these commands and options are self-explanatory.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," command is able to guess the command name and command namespace, eg. ",(0,i.kt)("inlineCode",{parentName:"p"},"tom mig:st")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"tom m:rol"),", ...")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can pass the ",(0,i.kt)("inlineCode",{parentName:"p"},"-vvv")," command-line argument to any command to see all executed SQL queries. \ud83d\udc4c")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate")," Tom command internally calls the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:install")," command which installs the migration repository table. To uninstall this repository table you can call the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:uninstall"),".")),(0,i.kt)("h4",{id:"forcing-migrations-to-run-in-production"},"Forcing Migrations To Run In Production"),(0,i.kt)("p",null,"Some migration operations are destructive, which means they may cause you to lose data. In order to protect you from running these commands against your production database, you will be prompted for confirmation before the commands are executed. To force the commands to run without a prompt, use the ",(0,i.kt)("inlineCode",{parentName:"p"},"--force")," flag:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate --force\n")),(0,i.kt)("h3",{id:"rolling-back-migrations"},"Rolling Back Migrations"),(0,i.kt)("p",null,"To roll back the latest migration operation, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"rollback"),' Tom command. This command rolls back the last "batch" of migrations, which may include multiple migration files:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:rollback\n")),(0,i.kt)("p",null,"You may roll back a limited number of migrations by providing the ",(0,i.kt)("inlineCode",{parentName:"p"},"step")," option to the ",(0,i.kt)("inlineCode",{parentName:"p"},"rollback")," command. For example, the following command will roll back the last five migrations:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:rollback --step=5\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:reset")," command will roll back all of your application's migrations:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:reset\n")),(0,i.kt)("p",null,'You may roll back a specific "batch" of migrations by providing the ',(0,i.kt)("inlineCode",{parentName:"p"},"batch")," option to the ",(0,i.kt)("inlineCode",{parentName:"p"},"rollback")," command, where the ",(0,i.kt)("inlineCode",{parentName:"p"},"batch")," option corresponds to a batch value within your application's ",(0,i.kt)("inlineCode",{parentName:"p"},"migrations")," database table. For example, the following command will roll back all migrations in batch three:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:rollback --batch=3\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:reset")," command will roll back all of your application's migrations:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:reset\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:uninstall")," command will uninstall the migration repository table, it optionally accepts the ",(0,i.kt)("inlineCode",{parentName:"p"},"--reset")," option to roll back all of your application's migrations:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:uninstall --reset\n")),(0,i.kt)("h4",{id:"roll-back--migrate-using-a-single-command"},"Roll Back & Migrate Using A Single Command"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:refresh")," command will roll back all of your migrations and then execute the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate")," command. This command effectively re-creates your entire database:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:refresh\n")),(0,i.kt)("p",null,"You may roll back and re-migrate a limited number of migrations by providing the ",(0,i.kt)("inlineCode",{parentName:"p"},"step")," option to the ",(0,i.kt)("inlineCode",{parentName:"p"},"refresh")," command. For example, the following command will roll back and re-migrate the last five migrations:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:refresh --step=5\n")),(0,i.kt)("h4",{id:"drop-all-tables--migrate"},"Drop All Tables & Migrate"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:fresh")," command will drop all tables from the database and then execute the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate")," command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:fresh\n")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:fresh")," command will drop all database tables regardless of their prefix. This command should be used with caution when developing on a database that is shared with other applications.")),(0,i.kt)("h2",{id:"tables"},"Tables"),(0,i.kt)("h3",{id:"creating-tables"},"Creating Tables"),(0,i.kt)("p",null,"To create a new database table, use the ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Schema")," facade. The ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method accepts two arguments: the first is the name of the table, while the second is a lambda expression which receives a ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::SchemaNs::Blueprint")," object that may be used to define the new table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nusing Orm::Schema;\n\nSchema::create("users", [](Blueprint &table)\n{\n table.id();\n table.string("name");\n table.string("email");\n table.timestamps();\n});\n')),(0,i.kt)("p",null,"When creating the table, you may use any of the schema builder's ",(0,i.kt)("a",{parentName:"p",href:"#creating-columns"},"column methods")," to define the table's columns."),(0,i.kt)("h4",{id:"checking-for-table--column-existence"},"Checking For Table / Column Existence"),(0,i.kt)("p",null,"You may check for the existence of a table or column using the ",(0,i.kt)("inlineCode",{parentName:"p"},"hasTable")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"hasColumn")," methods:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'if (Schema::hasTable("users")) {\n // The "users" table exists...\n}\n\nif (Schema::hasColumn("users", "email")) {\n // The "users" table exists and has an "email" column...\n}\n')),(0,i.kt)("h4",{id:"database-connection--table-options"},"Database Connection & Table Options"),(0,i.kt)("p",null,"If you want to perform a schema operation on a database connection that is not your application's default connection, use the ",(0,i.kt)("inlineCode",{parentName:"p"},"connection")," method or ",(0,i.kt)("inlineCode",{parentName:"p"},"on")," alias:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::connection("postgres").create("users", [](Blueprint &table)\n{\n table.id();\n});\n')),(0,i.kt)("p",null,"In addition, a few other data members and methods may be used to define other aspects of the table's creation. The ",(0,i.kt)("inlineCode",{parentName:"p"},"engine")," data member may be used to specify the table's storage engine when using MySQL:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/constants.hpp>\n\nusing Orm::Constants::InnoDB;\n\nSchema::create("users", [](Blueprint &table)\n{\n table.engine = InnoDB;\n\n // ...\n});\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"charset")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"collation")," data members may be used to specify the character set and collation for the created table when using MySQL:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/constants.hpp>\n\nusing Orm::Constants::UTF8MB4;\n\nSchema::create("users", [](Blueprint &table)\n{\n table.charset = UTF8MB4;\n table.collation = "utf8mb4_unicode_ci";\n\n // ...\n});\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"temporary"),' method may be used to indicate that the table should be "temporary". Temporary tables are only visible to the current connection\'s database session and are dropped automatically when the connection is closed:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::create("calculations", [](Blueprint &table)\n{\n table.temporary();\n\n // ...\n});\n')),(0,i.kt)("p",null,'If you would like to add a "comment" to a database table, you may invoke the ',(0,i.kt)("inlineCode",{parentName:"p"},"comment")," method on the table instance. Table comments are currently only supported by MySQL and PostgreSQL:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::create("calculations", [](Blueprint &table)\n{\n table.comment("Business calculations");\n\n // ...\n});\n')),(0,i.kt)("h3",{id:"updating-tables"},"Updating Tables"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"table")," method on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Schema")," facade may be used to update existing tables. Like the ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method, the ",(0,i.kt)("inlineCode",{parentName:"p"},"table")," method accepts two arguments: the name of the table and a lambda expression that receives a ",(0,i.kt)("inlineCode",{parentName:"p"},"Blueprint")," instance you may use to add columns or indexes to the table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.integer("votes");\n});\n')),(0,i.kt)("h3",{id:"renaming-and-dropping-tables"},"Renaming / Dropping Tables"),(0,i.kt)("p",null,"To rename an existing database table, use the ",(0,i.kt)("inlineCode",{parentName:"p"},"rename")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nSchema::rename("from", "to");\n')),(0,i.kt)("p",null,"To drop an existing table, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"drop")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"dropIfExists")," methods:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::drop("users");\n\nSchema::dropIfExists("users");\n')),(0,i.kt)("h4",{id:"renaming-tables-with-foreign-keys"},"Renaming Tables With Foreign Keys"),(0,i.kt)("p",null,"Before renaming a table, you should verify that any foreign key constraints on the table have an explicit name in your migration files instead of letting TinyORM assign a convention based name. Otherwise, the foreign key constraint ",(0,i.kt)("strong",{parentName:"p"},"index name")," will refer to the old table name."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"After renaming a table, you can re-create (drop and create again) the foreign key constraints to fix an ",(0,i.kt)("strong",{parentName:"p"},"index name"),", so it refers to a renamed table.")),(0,i.kt)("h2",{id:"columns"},"Columns"),(0,i.kt)("h3",{id:"creating-columns"},"Creating Columns"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"table")," method on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Schema")," facade may be used to update existing tables. Like the ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method, the ",(0,i.kt)("inlineCode",{parentName:"p"},"table")," method accepts two arguments: the name of the table and a lambda expression that receives a ",(0,i.kt)("inlineCode",{parentName:"p"},"Blueprint")," instance you may use to add columns to the table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.integer("votes");\n});\n')),(0,i.kt)("h3",{id:"available-column-types"},"Available Column Types"),(0,i.kt)("p",null,"The schema builder blueprint offers a variety of methods that correspond to the different types of columns you can add to your database tables. Each of the available methods are listed in the table below:"),(0,i.kt)("div",{class:"tom-column-types-list"},(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"#column-method-bigIncrements"},"bigIncrements"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-bigInteger"},"bigInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-binary"},"binary"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-boolean"},"boolean"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-Char"},"Char"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-date"},"date"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-datetime"},"datetime"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-datetimes"},"datetimes"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-datetimeTz"},"datetimeTz"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-decimal"},"decimal"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-Double"},"Double"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-Enum"},"Enum"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-Float"},"Float"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-foreignId"},"foreignId"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-foreignIdFor"},"foreignIdFor"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-foreignUuid"},"foreignUuid"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-geometry"},"geometry"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-geometryCollection"},"geometryCollection"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-id"},"id"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-increments"},"increments"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-integer"},"integer"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-ipAddress"},"ipAddress"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-json"},"json"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-jsonb"},"jsonb"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-lineString"},"lineString"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-longBinary"},"longBinary"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-longText"},"longText"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-macAddress"},"macAddress"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-mediumBinary"},"mediumBinary"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-mediumIncrements"},"mediumIncrements"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-mediumInteger"},"mediumInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-mediumText"},"mediumText"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-multiLineString"},"multiLineString"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-multiPoint"},"multiPoint"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-multiPolygon"},"multiPolygon"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-point"},"point"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-polygon"},"polygon"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-rememberToken"},"rememberToken"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-set"},"set"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-smallIncrements"},"smallIncrements"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-smallInteger"},"smallInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-softDeletes"},"softDeletes"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-softDeletesDatetime"},"softDeletesDatetime"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-softDeletesTz"},"softDeletesTz"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-string"},"string"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-text"},"text"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-time"},"time"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-timeTz"},"timeTz"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-timestamp"},"timestamp"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-timestampTz"},"timestampTz"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-timestampsTz"},"timestampsTz"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-timestamps"},"timestamps"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-tinyBinary"},"tinyBinary"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-tinyIncrements"},"tinyIncrements"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-tinyInteger"},"tinyInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-tinyText"},"tinyText"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-unsignedBigInteger"},"unsignedBigInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-unsignedDecimal"},"unsignedDecimal"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-unsignedInteger"},"unsignedInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-unsignedMediumInteger"},"unsignedMediumInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-unsignedSmallInteger"},"unsignedSmallInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-unsignedTinyInteger"},"unsignedTinyInteger"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-uuid"},"uuid"),"\n",(0,i.kt)("a",{parentName:"p",href:"#column-method-year"},"year"))),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Names of ",(0,i.kt)("inlineCode",{parentName:"p"},"Char"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"Double"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"Enum"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"Float")," column methods are in the CamelCase format to avoid collisions with C++ keywords.")),(0,i.kt)("div",{class:"tom-column-types"},(0,i.kt)("h4",{id:"column-method-bigIncrements"},(0,i.kt)("inlineCode",{parentName:"h4"},"bigIncrements()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"bigIncrements")," method creates an auto-incrementing ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED BIGINT")," (primary key) equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/constants.hpp>\n\ntable.bigIncrements(Orm::ID);\n")),(0,i.kt)("h4",{id:"column-method-bigInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"bigInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"bigInteger")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"BIGINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.bigInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-binary"},(0,i.kt)("inlineCode",{parentName:"h4"},"binary()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"binary")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"BLOB")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.binary("photo");\n')),(0,i.kt)("h4",{id:"column-method-boolean"},(0,i.kt)("inlineCode",{parentName:"h4"},"boolean()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"BOOLEAN")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.boolean("confirmed");\n')),(0,i.kt)("h4",{id:"column-method-Char"},(0,i.kt)("inlineCode",{parentName:"h4"},"Char()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Char")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"CHAR")," equivalent column with of a given length:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/constants.hpp>\n\ntable.Char(Orm::NAME, 100);\n")),(0,i.kt)("h4",{id:"column-method-date"},(0,i.kt)("inlineCode",{parentName:"h4"},"date()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"date")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"DATE")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.date("created_at");\n')),(0,i.kt)("h4",{id:"column-method-datetime"},(0,i.kt)("inlineCode",{parentName:"h4"},"datetime()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"datetime")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"DATETIME")," equivalent column with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.datetime("created_at", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-datetimes"},(0,i.kt)("inlineCode",{parentName:"h4"},"datetimes()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"datetimes")," method creates ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DATETIME")," equivalent columns with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"table.datetimes(precision = 0);\n")),(0,i.kt)("h4",{id:"column-method-datetimeTz"},(0,i.kt)("inlineCode",{parentName:"h4"},"datetimeTz()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"datetimeTz")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"DATETIME")," (with timezone) equivalent column with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/constants.hpp>\n\ntable.datetimeTz(Orm::CREATED_AT, precision = 0);\n")),(0,i.kt)("h4",{id:"column-method-decimal"},(0,i.kt)("inlineCode",{parentName:"h4"},"decimal()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"decimal")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"DECIMAL")," equivalent column with the given precision (total digits) and scale (decimal digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.decimal("amount", precision = 8, scale = 2);\n')),(0,i.kt)("h4",{id:"column-method-Double"},(0,i.kt)("inlineCode",{parentName:"h4"},"Double()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Double")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"DOUBLE")," equivalent column with the given precision (total digits) and scale (decimal digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.Double("amount", 8, 2);\n')),(0,i.kt)("h4",{id:"column-method-Enum"},(0,i.kt)("inlineCode",{parentName:"h4"},"Enum()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Enum")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"ENUM")," equivalent column with the given valid values:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.Enum("difficulty", {"easy", "hard"});\n')),(0,i.kt)("h4",{id:"column-method-Float"},(0,i.kt)("inlineCode",{parentName:"h4"},"Float()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Float")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"FLOAT")," equivalent column with the given precision (total digits) and scale (decimal digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.Float("amount", 8, 2);\n')),(0,i.kt)("h4",{id:"column-method-foreignId"},(0,i.kt)("inlineCode",{parentName:"h4"},"foreignId()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"foreignId")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED BIGINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.foreignId("user_id");\n')),(0,i.kt)("h4",{id:"column-method-foreignIdFor"},(0,i.kt)("inlineCode",{parentName:"h4"},"foreignIdFor()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"foreignIdFor")," method adds a ",(0,i.kt)("inlineCode",{parentName:"p"},"{column}_id UNSIGNED BIGINT")," equivalent column for a given model class:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include "models/user.hpp"\n\nModels::User user;\n\ntable.foreignIdFor(User);\n')),(0,i.kt)("h4",{id:"column-method-foreignUuid"},(0,i.kt)("inlineCode",{parentName:"h4"},"foreignUuid()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"foreignUuid")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"UUID")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.foreignUuid("user_id");\n')),(0,i.kt)("h4",{id:"column-method-geometry"},(0,i.kt)("inlineCode",{parentName:"h4"},"geometry()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"geometry")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"GEOMETRY")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.geometry("positions");\n')),(0,i.kt)("h4",{id:"column-method-geometryCollection"},(0,i.kt)("inlineCode",{parentName:"h4"},"geometryCollection()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"geometryCollection")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"GEOMETRYCOLLECTION")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.geometryCollection("positions");\n')),(0,i.kt)("h4",{id:"column-method-id"},(0,i.kt)("inlineCode",{parentName:"h4"},"id()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"id")," method is an alias of the ",(0,i.kt)("inlineCode",{parentName:"p"},"bigIncrements")," method. By default, the method will create an ",(0,i.kt)("inlineCode",{parentName:"p"},"id")," column; however, you may pass a column name if you would like to assign a different name to the column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"table.id();\n")),(0,i.kt)("h4",{id:"column-method-increments"},(0,i.kt)("inlineCode",{parentName:"h4"},"increments()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"increments")," method creates an auto-incrementing ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED INTEGER")," equivalent column as a primary key:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.increments("id");\n')),(0,i.kt)("h4",{id:"column-method-integer"},(0,i.kt)("inlineCode",{parentName:"h4"},"integer()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"integer")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"INTEGER")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.integer("votes");\n')),(0,i.kt)("h4",{id:"column-method-ipAddress"},(0,i.kt)("inlineCode",{parentName:"h4"},"ipAddress()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ipAddress")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"VARCHAR(45)")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.ipAddress("visitor");\n')),(0,i.kt)("h4",{id:"column-method-json"},(0,i.kt)("inlineCode",{parentName:"h4"},"json()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"json")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"JSON")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.json("options");\n')),(0,i.kt)("h4",{id:"column-method-jsonb"},(0,i.kt)("inlineCode",{parentName:"h4"},"jsonb()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"jsonb")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"JSONB")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.jsonb("options");\n')),(0,i.kt)("h4",{id:"column-method-lineString"},(0,i.kt)("inlineCode",{parentName:"h4"},"lineString()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"lineString")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"LINESTRING")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.lineString("positions");\n')),(0,i.kt)("h4",{id:"column-method-longBinary"},(0,i.kt)("inlineCode",{parentName:"h4"},"longBinary()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"longBinary")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"LONGBLOB")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.longBinary("photo");\n')),(0,i.kt)("h4",{id:"column-method-longText"},(0,i.kt)("inlineCode",{parentName:"h4"},"longText()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"longText")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"LONGTEXT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.longText("description");\n')),(0,i.kt)("h4",{id:"column-method-macAddress"},(0,i.kt)("inlineCode",{parentName:"h4"},"macAddress()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"macAddress")," method creates a column that is intended to hold a MAC address. Some database systems, such as PostgreSQL, have a dedicated column type for this type of data. Other database systems will use a string equivalent ",(0,i.kt)("inlineCode",{parentName:"p"},"VARCHAR(17)")," column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.macAddress("device");\n')),(0,i.kt)("h4",{id:"column-method-mediumBinary"},(0,i.kt)("inlineCode",{parentName:"h4"},"mediumBinary()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"mediumBinary")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"MEDIUMBLOB")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.mediumBinary("photo");\n')),(0,i.kt)("h4",{id:"column-method-mediumIncrements"},(0,i.kt)("inlineCode",{parentName:"h4"},"mediumIncrements()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"mediumIncrements")," method creates an auto-incrementing ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED MEDIUMINT")," equivalent column as a primary key:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.mediumIncrements("id");\n')),(0,i.kt)("h4",{id:"column-method-mediumInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"mediumInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"mediumInteger")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"MEDIUMINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.mediumInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-mediumText"},(0,i.kt)("inlineCode",{parentName:"h4"},"mediumText()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"mediumText")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"MEDIUMTEXT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.mediumText("description");\n')),(0,i.kt)("h4",{id:"column-method-multiLineString"},(0,i.kt)("inlineCode",{parentName:"h4"},"multiLineString()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"multiLineString")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"MULTILINESTRING")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.multiLineString("positions");\n')),(0,i.kt)("h4",{id:"column-method-multiPoint"},(0,i.kt)("inlineCode",{parentName:"h4"},"multiPoint()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"multiPoint")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"MULTIPOINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.multiPoint("positions");\n')),(0,i.kt)("h4",{id:"column-method-multiPolygon"},(0,i.kt)("inlineCode",{parentName:"h4"},"multiPolygon()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"multiPolygon")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"MULTIPOLYGON")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.multiPolygon("positions");\n')),(0,i.kt)("h4",{id:"column-method-point"},(0,i.kt)("inlineCode",{parentName:"h4"},"point()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"point")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"POINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.point("position");\n')),(0,i.kt)("h4",{id:"column-method-polygon"},(0,i.kt)("inlineCode",{parentName:"h4"},"polygon()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"polygon")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"POLYGON")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.polygon("position");\n')),(0,i.kt)("h4",{id:"column-method-rememberToken"},(0,i.kt)("inlineCode",{parentName:"h4"},"rememberToken()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"rememberToken")," method creates a nullable, ",(0,i.kt)("inlineCode",{parentName:"p"},"VARCHAR(100)"),' equivalent column that is intended to store the current "remember me" authentication token:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"table.rememberToken();\n")),(0,i.kt)("h4",{id:"column-method-set"},(0,i.kt)("inlineCode",{parentName:"h4"},"set()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"set")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"SET")," equivalent column with the given list of valid values:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.set("flavors", {"strawberry", "vanilla"});\n')),(0,i.kt)("h4",{id:"column-method-smallIncrements"},(0,i.kt)("inlineCode",{parentName:"h4"},"smallIncrements()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"smallIncrements")," method creates an auto-incrementing ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED SMALLINT")," equivalent column as a primary key:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.smallIncrements("id");\n')),(0,i.kt)("h4",{id:"column-method-smallInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"smallInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"smallInteger")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"SMALLINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.smallInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-softDeletes"},(0,i.kt)("inlineCode",{parentName:"h4"},"softDeletes()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"softDeletes")," method adds a nullable ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," ",(0,i.kt)("inlineCode",{parentName:"p"},"TIMESTAMP")," equivalent column with an optional precision (total digits). This column is intended to store the ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at"),' timestamp needed for TinyORM\'s "soft delete" functionality:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.softDeletes("deleted_at", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-softDeletesDatetime"},(0,i.kt)("inlineCode",{parentName:"h4"},"softDeletesDatetime()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"softDeletesDatetime")," method adds a nullable ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," ",(0,i.kt)("inlineCode",{parentName:"p"},"DATETIME")," equivalent column with an optional precision (total digits). This column is intended to store the ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at"),' timestamp needed for TinyORM\'s "soft delete" functionality:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.softDeletesDatetime("deleted_at", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-softDeletesTz"},(0,i.kt)("inlineCode",{parentName:"h4"},"softDeletesTz()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"softDeletesTz")," method adds a nullable ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," ",(0,i.kt)("inlineCode",{parentName:"p"},"TIMESTAMP")," (with timezone) equivalent column with an optional precision (total digits). This column is intended to store the ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at"),' timestamp needed for TinyORM\'s "soft delete" functionality:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.softDeletesTz("deleted_at", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-string"},(0,i.kt)("inlineCode",{parentName:"h4"},"string()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"string")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"VARCHAR")," equivalent column of the given length:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/constants.hpp>\n\ntable.string(Orm::NAME, 100);\n")),(0,i.kt)("h4",{id:"column-method-text"},(0,i.kt)("inlineCode",{parentName:"h4"},"text()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"text")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TEXT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.text("description");\n')),(0,i.kt)("h4",{id:"column-method-time"},(0,i.kt)("inlineCode",{parentName:"h4"},"time()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"time")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TIME")," equivalent column with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.time("sunrise", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-timeTz"},(0,i.kt)("inlineCode",{parentName:"h4"},"timeTz()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"timeTz")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TIME")," (with timezone) equivalent column with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.timeTz("sunrise", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-timestamp"},(0,i.kt)("inlineCode",{parentName:"h4"},"timestamp()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"timestamp")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TIMESTAMP")," equivalent column with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.timestamp("added_at", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-timestampTz"},(0,i.kt)("inlineCode",{parentName:"h4"},"timestampTz()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"timestampTz")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TIMESTAMP")," (with timezone) equivalent column with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.timestampTz("added_at", precision = 0);\n')),(0,i.kt)("h4",{id:"column-method-timestampsTz"},(0,i.kt)("inlineCode",{parentName:"h4"},"timestampsTz()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"timestampsTz")," method creates ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," ",(0,i.kt)("inlineCode",{parentName:"p"},"TIMESTAMP")," (with timezone) equivalent columns with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"table.timestampsTz(precision = 0);\n")),(0,i.kt)("h4",{id:"column-method-timestamps"},(0,i.kt)("inlineCode",{parentName:"h4"},"timestamps()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"timestamps")," method creates ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," ",(0,i.kt)("inlineCode",{parentName:"p"},"TIMESTAMP")," equivalent columns with an optional precision (total digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"table.timestamps(precision = 0);\n")),(0,i.kt)("h4",{id:"column-method-tinyBinary"},(0,i.kt)("inlineCode",{parentName:"h4"},"tinyBinary()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tinyBinary")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TINYBLOB")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.tinyBinary("photo");\n')),(0,i.kt)("h4",{id:"column-method-tinyIncrements"},(0,i.kt)("inlineCode",{parentName:"h4"},"tinyIncrements()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tinyIncrements")," method creates an auto-incrementing ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED TINYINT")," equivalent column as a primary key:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.tinyIncrements("id");\n')),(0,i.kt)("h4",{id:"column-method-tinyInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"tinyInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tinyInteger")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TINYINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.tinyInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-tinyText"},(0,i.kt)("inlineCode",{parentName:"h4"},"tinyText()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tinyText")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"TINYTEXT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.tinyText("notes");\n')),(0,i.kt)("h4",{id:"column-method-unsignedBigInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"unsignedBigInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"unsignedBigInteger")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED BIGINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unsignedBigInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-unsignedDecimal"},(0,i.kt)("inlineCode",{parentName:"h4"},"unsignedDecimal()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"unsignedDecimal")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED DECIMAL")," equivalent column with an optional precision (total digits) and scale (decimal digits):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unsignedDecimal("amount", precision = 8, scale = 2);\n')),(0,i.kt)("h4",{id:"column-method-unsignedInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"unsignedInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"unsignedInteger")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED INTEGER")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unsignedInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-unsignedMediumInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"unsignedMediumInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"unsignedMediumInteger")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED MEDIUMINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unsignedMediumInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-unsignedSmallInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"unsignedSmallInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"unsignedSmallInteger")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED SMALLINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unsignedSmallInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-unsignedTinyInteger"},(0,i.kt)("inlineCode",{parentName:"h4"},"unsignedTinyInteger()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"unsignedTinyInteger")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED TINYINT")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unsignedTinyInteger("votes");\n')),(0,i.kt)("h4",{id:"column-method-uuid"},(0,i.kt)("inlineCode",{parentName:"h4"},"uuid()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"uuid")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"UUID")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.uuid("id");\n')),(0,i.kt)("h4",{id:"column-method-year"},(0,i.kt)("inlineCode",{parentName:"h4"},"year()")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"year")," method creates a ",(0,i.kt)("inlineCode",{parentName:"p"},"YEAR")," equivalent column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.year("birth_year");\n'))),(0,i.kt)("h3",{id:"column-modifiers"},"Column Modifiers"),(0,i.kt)("p",null,'In addition to the column types listed above, there are several column "modifiers" you may use when adding a column to a database table. For example, to make the column "nullable", you may use the ',(0,i.kt)("inlineCode",{parentName:"p"},"nullable")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.string("email").nullable();\n});\n')),(0,i.kt)("p",null,"The following table contains all of the available column modifiers. This list does not include ",(0,i.kt)("a",{parentName:"p",href:"#creating-indexes"},"index modifiers"),":"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Modifier"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'.after("column")')),(0,i.kt)("td",{parentName:"tr",align:null},'Place the column "after" another column ',(0,i.kt)("small",null,"(MySQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".autoIncrement()")),(0,i.kt)("td",{parentName:"tr",align:null},"Set INTEGER columns as auto-incrementing (primary key).")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'.charset("utf8mb4")')),(0,i.kt)("td",{parentName:"tr",align:null},"Specify a character set for the column ",(0,i.kt)("small",null,"(MySQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("small",null,(0,i.kt)("inlineCode",{parentName:"td"},'.collation("utf8mb4_unicode_ci")'))),(0,i.kt)("td",{parentName:"tr",align:null},"Specify a collation for the column ",(0,i.kt)("small",null,"(MySQL/PostgreSQL/SQL Server)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'.comment("my comment")')),(0,i.kt)("td",{parentName:"tr",align:null},"Add a comment to a column ",(0,i.kt)("small",null,"(MySQL / PostgreSQL)"),".",(0,i.kt)("br",null),(0,i.kt)("small",null,"Special characters are escaped."))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".defaultValue(value)")),(0,i.kt)("td",{parentName:"tr",align:null},'Specify a "default" value for the column.',(0,i.kt)("br",null),(0,i.kt)("small",null,"Special characters are escaped."))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".first()")),(0,i.kt)("td",{parentName:"tr",align:null},'Place the column "first" in the table ',(0,i.kt)("small",null,"(MySQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".from(integer)")),(0,i.kt)("td",{parentName:"tr",align:null},"Set the starting value of an auto-incrementing field, an alias for ",(0,i.kt)("inlineCode",{parentName:"td"},"startingValue()")," ",(0,i.kt)("small",null,"(MySQL / PostgreSQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".invisible()")),(0,i.kt)("td",{parentName:"tr",align:null},'Make the column "invisible" to ',(0,i.kt)("inlineCode",{parentName:"td"},"SELECT *")," queries ",(0,i.kt)("small",null,"(MySQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".nullable(value = true)")),(0,i.kt)("td",{parentName:"tr",align:null},"Allow NULL values to be inserted into the column.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".startingValue(integer)")),(0,i.kt)("td",{parentName:"tr",align:null},"Set the starting value of an auto-incrementing field ",(0,i.kt)("small",null,"(MySQL / PostgreSQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".storedAs(expression)")),(0,i.kt)("td",{parentName:"tr",align:null},"Create a stored generated column ",(0,i.kt)("small",null,"(MySQL / PostgreSQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".unsigned()")),(0,i.kt)("td",{parentName:"tr",align:null},"Set INTEGER columns as UNSIGNED ",(0,i.kt)("small",null,"(MySQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".useCurrent()")),(0,i.kt)("td",{parentName:"tr",align:null},"Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".useCurrentOnUpdate()")),(0,i.kt)("td",{parentName:"tr",align:null},"Set TIMESTAMP columns to use CURRENT_TIMESTAMP when a record is updated.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".virtualAs(expression)")),(0,i.kt)("td",{parentName:"tr",align:null},"Create a virtual generated column ",(0,i.kt)("small",null,"(MySQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".generatedAs(expression)")),(0,i.kt)("td",{parentName:"tr",align:null},"Create an identity column with specified sequence options ",(0,i.kt)("small",null,"(PostgreSQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".always()")),(0,i.kt)("td",{parentName:"tr",align:null},"Defines the precedence of sequence values over input for an identity column ",(0,i.kt)("small",null,"(PostgreSQL)"),".")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".isGeometry()")),(0,i.kt)("td",{parentName:"tr",align:null},"Set spatial column type to ",(0,i.kt)("inlineCode",{parentName:"td"},"geometry")," - the default type is ",(0,i.kt)("inlineCode",{parentName:"td"},"geography")," ",(0,i.kt)("small",null,"(PostgreSQL)"),".")))),(0,i.kt)("h4",{id:"default-expressions"},"Default Expressions"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"defaultValue")," modifier accepts a value or an ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Query::Expression")," instance. Using an ",(0,i.kt)("inlineCode",{parentName:"p"},"Expression")," instance will prevent TinyORM from wrapping the value in quotes and allow you to use database-specific functions. One situation where this is particularly useful is when you need to assign default values to JSON columns:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nusing Orm::Query::Expression;\n\nSchema::create("flights", [](Blueprint &table)\n{\n table.id();\n table.json("detail").defaultValue(Expression("(JSON_ARRAY(\'none\'))"));\n table.timestamps();\n});\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Support for default expressions depends on your database driver, database version, and the field type. Please refer to your database's documentation.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can obtain an ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Query::Expression")," using the ",(0,i.kt)("a",{parentName:"p",href:"/database/query-builder#raw-expressions"},(0,i.kt)("inlineCode",{parentName:"a"},"DB::raw"))," method if you have access to the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade.")),(0,i.kt)("h4",{id:"column-order"},"Column Order"),(0,i.kt)("p",null,"When using the MySQL database, the ",(0,i.kt)("inlineCode",{parentName:"p"},"after")," method may be used to add columns after an existing column in the schema:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.after("password", [](Blueprint &table)\n{\n table.string("address_line1");\n table.string("address_line2");\n table.string("city");\n});\n')),(0,i.kt)("h3",{id:"modifying-columns"},"Modifying Columns"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"change")," method allows you to modify the type and attributes of existing columns. For example, you may wish to increase the size of a ",(0,i.kt)("inlineCode",{parentName:"p"},"string")," column. To see the ",(0,i.kt)("inlineCode",{parentName:"p"},"change")," method in action, let's increase the size of the ",(0,i.kt)("inlineCode",{parentName:"p"},"name")," column from 25 to 50. To accomplish this, we simply define the new state of the column and then call the ",(0,i.kt)("inlineCode",{parentName:"p"},"change")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.string("name", 50).change();\n});\n')),(0,i.kt)("p",null,"When modifying a column, you must explicitly include all of the modifiers you want to keep on the column definition - any missing attribute will be dropped. For example, to retain the ",(0,i.kt)("inlineCode",{parentName:"p"},"unsigned"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"default"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"comment")," attributes, you must call each modifier explicitly when changing the column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("users", [](Blueprint &table)\n{\n table.integer("votes").isUnsigned().defaultValue(1).comment("my comment").change();\n});\n')),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"change")," method and modifying columns is not implemented for the ",(0,i.kt)("inlineCode",{parentName:"p"},"SQLite")," database because it doesn't support modifying columns out of the box.")),(0,i.kt)("h4",{id:"renaming-columns"},"Renaming Columns"),(0,i.kt)("p",null,"To rename a column, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"renameColumn")," method provided by the schema builder blueprint:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("users", [](Blueprint &table)\n{\n table.renameColumn("from", "to");\n});\n')),(0,i.kt)("h4",{id:"renaming-columns-on-legacy-databases"},"Renaming Columns On Legacy Databases"),(0,i.kt)("p",null,"Renaming columns is not supported if you are running a database installation older than one of the following releases:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"MySQL ",(0,i.kt)("inlineCode",{parentName:"li"},"<8.0.3")),(0,i.kt)("li",{parentName:"ul"},"MariaDB ",(0,i.kt)("inlineCode",{parentName:"li"},"<10.5.2")),(0,i.kt)("li",{parentName:"ul"},"SQLite ",(0,i.kt)("inlineCode",{parentName:"li"},"<3.25.0"))),(0,i.kt)("h3",{id:"dropping-columns"},"Dropping Columns"),(0,i.kt)("p",null,"To drop a column, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"dropColumn")," method on the schema builder blueprint:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("users", [](Blueprint &table)\n{\n table.dropColumn("votes");\n});\n')),(0,i.kt)("p",null,"You may drop multiple columns from a table by passing a ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<QString>")," of column names to the ",(0,i.kt)("inlineCode",{parentName:"p"},"dropColumns")," method, the ",(0,i.kt)("inlineCode",{parentName:"p"},"dropColumns")," method also provides parameter pack overload:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("users", [](Blueprint &table)\n{\n table.dropColumns({"votes", "avatar", "location"});\n // Parameter pack overload\n table.dropColumns("votes", "avatar", "location");\n});\n')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The SQLite prior to ",(0,i.kt)("inlineCode",{parentName:"p"},"v3.35.0")," doesn't support dropping columns using the ",(0,i.kt)("inlineCode",{parentName:"p"},"ALTER TABLE DROP COLUMN"),", dropping columns was added in the SQLite ",(0,i.kt)("inlineCode",{parentName:"p"},"v3.35.0")," as is described in the ",(0,i.kt)("a",{parentName:"p",href:"https://www.sqlite.org/releaselog/3_35_0.html"},"release notes"),".")),(0,i.kt)("h4",{id:"available-command-aliases"},"Available Command Aliases"),(0,i.kt)("p",null,"TinyORM provides several convenient methods related to dropping common types of columns. Each of these methods is described in the table below:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Command"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.dropRememberToken();")),(0,i.kt)("td",{parentName:"tr",align:null},"Drop the ",(0,i.kt)("inlineCode",{parentName:"td"},"remember_token")," column.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.dropSoftDeletes();")),(0,i.kt)("td",{parentName:"tr",align:null},"Drop the ",(0,i.kt)("inlineCode",{parentName:"td"},"deleted_at")," column.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.dropSoftDeletesDatetime();")),(0,i.kt)("td",{parentName:"tr",align:null},"Alias of ",(0,i.kt)("inlineCode",{parentName:"td"},"dropSoftDeletes()")," method.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.dropSoftDeletesTz();")),(0,i.kt)("td",{parentName:"tr",align:null},"Alias of ",(0,i.kt)("inlineCode",{parentName:"td"},"dropSoftDeletes()")," method.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.dropTimestamps();")),(0,i.kt)("td",{parentName:"tr",align:null},"Drop the ",(0,i.kt)("inlineCode",{parentName:"td"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"td"},"updated_at")," columns.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.dropTimestampsTz();")),(0,i.kt)("td",{parentName:"tr",align:null},"Alias of ",(0,i.kt)("inlineCode",{parentName:"td"},"dropTimestamps()")," method.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.dropDatetimes();")),(0,i.kt)("td",{parentName:"tr",align:null},"Alias of ",(0,i.kt)("inlineCode",{parentName:"td"},"dropTimestamps()")," method.")))),(0,i.kt)("h2",{id:"indexes"},"Indexes"),(0,i.kt)("h3",{id:"creating-indexes"},"Creating Indexes"),(0,i.kt)("p",null,"The TinyORM schema builder supports several types of indexes. The following example creates a new ",(0,i.kt)("inlineCode",{parentName:"p"},"email")," column and specifies that its values should be unique. To create the index, we can chain the ",(0,i.kt)("inlineCode",{parentName:"p"},"unique")," method onto the column definition:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nSchema::table("users", [](Blueprint &table)\n{\n table.string("email").unique();\n});\n')),(0,i.kt)("p",null,"Alternatively, you may create the index after defining the column. To do so, you should call the ",(0,i.kt)("inlineCode",{parentName:"p"},"unique")," method on the schema builder blueprint. This method accepts the name of the column that should receive a unique index:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unique("email");\n')),(0,i.kt)("p",null,"You may even pass a ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<QString>")," of columns to an index method to create a compound (or composite) index:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.index({"account_id", "created_at"});\n')),(0,i.kt)("p",null,"When creating an index, TinyORM will automatically generate an index name based on the table, column names, and the index type (eg. users_email_unique), but you may pass a second argument to the method to specify the index name yourself:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.unique("email", "unique_email");\n')),(0,i.kt)("h4",{id:"available-index-types"},"Available Index Types"),(0,i.kt)("p",null,"TinyORM's schema builder blueprint class provides methods for creating each type of index supported by TinyORM. Each index method accepts an optional second argument to specify the name of the index. If omitted, the name will be derived from the names of the table and column(s) used for the index, as well as the index type (eg. users_email_fulltext). Each of the available index methods is described in the table below:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Command"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.primary("id");')),(0,i.kt)("td",{parentName:"tr",align:null},"Adds a primary key.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.primary({"id", "parent_id"});')),(0,i.kt)("td",{parentName:"tr",align:null},"Adds composite keys.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.unique("email");')),(0,i.kt)("td",{parentName:"tr",align:null},"Adds a unique index.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.index("state");')),(0,i.kt)("td",{parentName:"tr",align:null},"Adds an index.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.fullText("body");')),(0,i.kt)("td",{parentName:"tr",align:null},"Adds a full text index (MySQL/PostgreSQL).")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("small",null,(0,i.kt)("inlineCode",{parentName:"td"},'table.fullText("body").language("english");'))),(0,i.kt)("td",{parentName:"tr",align:null},"Adds a full text index of the specified language (PostgreSQL).")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.spatialIndex("location");')),(0,i.kt)("td",{parentName:"tr",align:null},"Adds a spatial index (except SQLite).")))),(0,i.kt)("h4",{id:"index-lengths--mysql--mariadb"},"Index Lengths & MySQL / MariaDB"),(0,i.kt)("p",null,"By default, TinyORM uses the ",(0,i.kt)("inlineCode",{parentName:"p"},"utf8mb4")," character set. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure the default string length by calling the ",(0,i.kt)("inlineCode",{parentName:"p"},"Schema::defaultStringLength")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/schema.hpp>\n\nSchema::defaultStringLength(191);\n")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Alternatively, you may enable the ",(0,i.kt)("inlineCode",{parentName:"p"},"innodb_large_prefix")," option for your database (enabled by default in >=MySQL 5.7.7). Refer to your database's documentation for instructions on how to properly enable this option.")),(0,i.kt)("h3",{id:"renaming-indexes"},"Renaming Indexes"),(0,i.kt)("p",null,"To rename an index, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"renameIndex")," method provided by the schema builder blueprint. This method accepts the current index name as its first argument and the desired name as its second argument:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.renameIndex("from", "to");\n')),(0,i.kt)("h3",{id:"dropping-indexes"},"Dropping Indexes"),(0,i.kt)("p",null,"To drop an index, you must specify the index's name. By default, TinyORM automatically assigns an index name based on the table name, the name of the indexed column, and the index type (eg. users_email_unique). Here are some examples:"),(0,i.kt)("div",{id:"apitable-dropping-indexes"},(0,i.kt)(l.Z,{mdxType:"APITable"},(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Command"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.dropPrimary("users_id_primary");')),(0,i.kt)("td",{parentName:"tr",align:null},'Drop a primary key from the "users" table.')),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.dropUnique("users_email_unique");')),(0,i.kt)("td",{parentName:"tr",align:null},'Drop a unique index from the "users" table.')),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'table.dropIndex("geo_state_index");')),(0,i.kt)("td",{parentName:"tr",align:null},'Drop a basic index from the "geo" table.')),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("small",null,(0,i.kt)("inlineCode",{parentName:"td"},'table.dropFullText("posts_body_fulltext");'))),(0,i.kt)("td",{parentName:"tr",align:null},'Drop a full text index from the "posts" table.')),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("small",null,(0,i.kt)("inlineCode",{parentName:"td"},'.dropSpatialIndex("geo_location_spatialindex");'))),(0,i.kt)("td",{parentName:"tr",align:null},'Drop a spatial index from the "geo" table (except SQLite).')))))),(0,i.kt)("p",null,"I may also drop indexes by a column name or column names for composite keys, if you pass a ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<QString>")," of columns into a method that drops indexes, the conventional index name will be generated based on the table name, columns, and index type:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("geo", [](Blueprint &table)\n{\n table.dropIndex({"state"}); // Drops index \'geo_state_index\'\n});\n')),(0,i.kt)("h3",{id:"foreign-key-constraints"},"Foreign Key Constraints"),(0,i.kt)("p",null,"TinyORM also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a ",(0,i.kt)("inlineCode",{parentName:"p"},"user_id")," column on the ",(0,i.kt)("inlineCode",{parentName:"p"},"posts")," table that references the ",(0,i.kt)("inlineCode",{parentName:"p"},"id")," column on a ",(0,i.kt)("inlineCode",{parentName:"p"},"users")," table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/schema.hpp>\n\nusing Orm::Constants::ID;\n\nSchema::table("posts", [](Blueprint &table)\n{\n table.unsignedBigInteger("user_id");\n\n table.foreign("user_id").references(ID).on("users");\n});\n')),(0,i.kt)("p",null,"Since this syntax is rather verbose, TinyORM provides additional, terser methods that use conventions to provide a better developer experience. When using the ",(0,i.kt)("inlineCode",{parentName:"p"},"foreignId")," method to create your column, the example above can be rewritten like so:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("posts", [](Blueprint &table)\n{\n table.foreignId("user_id").constrained();\n});\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"foreignId")," method creates an ",(0,i.kt)("inlineCode",{parentName:"p"},"UNSIGNED BIGINT")," equivalent column, while the ",(0,i.kt)("inlineCode",{parentName:"p"},"constrained")," method will use conventions to determine the table and column name being referenced. If your table name does not match TinyORM's conventions, you may specify the table name by passing it as an argument to the ",(0,i.kt)("inlineCode",{parentName:"p"},"constrained")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("posts", [](Blueprint &table)\n{\n table.foreignId("user_id").constrained("users");\n});\n')),(0,i.kt)("p",null,'You may also specify the desired action for the "on delete" and "on update" properties of the constraint:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/constants.hpp>\n\nusing Orm::SchemaNs::Constants::Cascade;\n\ntable.foreignId("user_id")\n .constrained()\n .onUpdate("cascade")\n .onDelete(Cascade);\n')),(0,i.kt)("p",null,"An alternative, expressive syntax is also provided for these actions:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Method"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.cascadeOnUpdate();")),(0,i.kt)("td",{parentName:"tr",align:null},"Updates should cascade.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.restrictOnUpdate();")),(0,i.kt)("td",{parentName:"tr",align:null},"Updates should be restricted.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.cascadeOnDelete();")),(0,i.kt)("td",{parentName:"tr",align:null},"Deletes should cascade.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.restrictOnDelete();")),(0,i.kt)("td",{parentName:"tr",align:null},"Deletes should be restricted.")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"table.nullOnDelete();")),(0,i.kt)("td",{parentName:"tr",align:null},"Deletes should set the foreign key value to null.")))),(0,i.kt)("p",null,"Any additional ",(0,i.kt)("a",{parentName:"p",href:"#column-modifiers"},"column modifiers")," must be called before the ",(0,i.kt)("inlineCode",{parentName:"p"},"constrained")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.foreignId("user_id")\n .nullable()\n .constrained();\n')),(0,i.kt)("h4",{id:"dropping-foreign-keys"},"Dropping Foreign Keys"),(0,i.kt)("p",null,"To drop a foreign key, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"dropForeign"),' method, passing the name of the foreign key constraint to be deleted as an argument. Foreign key constraints use the same naming convention as indexes. In other words, the foreign key constraint name is based on the name of the table and the columns in the constraint, followed by a "_foreign" suffix:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.dropForeign("posts_user_id_foreign");\n')),(0,i.kt)("p",null,"Alternatively, you may pass a ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<QString>")," containing the column name that holds the foreign key to the ",(0,i.kt)("inlineCode",{parentName:"p"},"dropForeign")," method. The ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector")," will be converted to a foreign key constraint name using TinyORM's constraint naming conventions:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'table.dropForeign({"user_id"});\n')),(0,i.kt)("h4",{id:"toggling-foreign-key-constraints"},"Toggling Foreign Key Constraints"),(0,i.kt)("p",null,"You may enable or disable foreign key constraints within your migrations by using the following methods:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"Schema::enableForeignKeyConstraints();\n\nSchema::disableForeignKeyConstraints();\n\nSchema::withoutForeignKeyConstraints([]\n{\n // Constraints disabled within this lambda expression...\n});\n")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The SQLite disables foreign key constraints by default. When using SQLite, make sure to ",(0,i.kt)("a",{parentName:"p",href:"/database/getting-started#sqlite-configuration"},"enable foreign key support")," in your database configuration before attempting to create them in your migrations. In addition, SQLite only supports creating foreign keys when creating tables and ",(0,i.kt)("a",{parentName:"p",href:"https://www.sqlite.org/omitted.html"},"not when tables are altered"),".")))}b.isMDXComponent=!0},9566:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/tom_cli-402f7dd4dfe7dbd0b20dfe5fb61838a2.png"}}]); \ No newline at end of file diff --git a/assets/js/237.d109f2ba.js b/assets/js/237.d109f2ba.js new file mode 100644 index 000000000..28eec7750 --- /dev/null +++ b/assets/js/237.d109f2ba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[237],{3363:(e,t,n)=>{n.d(t,{A:()=>a});n(6540);var i=n(4164),o=n(1312),r=n(1107),s=n(4848);function a(e){let{className:t}=e;return(0,s.jsx)("main",{className:(0,i.A)("container margin-vert--xl",t),children:(0,s.jsx)("div",{className:"row",children:(0,s.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,s.jsx)(r.A,{as:"h1",className:"hero__title",children:(0,s.jsx)(o.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}},2237:(e,t,n)=>{n.r(t),n.d(t,{default:()=>l});n(6540);var i=n(1312),o=n(9024),r=n(9201),s=n(3363),a=n(4848);function l(){const e=(0,i.T)({id:"theme.NotFound.title",message:"Page Not Found"});return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(o.be,{title:e}),(0,a.jsx)(r.A,{children:(0,a.jsx)(s.A,{})})]})}}}]); \ No newline at end of file diff --git a/assets/js/3dd307b5.7b464df0.js b/assets/js/3dd307b5.7b464df0.js deleted file mode 100644 index 1cc1a9262..000000000 --- a/assets/js/3dd307b5.7b464df0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[108],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>c});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function i(e,t){if(null==e)return{};var n,o,a=function(e,t){if(null==e)return{};var n,o,a={},r=Object.keys(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o<r.length;o++)n=r[o],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=o.createContext({}),d=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=d(e.components);return o.createElement(s.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=d(n),h=a,c=m["".concat(s,".").concat(h)]||m[h]||u[h]||r;return n?o.createElement(c,l(l({ref:t},p),{},{components:n})):o.createElement(c,l({ref:t},p))}));function c(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,l=new Array(r);l[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[m]="string"==typeof e?e:a,l[1]=i;for(var d=2;d<r;d++)l[d]=n[d];return o.createElement.apply(null,l)}return o.createElement.apply(null,n)}h.displayName="MDXCreateElement"},8503:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>d});var o=n(7462),a=(n(7294),n(3905));const r={sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},l="TinyORM: Collections",i={unversionedId:"tinyorm/collections",id:"tinyorm/collections",title:"TinyORM: Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",source:"@site/docs/tinyorm/collections.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/collections",permalink:"/tinyorm/collections",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/tinyorm/collections.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Relationships",permalink:"/tinyorm/relationships"},next:{title:"Casts",permalink:"/tinyorm/casts"}},s={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Collection Conversion",id:"collection-conversion",level:4},{value:"Creating Collections",id:"creating-collections",level:3},{value:"Available Methods",id:"available-methods",level:2},{value:"<code>all()</code>",id:"method-all",level:4},{value:"<code>contains()</code>",id:"method-contains",level:4},{value:"<code>doesntContain()</code>",id:"method-doesntcontain",level:4},{value:"<code>each()</code>",id:"method-each",level:4},{value:"<code>except()</code>",id:"method-except",level:4},{value:"<code>filter()</code>",id:"method-filter",level:4},{value:"<code>find()</code>",id:"method-find",level:4},{value:"<code>first()</code>",id:"method-first",level:4},{value:"<code>firstWhere()</code>",id:"method-first-where",level:4},{value:"<code>fresh()</code>",id:"method-fresh",level:4},{value:"<code>implode()</code>",id:"method-implode",level:4},{value:"<code>isEmpty()</code>",id:"method-isempty",level:4},{value:"<code>isNotEmpty()</code>",id:"method-isnotempty",level:4},{value:"<code>last()</code>",id:"method-last",level:4},{value:"<code>load()</code>",id:"method-load",level:4},{value:"<code>map()</code>",id:"method-map",level:4},{value:"<code>mapWithKeys()</code>",id:"method-mapwithkeys",level:4},{value:"<code>mapWithModelKeys()</code>",id:"method-mapwithmodelkeys",level:4},{value:"<code>modelKeys()</code>",id:"method-modelkeys",level:4},{value:"<code>only()</code>",id:"method-only",level:4},{value:"<code>pluck()</code>",id:"method-pluck",level:4},{value:"<code>reject()</code>",id:"method-reject",level:4},{value:"<code>sort()</code>",id:"method-sort",level:4},{value:"<code>sortBy()</code>",id:"method-sortby",level:4},{value:"<code>sortByDesc()</code>",id:"method-sortbydesc",level:4},{value:"<code>sortDesc()</code>",id:"method-sortdesc",level:4},{value:"<code>stableSort()</code>",id:"method-stablesort",level:4},{value:"<code>stableSortBy()</code>",id:"method-stablesortby",level:4},{value:"<code>stableSortByDesc()</code>",id:"method-stablesortbydesc",level:4},{value:"<code>stableSortDesc()</code>",id:"method-stablesortdesc",level:4},{value:"<code>tap()</code>",id:"method-tap",level:4},{value:"<code>toBase()</code>",id:"method-tobase",level:4},{value:"<code>toJson()</code>",id:"method-tojson",level:4},{value:"<code>toJsonArray()</code>",id:"method-tojsonarray",level:4},{value:"<code>toJsonDocument()</code>",id:"method-tojsondocument",level:4},{value:"<code>toMap()</code>",id:"method-tomap",level:4},{value:"<code>toMapVariantList()</code>",id:"method-tomapvariantlist",level:4},{value:"<code>toQuery()</code>",id:"method-toquery",level:4},{value:"<code>toVector()</code>",id:"method-tovector",level:4},{value:"<code>toVectorVariantList()</code>",id:"method-tovectorvariantlist",level:4},{value:"<code>unique()</code>",id:"method-unique",level:4},{value:"<code>uniqueBy()</code>",id:"method-uniqueby",level:4},{value:"<code>uniqueRelaxed()</code>",id:"method-uniquerelaxed",level:4},{value:"<code>uniqueRelaxedBy()</code>",id:"method-uniquerelaxedby",level:4},{value:"<code>value()</code>",id:"method-value",level:4},{value:"<code>where()</code>",id:"method-where",level:4},{value:"<code>whereBetween()</code>",id:"method-wherebetween",level:4},{value:"<code>whereIn()</code>",id:"method-wherein",level:4},{value:"<code>whereNotBetween()</code>",id:"method-wherenotbetween",level:4},{value:"<code>whereNotIn()</code>",id:"method-wherenotin",level:4},{value:"<code>whereNotNull()</code>",id:"method-wherenotnull",level:4},{value:"<code>whereNull()</code>",id:"method-wherenull",level:4}],p={toc:d},m="wrapper";function u(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"tinyorm-collections"},"TinyORM: Collections"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#introduction"},"Introduction"),(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#creating-collections"},"Creating Collections")))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#available-methods"},"Available Methods"))),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Types::ModelsCollection")," is specialized container which provides a fluent, convenient wrapper for working with vector of models. All TinyORM methods that return more than one model result, will return instances of the ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," class, including results retrieved via the ",(0,a.kt)("inlineCode",{parentName:"p"},"get")," method or methods that return relationships like the ",(0,a.kt)("inlineCode",{parentName:"p"},"getRelation")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"getRelationValue"),"."),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," class extends ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<Model>"),", so it naturally inherits dozens of methods used to work with the underlying vector of TinyORM models. Be sure to review the ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qlist.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QList"))," documentation to learn all about these helpful methods!"),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," template parameter can be declared only with the model type or a model type pointer, it also can't be ",(0,a.kt)("inlineCode",{parentName:"p"},"const")," and can't be a reference. It's constrained using the ",(0,a.kt)("inlineCode",{parentName:"p"},"DerivedCollectionModel")," concept.")),(0,a.kt)("p",null,"You can iterate over the ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," the same way as over the ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using Models::User;\n\nModelsCollection<User> users = User::whereEq("active", true)->get();\n\nfor (const auto &user : users)\n qDebug() << user.getAttribute<QString>("name");\n')),(0,a.kt)("p",null,"However, as previously mentioned, collections are much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, we may remove all active users and then gather the first name of each remaining user:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto names = User::all().reject([](User *const user)\n{\n return user->getAttribute<bool>("active");\n})\n .pluck("name");\n')),(0,a.kt)("p",null,"As you can see, the ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," class allows you to chain its methods to perform fluent mapping and reducing of the underlying vector. In general, collections are immutable, meaning every ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," method returns an entirely new ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," instance."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection<Model>")," is returning from the Models' methods like ",(0,a.kt)("inlineCode",{parentName:"p"},"get"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"all"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"findMany"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"chunk"),"; the ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection<Model *>")," is returning from the relationship-related methods as ",(0,a.kt)("inlineCode",{parentName:"p"},"getRelation")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"getRelationValue"),".")),(0,a.kt)("h4",{id:"collection-conversion"},"Collection Conversion"),(0,a.kt)("p",null,"While most TinyORM collection methods return a new instance of ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection"),", the ",(0,a.kt)("inlineCode",{parentName:"p"},"modelKeys"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"mapWithKeys"),", and ",(0,a.kt)("inlineCode",{parentName:"p"},"pluck")," methods return a base QVector or std unordered/map instances. Likewise, one of the ",(0,a.kt)("inlineCode",{parentName:"p"},"map")," methods overload returns the ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<T>"),"."),(0,a.kt)("h3",{id:"creating-collections"},"Creating Collections"),(0,a.kt)("p",null,"Creating a ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," is as simple as:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n')),(0,a.kt)("p",null,"You can also create a collection of pointers, eg. ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection<User *>"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ModelsCollection<User *> userPointers {\n &users[0], &users[1],\n};\n")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection<Model>")," is implicitly convertible and assignable from the ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<Model>"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'QVector<User> usersVector {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n\nModelsCollection<User> users(usersVector);\nusers = usersVector;\n')),(0,a.kt)("p",null,"Alternatively, you can use the ",(0,a.kt)("inlineCode",{parentName:"p"},"Orm::collect<Model>")," helper function to create a ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," from the given attributes:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users = Orm::collect<User>({\n {{"name", "Kate"}, {"added_on", QDateTime::currentDateTimeUtc()}},\n {{"name", "John"}, {"added_on", QDateTime({2023, 6, 1}, {13, 46, 15}, Qt::UTC)}},\n});\n')),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"Orm::collect<Model>")," function is ",(0,a.kt)("strong",{parentName:"p"},"mandatory")," if your attributes contain the ",(0,a.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance, you can read more about this problem ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/getting-started#qdatetime-and-connection-name-problem"},"here"),".")),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"The results of ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/getting-started"},"TinyORM")," queries are always returned as ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," instances.")),(0,a.kt)("h2",{id:"available-methods"},"Available Methods"),(0,a.kt)("p",null,"For the majority of the remaining collection documentation, we'll discuss each method available on the ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," class. Remember, all of these methods may be chained to fluently manipulate the underlying vector."),(0,a.kt)("p",null,"Furthermore, almost every method returns a new ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," instance, allowing you to preserve the original copy of the collection when necessary:"),(0,a.kt)("div",{class:"collection-methods-list"},(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"#method-all"},"all"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-contains"},"contains"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-doesntcontain"},"doesntContain"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-each"},"each"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-except"},"except"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-filter"},"filter"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-find"},"find"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-first"},"first"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-first-where"},"firstWhere"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-fresh"},"fresh"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-implode"},"implode"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-isempty"},"isEmpty"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-isnotempty"},"isNotEmpty"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-last"},"last"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-load"},"load"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-map"},"map"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-mapwithkeys"},"mapWithKeys"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-mapwithmodelkeys"},"mapWithModelKeys"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-modelkeys"},"modelKeys"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-only"},"only"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-pluck"},"pluck"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-reject"},"reject"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-sort"},"sort"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-sortby"},"sortBy"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-sortbydesc"},"sortByDesc"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-sortdesc"},"sortDesc"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-stablesort"},"stableSort"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-stablesortby"},"stableSortBy"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-stablesortbydesc"},"stableSortByDesc"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-stablesortdesc"},"stableSortDesc"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tap"},"tap"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tobase"},"toBase"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tojson"},"toJson"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tojsonarray"},"toJsonArray"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tojsondocument"},"toJsonDocument"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tomap"},"toMap"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tomapvariantlist"},"toMapVariantList"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-toquery"},"toQuery"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tovector"},"toVector"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-tovectorvariantlist"},"toVectorVariantList"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-unique"},"unique"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-uniqueby"},"uniqueBy"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-uniquerelaxed"},"uniqueRelaxed"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-uniquerelaxedby"},"uniqueRelaxedBy"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-value"},"value"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-where"},"where"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-wherebetween"},"whereBetween"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-wherein"},"whereIn"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-wherenotbetween"},"whereNotBetween"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-wherenotin"},"whereNotIn"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-wherenotnull"},"whereNotNull"),"\n",(0,a.kt)("a",{parentName:"p",href:"#method-wherenull"},"whereNull"))),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"For a better understanding of the following examples, many of the variable declarations below use actual types instead of the ",(0,a.kt)("inlineCode",{parentName:"p"},"auto")," keyword.")),(0,a.kt)("div",{class:"collection-methods"},(0,a.kt)("h4",{id:"method-all"},(0,a.kt)("inlineCode",{parentName:"h4"},"all()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"all")," method returns a copy of the underlying vector represented by the collection:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"QVector<User> = users.all();\n")),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("a",{parentName:"p",href:"#method-tobase"},(0,a.kt)("inlineCode",{parentName:"a"},"toBase"))," is an alias to the ",(0,a.kt)("inlineCode",{parentName:"p"},"all")," method.")),(0,a.kt)("h4",{id:"method-contains"},(0,a.kt)("inlineCode",{parentName:"h4"},"contains()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"contains")," method may be used to determine if a given model instance is contained by the collection. This method accepts a primary key or a model instance:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"users.contains(1);\n\nusers.contains(User::find(1));\n")),(0,a.kt)("p",null,"Alternatively, you may pass a lambda expression to the ",(0,a.kt)("inlineCode",{parentName:"p"},"contains")," method to determine if a model exists in the collection matching a given truth test:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"users.contains([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n")),(0,a.kt)("p",null,"For the inverse of ",(0,a.kt)("inlineCode",{parentName:"p"},"contains"),", see the ",(0,a.kt)("a",{parentName:"p",href:"#method-doesntcontain"},"doesntContain")," method."),(0,a.kt)("h4",{id:"method-doesntcontain"},(0,a.kt)("inlineCode",{parentName:"h4"},"doesntContain()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"doesntContain")," method determines whether the collection does not contain a given item. This method accepts a primary key or a model instance:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"users.doesntContain(1);\n\nusers.doesntContain(User::find(1));\n")),(0,a.kt)("p",null,"Alternatively, you may pass a lambda expression to the ",(0,a.kt)("inlineCode",{parentName:"p"},"doesntContain")," method to determine if a model does not exist in the collection matching a given truth test:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"users.doesntContain([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n")),(0,a.kt)("p",null,"For the inverse of ",(0,a.kt)("inlineCode",{parentName:"p"},"doesntContain"),", see the ",(0,a.kt)("a",{parentName:"p",href:"#method-contains"},"contains")," method."),(0,a.kt)("h4",{id:"method-each"},(0,a.kt)("inlineCode",{parentName:"h4"},"each()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"each")," method iterates over the models in the collection and passes each model to the lambda expression:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users = Post::whereEq("user_id", 1)->get();\n\nusers.each([](User *const user)\n{\n // ...\n});\n')),(0,a.kt)("p",null,"If you would like to stop iterating through the models, you may return ",(0,a.kt)("inlineCode",{parentName:"p"},"false")," from your lambda expression:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"users.each([](User *const user)\n{\n if (/* condition */)\n return false;\n\n // Some logic\n\n return true;\n});\n")),(0,a.kt)("p",null,"You may also pass the lambda expression with two parameters, whereas the second one is an index:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"users.each([](User *const user, const std::size_t index)\n{\n // ...\n});\n")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"each")," method returns an lvalue ",(0,a.kt)("strong",{parentName:"p"},"reference")," to the currently processed collection."),(0,a.kt)("p",null,"It can be also called on ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," rvalues, it returns an rvalue reference in this case."),(0,a.kt)("h4",{id:"method-except"},(0,a.kt)("inlineCode",{parentName:"h4"},"except()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"except")," method returns all of the models that do not have the given primary keys:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ModelsCollection<User *> usersResult = users.except({1, 2, 3});\n")),(0,a.kt)("p",null,"All of the models are returned if the ",(0,a.kt)("inlineCode",{parentName:"p"},"ids")," argument is empty ",(0,a.kt)("inlineCode",{parentName:"p"},"except({})"),"."),(0,a.kt)("p",null,"The order of models in the collection is preserved."),(0,a.kt)("p",null,"For the inverse of ",(0,a.kt)("inlineCode",{parentName:"p"},"except"),", see the ",(0,a.kt)("a",{parentName:"p",href:"#method-only"},"only")," method."),(0,a.kt)("h4",{id:"method-filter"},(0,a.kt)("inlineCode",{parentName:"h4"},"filter()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"filter")," method filters the collection using the lambda expression, keeping only those models that pass a given truth test:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto usersBanned = users.filter([](const User *const user)\n{\n return user->getAttribute<bool>("is_banned");\n});\n')),(0,a.kt)("p",null,"You may also pass the lambda expression with two parameters, whereas the second one is an index:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto usersBanned = users.filter([](const User *const user,\n const std::size_t index)\n{\n return index < 10 && user->getAttribute<bool>("is_banned");\n});\n')),(0,a.kt)("p",null,"If no lambda expression is supplied, all models of the collection that are equivalent to the ",(0,a.kt)("inlineCode",{parentName:"p"},"nullptr")," will be removed:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ModelsCollection<User> usersRaw = User::findMany({1, 2});\nModelsCollection<User *> users {&usersRaw[0], nullptr, &usersRaw[1]};\n\nModelsCollection<User *> filtered = users.filter();\n\n// {1, 2}\n")),(0,a.kt)("p",null,"For the inverse of ",(0,a.kt)("inlineCode",{parentName:"p"},"filter"),", see the ",(0,a.kt)("a",{parentName:"p",href:"#method-reject"},"reject")," method."),(0,a.kt)("h4",{id:"method-find"},(0,a.kt)("inlineCode",{parentName:"h4"},"find()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"find")," method returns the model that has a primary key matching the given key:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"User *const user = users.find(1);\n")),(0,a.kt)("p",null,"If you pass a model instance, ",(0,a.kt)("inlineCode",{parentName:"p"},"find")," will attempt to return a model matching the primary key:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"User *user = users.find(anotherUser);\n")),(0,a.kt)("p",null,"The two overloads above also accept the second ",(0,a.kt)("inlineCode",{parentName:"p"},"defaultModel")," model argument, which will be returned if a model was not found in the collection, its default value is the ",(0,a.kt)("inlineCode",{parentName:"p"},"nullptr"),"."),(0,a.kt)("p",null,"Alternatively, may pass more IDs and ",(0,a.kt)("inlineCode",{parentName:"p"},"find")," will return all models which have a primary key within the given unordered set:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ModelsCollection<User *> usersMany = users.find({1, 2});\n")),(0,a.kt)("p",null,"This overload internally calls the ",(0,a.kt)("a",{parentName:"p",href:"#method-only"},(0,a.kt)("inlineCode",{parentName:"a"},"only"))," method."),(0,a.kt)("h4",{id:"method-first"},(0,a.kt)("inlineCode",{parentName:"h4"},"first()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"first")," method returns the first model in the collection that passes a given truth test:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute<quint64>("votes") > 150;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n')),(0,a.kt)("p",null,"If no model passes a given truth test then the value of the second ",(0,a.kt)("inlineCode",{parentName:"p"},"defaultModel")," argument will be returned, its default value is the ",(0,a.kt)("inlineCode",{parentName:"p"},"nullptr"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute<quint64>("votes") > 500;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n')),(0,a.kt)("p",null,"You can also call all ",(0,a.kt)("inlineCode",{parentName:"p"},"first")," overloads provided by the ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qlist.html#first"},(0,a.kt)("inlineCode",{parentName:"a"},"QList::first")),"."),(0,a.kt)("h4",{id:"method-first-where"},(0,a.kt)("inlineCode",{parentName:"h4"},"firstWhere()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"firstWhere")," method returns the first model in the collection with the given column / value pair:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection<User> users {\n {{"name", "Leon"}, {"age", NullVariant::UShort()}},\n {{"name", "Jill"}, {"age", 14}},\n {{"name", "Jack"}, {"age", 23}},\n {{"name", "Jill"}, {"age", 84}},\n};\n\nauto user = users.firstWhereEq("name", "Linda");\n\n// {{"name", "Jill"}, {"age", 14}}\n')),(0,a.kt)("p",null,"You may also call the ",(0,a.kt)("inlineCode",{parentName:"p"},"firstWhere")," method with a comparison operator:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'users.firstWhere("age", ">=", 18);\n\n// {{"name", "Jack"}, {"age", 23}}\n')),(0,a.kt)("h4",{id:"method-fresh"},(0,a.kt)("inlineCode",{parentName:"h4"},"fresh()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"fresh")," method retrieves a fresh instance of each model in the collection from the database. In addition, any specified relationships will be eager loaded:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto usersFresh = users.fresh();\n\nauto usersFresh = users.fresh("comments");\n\nauto usersFresh = users.fresh("posts:id,name");\n\nauto usersFresh = users.fresh({"comments", "posts:id,name"});\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"relations")," argument format is the same as for TinyBuilder's ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/relationships#lazy-eager-loading"},(0,a.kt)("inlineCode",{parentName:"a"},"load"))," method."),(0,a.kt)("h4",{id:"method-implode"},(0,a.kt)("inlineCode",{parentName:"h4"},"implode()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"implode"),' method joins attributes by the given column and the "glue" string you wish to place between the values:'),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n};\n\nproducts.implode("product", ", ");\n\n// {Desk, Chair}\n')),(0,a.kt)("p",null,'The default "glue" value is an empty string "".'),(0,a.kt)("h4",{id:"method-isempty"},(0,a.kt)("inlineCode",{parentName:"h4"},"isEmpty()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"isEmpty")," method returns ",(0,a.kt)("inlineCode",{parentName:"p"},"true")," if the collection is empty; otherwise, ",(0,a.kt)("inlineCode",{parentName:"p"},"false")," is returned:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ModelsCollection<User>().isEmpty();\n\n// true\n")),(0,a.kt)("h4",{id:"method-isnotempty"},(0,a.kt)("inlineCode",{parentName:"h4"},"isNotEmpty()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"isNotEmpty")," method returns ",(0,a.kt)("inlineCode",{parentName:"p"},"true")," if the collection is not empty; otherwise, ",(0,a.kt)("inlineCode",{parentName:"p"},"false")," is returned:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ModelsCollection<User>().isNotEmpty();\n\n// false\n")),(0,a.kt)("h4",{id:"method-last"},(0,a.kt)("inlineCode",{parentName:"h4"},"last()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"last")," method returns the last model in the collection that passes a given truth test:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "Rose"}, {"votes", 350}},\n};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute<quint64>("votes") < 300;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n')),(0,a.kt)("p",null,"If no model passes a given truth test then the value of the second ",(0,a.kt)("inlineCode",{parentName:"p"},"defaultModel")," argument will be returned, its default value is the ",(0,a.kt)("inlineCode",{parentName:"p"},"nullptr"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute<quint64>("votes") < 100;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n')),(0,a.kt)("p",null,"You can also call all ",(0,a.kt)("inlineCode",{parentName:"p"},"last")," overloads provided by the ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qlist.html#last"},(0,a.kt)("inlineCode",{parentName:"a"},"QList::last")),"."),(0,a.kt)("h4",{id:"method-load"},(0,a.kt)("inlineCode",{parentName:"h4"},"load()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"load")," method eager loads the given relationships for all models in the collection:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'users.load({"comments", "posts"});\n\nusers.load("comments.author");\n\nusers.load({{"comments"}, {"posts", [](auto &query)\n{\n query.whereEq("active", true);\n}}});\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"relations")," argument format is the same as for TinyBuilder's ",(0,a.kt)("a",{parentName:"p",href:"/tinyorm/relationships#lazy-eager-loading"},(0,a.kt)("inlineCode",{parentName:"a"},"load"))," method."),(0,a.kt)("h4",{id:"method-map"},(0,a.kt)("inlineCode",{parentName:"h4"},"map()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"map")," method iterates through the collection and passes a ",(0,a.kt)("strong",{parentName:"p"},"copy")," of each model to the given lambda expression. The lambda expression is free to modify the model and return it, thus forming a new collection of modified models:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto usersAdded = users.map([](User &&userCopy)\n{\n if (userCopy.getAttribute<QString>("name") == "John")\n userCopy["votes"] = userCopy.getAttribute<quint64>("votes") + 1;\n\n return std::move(userCopy);\n});\n\n/*\n {\n {{"name", "John"}, {"price", 201}},\n {{"name", "Jack"}, {"price", 400}},\n }\n*/\n')),(0,a.kt)("p",null,"The second ",(0,a.kt)("inlineCode",{parentName:"p"},"map")," overload allows to return the ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<T>"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'QVector<quint64> usersAdded = users.map<quint64>([](User &&userCopy)\n{\n const auto votesRef = userCopy["votes"];\n\n if (userCopy.getAttribute<QString>("name") == "John")\n votesRef = userCopy.getAttribute<quint64>("votes") + 1;\n\n return votesRef->value<quint64>();\n});\n\n// {201, 400}\n')),(0,a.kt)("p",null,"Both overloads allow to pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,a.kt)("inlineCode",{parentName:"p"},"std::size_t")," type."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"Like most other collection methods, ",(0,a.kt)("inlineCode",{parentName:"p"},"map")," returns a new collection instance; it does not modify the collection it is called on. If you want to modify the original collection in place, use the ",(0,a.kt)("a",{parentName:"p",href:"#method-each"},(0,a.kt)("inlineCode",{parentName:"a"},"each"))," method.")),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The model copy is passed to the lambda expression even if the ",(0,a.kt)("inlineCode",{parentName:"p"},"map")," iterates over a collection of model pointers ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection<Model *>"),". The models are dereferenced behind the scene.")),(0,a.kt)("h4",{id:"method-mapwithkeys"},(0,a.kt)("inlineCode",{parentName:"h4"},"mapWithKeys()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"mapWithKeys")," method iterates through the collection and passes each model to the given lambda expression. It returns the ",(0,a.kt)("inlineCode",{parentName:"p"},"std::unordered_map<K, V>")," and the lambda expression should return the ",(0,a.kt)("inlineCode",{parentName:"p"},"std::pair<K, V>")," containing a single column / value pair:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"id", 1}, {"name", "John"}, {"email", "john@example.com"}},\n {{"id", 2}, {"name", "Jill"}, {"email", "jill@example.com"}},\n};\n\nauto usersMap = users.mapWithKeys<quint64, QString>(\n [](User *const user) -> std::pair<quint64, QString>\n{\n return {user->getKeyCasted(), user->getAttribute<QString>("name")};\n});\n\n// {{1, \'John\'}, {2, \'Jill\'}}\n')),(0,a.kt)("p",null,"You can also map IDs to the model pointers:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"auto usersMap = users.mapWithKeys<quint64, User *>(\n [](User *const user) -> std::pair<quint64, User *>\n{\n return {user->getKeyCasted(), user};\n});\n")),(0,a.kt)("h4",{id:"method-mapwithmodelkeys"},(0,a.kt)("inlineCode",{parentName:"h4"},"mapWithModelKeys()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"mapWithModelKeys")," maps the primary keys to the ",(0,a.kt)("inlineCode",{parentName:"p"},"Model *"),", it returns the ",(0,a.kt)("inlineCode",{parentName:"p"},"std::unordered_map<Model::KeyType, Model *>"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"auto usersMap = users.mapWithModelKeys();\n")),(0,a.kt)("h4",{id:"method-modelkeys"},(0,a.kt)("inlineCode",{parentName:"h4"},"modelKeys()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"modelKeys")," method returns the primary keys for all models in the collection:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"id", 1}, {"name", "John"}},\n {{"id", 2}, {"name", "Jill"}},\n {{"id", 3}, {"name", "Kate"}},\n {{"id", 5}, {"name", "Rose"}},\n};\n\nusers.modelKeys(); // Returns QVector<QVariant>\nusers.modelKeys<quint64>();\n\n// {1, 2, 3, 5}\n')),(0,a.kt)("h4",{id:"method-only"},(0,a.kt)("inlineCode",{parentName:"h4"},"only()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"only")," method returns all of the models that have the given primary keys:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ModelsCollection<User *> usersResult = users.only({1, 2, 3});\n")),(0,a.kt)("p",null,"An empty collection is returned if the ",(0,a.kt)("inlineCode",{parentName:"p"},"ids")," argument is empty ",(0,a.kt)("inlineCode",{parentName:"p"},"only({})"),"."),(0,a.kt)("p",null,"The order of models in the collection is preserved."),(0,a.kt)("p",null,"For the inverse of ",(0,a.kt)("inlineCode",{parentName:"p"},"only"),", see the ",(0,a.kt)("a",{parentName:"p",href:"#method-except"},"except")," method."),(0,a.kt)("h4",{id:"method-pluck"},(0,a.kt)("inlineCode",{parentName:"h4"},"pluck()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"pluck")," method retrieves all of the values for a given column, the following overload returns the ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<QVariant>"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"id", 1}, {"name", "Desk"}},\n {{"id", 2}, {"name", "Chair"}},\n};\n\nauto plucked = products.pluck("name");\n\n// {Desk, Chair}\n')),(0,a.kt)("p",null,"The second overload allows returning the custom type ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<T>"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto plucked = products.pluck<QString>("name");\n')),(0,a.kt)("p",null,"You may also specify how you wish the resulting collection to be keyed, this overload returns the ",(0,a.kt)("inlineCode",{parentName:"p"},"std::map<T, QVariant>"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto plucked = products.pluck<quint64>("name", "id");\n\n// {{1, "Desk"}, {2, "Chair"}}\n')),(0,a.kt)("p",null,"If duplicate keys exist, the last matching attribute will be inserted into the plucked collection:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> collection {\n {{"brand", "Tesla"}, {"color", "red"}},\n {{"brand", "Pagani"}, {"color", "white"}},\n {{"brand", "Tesla"}, {"color", "black"}},\n {{"brand", "Pagani"}, {"color", "orange"}},\n};\n\nauto plucked = collection.pluck<QString>("color", "brand");\n\n// {{\'Tesla\', \'black\'}, {\'Pagani\', \'orange"}}\n')),(0,a.kt)("h4",{id:"method-reject"},(0,a.kt)("inlineCode",{parentName:"h4"},"reject()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"reject")," method filters the collection using the given lambda expression. The lambda should return ",(0,a.kt)("inlineCode",{parentName:"p"},"true")," if the model should be removed from the resulting collection:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto usersWithNote = users.reject([](const User *const user)\n{\n return user->getAttribute("note").isNull();\n});\n')),(0,a.kt)("p",null,"You may also pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,a.kt)("inlineCode",{parentName:"p"},"std::size_t")," type."),(0,a.kt)("p",null,"For the inverse of the ",(0,a.kt)("inlineCode",{parentName:"p"},"reject")," method, see the ",(0,a.kt)("a",{parentName:"p",href:"#method-filter"},(0,a.kt)("inlineCode",{parentName:"a"},"filter"))," method."),(0,a.kt)("h4",{id:"method-sort"},(0,a.kt)("inlineCode",{parentName:"h4"},"sort()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"sort")," method sorts the models collection by primary keys:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sort();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n')),(0,a.kt)("p",null,"You may pass a predicate and projection callbacks to the ",(0,a.kt)("inlineCode",{parentName:"p"},"sort")," method with your own algorithms. Refer to the CPP reference documentation on ",(0,a.kt)("a",{parentName:"p",href:"https://en.cppreference.com/w/cpp/algorithm/ranges/sort"},(0,a.kt)("inlineCode",{parentName:"a"},"ranges::sort")),", which is what the ",(0,a.kt)("inlineCode",{parentName:"p"},"sort")," method calls internally."),(0,a.kt)("p",null,"You can eg. sort by multiple columns, for an alternative method of multi-column sorting look at ",(0,a.kt)("a",{parentName:"p",href:"#method-sortby"},"sortBy"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sort([](const User *const left,\n const User *const right)\n{\n const auto leftValue = left->getAttribute<QString>("name");\n const auto rightValue = right->getAttribute<QString>("name");\n\n if (leftValue == rightValue)\n return left->getAttribute<quint64>("votes") <\n right->getAttribute<quint64>("votes");\n\n return leftValue < rightValue;\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 350}},\n }\n*/\n')),(0,a.kt)("p",null,"The order of equal elements is not guaranteed to be preserved."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"You can use the ",(0,a.kt)("a",{parentName:"p",href:"#method-stablesort"},"stable")," sort method variants to preserve the order of equal models.")),(0,a.kt)("h4",{id:"method-sortby"},(0,a.kt)("inlineCode",{parentName:"h4"},"sortBy()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"sortBy")," method sorts the collection by the given column, this overload needs the template argument so it can cast the attribute value before comparing:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto sorted = users.sortBy<QString>("name");\n\n/*\n {\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 150}},\n }\n*/\n')),(0,a.kt)("p",null,"You may pass the projection callback to determine how to sort the collection's models:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto sorted = users.sortBy([](User *const user)\n{\n return user->getAttribute<quint64>("votes");\n});\n\n/*\n {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n }\n*/\n')),(0,a.kt)("p",null,"If you would like to sort your collection by multiple columns, you may pass a vector of comparison lambda expressions that define each sort operation to the ",(0,a.kt)("inlineCode",{parentName:"p"},"sortBy")," method, in the following example is the ",(0,a.kt)("inlineCode",{parentName:"p"},"name")," column sorted in ascending order and the second ",(0,a.kt)("inlineCode",{parentName:"p"},"votes")," column is sorted in descending order:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using AttributeUtils = Orm::Tiny::Utils::Attribute;\n\nModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sortBy({\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortBy(\n left->getAttribute<QString>("name"),\n right->getAttribute<QString>("name"));\n },\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortByDesc(\n left->getAttribute<quint64>("votes"),\n right->getAttribute<quint64>("votes"));\n },\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "Kate"}, {"votes", 200}},\n }\n*/\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"AttributeUtils::compareForSortBy")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"compareForSortByDesc")," methods are helper methods, they are needed because the Qt framework doesn't define ",(0,a.kt)("inlineCode",{parentName:"p"},"<=>")," spaceship operator on its types, it doesn't support the three-way comparison."),(0,a.kt)("p",null,"The order of equal elements is not guaranteed to be preserved."),(0,a.kt)("h4",{id:"method-sortbydesc"},(0,a.kt)("inlineCode",{parentName:"h4"},"sortByDesc()")),(0,a.kt)("p",null,"This method has the same signature as the ",(0,a.kt)("a",{parentName:"p",href:"#method-sortby"},(0,a.kt)("inlineCode",{parentName:"a"},"sortBy"))," method but will sort the collection in the opposite order."),(0,a.kt)("p",null,"The order of equal elements is not guaranteed to be preserved."),(0,a.kt)("h4",{id:"method-sortdesc"},(0,a.kt)("inlineCode",{parentName:"h4"},"sortDesc()")),(0,a.kt)("p",null,"This method will sort the collection in the opposite order as the ",(0,a.kt)("a",{parentName:"p",href:"#method-sort"},(0,a.kt)("inlineCode",{parentName:"a"},"sort"))," method:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sortDesc();\n\n/*\n {\n {{"id", 3}, {"name", "John"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n }\n*/\n')),(0,a.kt)("p",null,"The order of equal elements is not guaranteed to be preserved."),(0,a.kt)("h4",{id:"method-stablesort"},(0,a.kt)("inlineCode",{parentName:"h4"},"stableSort()")),(0,a.kt)("p",null,"This method has the same signature as the ",(0,a.kt)("a",{parentName:"p",href:"#method-sort"},(0,a.kt)("inlineCode",{parentName:"a"},"sort"))," method but will preserve the order of equal elements (guaranteed to be preserved)."),(0,a.kt)("h4",{id:"method-stablesortby"},(0,a.kt)("inlineCode",{parentName:"h4"},"stableSortBy()")),(0,a.kt)("p",null,"This method has the same signature as the ",(0,a.kt)("a",{parentName:"p",href:"#method-sortby"},(0,a.kt)("inlineCode",{parentName:"a"},"sortBy"))," method but will preserve the order of equal elements (guaranteed to be preserved)."),(0,a.kt)("h4",{id:"method-stablesortbydesc"},(0,a.kt)("inlineCode",{parentName:"h4"},"stableSortByDesc()")),(0,a.kt)("p",null,"This method has the same signature as the ",(0,a.kt)("a",{parentName:"p",href:"#method-sortbydesc"},(0,a.kt)("inlineCode",{parentName:"a"},"sortByDesc"))," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."),(0,a.kt)("h4",{id:"method-stablesortdesc"},(0,a.kt)("inlineCode",{parentName:"h4"},"stableSortDesc()")),(0,a.kt)("p",null,"This method has the same signature as the ",(0,a.kt)("a",{parentName:"p",href:"#method-sortdesc"},(0,a.kt)("inlineCode",{parentName:"a"},"sortDesc"))," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."),(0,a.kt)("h4",{id:"method-tap"},(0,a.kt)("inlineCode",{parentName:"h4"},"tap()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"tap"),' method passes a collection to the given lambda expression, allowing you to "tap" into the collection at a specific point and do something with the models while not affecting the collection itself:'),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nusers.sort()\n .tap([](/*const */ModelsCollection<User *> &usersRef)\n{\n qDebug() << "IDs after sorting:"\n << usersRef.template modelKeys<quint64>();\n})\n .value<quint64>("id");\n\n// 1\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"tap")," method returns an lvalue ",(0,a.kt)("strong",{parentName:"p"},"reference")," to the currently processed collection."),(0,a.kt)("p",null,"It can be also called on ",(0,a.kt)("inlineCode",{parentName:"p"},"ModelsCollection")," rvalues, it returns an rvalue reference in this case."),(0,a.kt)("h4",{id:"method-tobase"},(0,a.kt)("inlineCode",{parentName:"h4"},"toBase()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toBase")," method returns a copy of the underlying vector represented by the collection:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"QVector<User> = users.toBase();\n")),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("a",{parentName:"p",href:"#method-tobase"},(0,a.kt)("inlineCode",{parentName:"a"},"toBase"))," is an alias to the ",(0,a.kt)("inlineCode",{parentName:"p"},"all")," method.")),(0,a.kt)("h4",{id:"method-tojson"},(0,a.kt)("inlineCode",{parentName:"h4"},"toJson()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toJson")," method converts the collection of models with all nested relations into a JSON serialized ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qbytearray.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QByteArray")),"."),(0,a.kt)("p",null,"It returns an empty array for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"many")," type relations and ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"one")," type relations."),(0,a.kt)("admonition",{type:"info"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toJson")," method accepts the ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsondocument.html#JsonFormat-enum"},(0,a.kt)("inlineCode",{parentName:"a"},"QJsonDocument::JsonFormat")),", possible values are ",(0,a.kt)("inlineCode",{parentName:"p"},"QJsonDocument::Indented")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"QJsonDocument::Compact"),".")),(0,a.kt)("h4",{id:"method-tojsonarray"},(0,a.kt)("inlineCode",{parentName:"h4"},"toJsonArray()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toJsonArray")," method converts the collection of models with all nested relations into a ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsonarray.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QJsonArray")),"."),(0,a.kt)("h4",{id:"method-tojsondocument"},(0,a.kt)("inlineCode",{parentName:"h4"},"toJsonDocument()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toJsonDocument")," method converts the collection of models with all nested relations into a ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qjsondocument.html"},(0,a.kt)("inlineCode",{parentName:"a"},"QJsonDocument")),"."),(0,a.kt)("h4",{id:"method-tomap"},(0,a.kt)("inlineCode",{parentName:"h4"},"toMap()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toMap")," method converts the collection of models with all nested relations into an attributes map ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<QVariantMap>"),"."),(0,a.kt)("p",null,"It returns an empty ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariantList")," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"many")," type relations and a null ",(0,a.kt)("abbr",{title:"QVariant::fromValue(nullptr)"},(0,a.kt)("inlineCode",{parentName:"p"},"QVariant"))," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"one")," type relations."),(0,a.kt)("h4",{id:"method-tomapvariantlist"},(0,a.kt)("inlineCode",{parentName:"h4"},"toMapVariantList()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toMapVariantList")," method converts the collection of models with all nested relations into an attributes map, but it returns the ",(0,a.kt)("abbr",{title:"QList<QVariant>"},(0,a.kt)("inlineCode",{parentName:"p"},"QVariantList"))," instead of the ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<QVariantMap>"),"."),(0,a.kt)("p",null,"It returns an empty ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariantList")," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"many")," type relations and a null ",(0,a.kt)("abbr",{title:"QVariant::fromValue(nullptr)"},(0,a.kt)("inlineCode",{parentName:"p"},"QVariant"))," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"one")," type relations."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toMapVariantList")," method is internally needed by the ",(0,a.kt)("inlineCode",{parentName:"p"},"toJson")," related methods.")),(0,a.kt)("h4",{id:"method-toquery"},(0,a.kt)("inlineCode",{parentName:"h4"},"toQuery()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toQuery")," method returns the ",(0,a.kt)("inlineCode",{parentName:"p"},"TinyBuilder")," instance containing a ",(0,a.kt)("inlineCode",{parentName:"p"},"whereIn")," constraint with the collection of models' primary keys:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'using Models::User;\n\nModelsCollection<User> users = User::whereEq("status", "VIP")->get();\n\nusers.toQuery()->update({\n {"status", "Administrator"},\n});\n')),(0,a.kt)("h4",{id:"method-tovector"},(0,a.kt)("inlineCode",{parentName:"h4"},"toVector()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toVector")," method converts the collection of models with all nested relations into an attributes vector ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<QVector<AttributeItem>>"),"."),(0,a.kt)("p",null,"It returns an empty ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariantList")," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"many")," type relations and a null ",(0,a.kt)("abbr",{title:"QVariant::fromValue(nullptr)"},(0,a.kt)("inlineCode",{parentName:"p"},"QVariant"))," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"one")," type relations."),(0,a.kt)("h4",{id:"method-tovectorvariantlist"},(0,a.kt)("inlineCode",{parentName:"h4"},"toVectorVariantList()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toVectorVariantList")," method converts the collection of models with all nested relations into an attributes vector, but it returns the ",(0,a.kt)("abbr",{title:"QList<QVariant>"},(0,a.kt)("inlineCode",{parentName:"p"},"QVariantList"))," instead of the ",(0,a.kt)("inlineCode",{parentName:"p"},"QVector<QVector<AttributeItem>>"),"."),(0,a.kt)("p",null,"It returns an empty ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariantList")," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"many")," type relations and a null ",(0,a.kt)("abbr",{title:"QVariant::fromValue(nullptr)"},(0,a.kt)("inlineCode",{parentName:"p"},"QVariant"))," for empty ",(0,a.kt)("inlineCode",{parentName:"p"},"one")," type relations."),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"toVectorVariantList")," method is internally needed by the ",(0,a.kt)("inlineCode",{parentName:"p"},"toJson")," related methods.")),(0,a.kt)("h4",{id:"method-unique"},(0,a.kt)("inlineCode",{parentName:"h4"},"unique()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"unique")," method returns all of the unique models in the ",(0,a.kt)("strong",{parentName:"p"},"sorted")," collection. Any models with the same primary key as another model in the collection are removed:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.unique();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n')),(0,a.kt)("p",null,"It sorts the collection internally because the ",(0,a.kt)("a",{parentName:"p",href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique"},(0,a.kt)("inlineCode",{parentName:"a"},"ranges::unique"))," can correctly operate only on the sorted container. You can disable it by passing ",(0,a.kt)("inlineCode",{parentName:"p"},"false")," using the first ",(0,a.kt)("inlineCode",{parentName:"p"},"sort")," parameter:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto unique = users.sort().unique(false);\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n')),(0,a.kt)("h4",{id:"method-uniqueby"},(0,a.kt)("inlineCode",{parentName:"h4"},"uniqueBy()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"uniqueBy")," method returns all of the unique models in the ",(0,a.kt)("strong",{parentName:"p"},"sorted")," collection by the given column. Any models with the same column value as another model in the collection are removed. It needs the template argument, so it can cast the attribute value before comparing:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueBy<QString>("name");\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n')),(0,a.kt)("p",null,"It sorts the collection internally because the ",(0,a.kt)("a",{parentName:"p",href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique"},(0,a.kt)("inlineCode",{parentName:"a"},"ranges::unique"))," can correctly operate only on the sorted container. You can disable it by passing ",(0,a.kt)("inlineCode",{parentName:"p"},"false")," using the second ",(0,a.kt)("inlineCode",{parentName:"p"},"sort")," parameter:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto unique = users.sortBy<QString>("name")\n .uniqueBy<QString>("name", false);\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n')),(0,a.kt)("h4",{id:"method-uniquerelaxed"},(0,a.kt)("inlineCode",{parentName:"h4"},"uniqueRelaxed()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"uniqueRelaxed")," method returns all of the unique models in the collection, it doesn't need a sorted collection. Any models with the same primary key as another model in the collection are removed:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxed();\n\n/*\n {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n')),(0,a.kt)("h4",{id:"method-uniquerelaxedby"},(0,a.kt)("inlineCode",{parentName:"h4"},"uniqueRelaxedBy()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"uniqueRelaxedBy")," method returns all of the unique models in the collection by the given column, it doesn't need a sorted collection, but it needs the template argument, so it can cast the attribute value before comparing:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxedBy<QString>("name");\n\n/*\n {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n }\n*/\n')),(0,a.kt)("h4",{id:"method-value"},(0,a.kt)("inlineCode",{parentName:"h4"},"value()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"value")," method retrieves a given value from the first model of the collection:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<User> users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nQVariant votes = users.value("votes");\n\n// 200\n')),(0,a.kt)("p",null,"Alternatively, you can cast an obtained ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariant")," value to the given type by the second ",(0,a.kt)("inlineCode",{parentName:"p"},"value")," overload:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'quint64 votes = users.value<quint64>("votes");\n')),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"value")," method also accepts the second ",(0,a.kt)("inlineCode",{parentName:"p"},"defaultValue")," argument, which will be returned if a collection is empty, the first model is ",(0,a.kt)("inlineCode",{parentName:"p"},"nullptr"),", or a model doesn't contain the given column:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto votes = ModelsCollection<User>().value("votes", 0);\n\n// 0\n')),(0,a.kt)("p",null,"You can also call all ",(0,a.kt)("inlineCode",{parentName:"p"},"value")," overloads provided by the ",(0,a.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qlist.html#value"},(0,a.kt)("inlineCode",{parentName:"a"},"QList::value")),"."),(0,a.kt)("h4",{id:"method-where"},(0,a.kt)("inlineCode",{parentName:"h4"},"where()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"where")," method filters the collection by a given column / value pair:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.where("price", "=", 100);\n\n/*\n {\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n')),(0,a.kt)("p",null,"For convenience, if you want to verify that a column is ",(0,a.kt)("inlineCode",{parentName:"p"},"=")," to a given value, you may call ",(0,a.kt)("inlineCode",{parentName:"p"},"whereEq")," method. Similar ",(0,a.kt)("inlineCode",{parentName:"p"},"XxxEq")," methods are also defined for other commands:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'auto filtered = products.whereEq("price", 100);\n')),(0,a.kt)("p",null,"Optionally, you may pass a comparison operator as the second argument.",(0,a.kt)("br",null),"Supported operators are ",(0,a.kt)("inlineCode",{parentName:"p"},"="),", ",(0,a.kt)("inlineCode",{parentName:"p"},"!="),", ",(0,a.kt)("inlineCode",{parentName:"p"},"<"),", ",(0,a.kt)("inlineCode",{parentName:"p"},">"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"<="),", and ",(0,a.kt)("inlineCode",{parentName:"p"},">="),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.where("price", ">", 150);\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n')),(0,a.kt)("h4",{id:"method-wherebetween"},(0,a.kt)("inlineCode",{parentName:"h4"},"whereBetween()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"whereBetween")," method filters the collection by determining if a specified models' attribute value is within a given range:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereBetween<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n')),(0,a.kt)("h4",{id:"method-wherein"},(0,a.kt)("inlineCode",{parentName:"h4"},"whereIn()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"whereIn")," method filters models from the collection that have a specified attribute value that is contained within the given unordered set:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereIn<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n }\n*/\n')),(0,a.kt)("p",null,"An empty collection is returned if the ",(0,a.kt)("inlineCode",{parentName:"p"},"values")," argument is empty ",(0,a.kt)("inlineCode",{parentName:"p"},'whereIn("price", {})'),"."),(0,a.kt)("p",null,"The order of models in the collection is preserved."),(0,a.kt)("h4",{id:"method-wherenotbetween"},(0,a.kt)("inlineCode",{parentName:"h4"},"whereNotBetween()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"whereNotBetween")," method filters the collection by determining if a specified models' attribute value is outside of a given range:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereNotBetween<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Pencil"}, {"price", 30}},\n }\n*/\n')),(0,a.kt)("h4",{id:"method-wherenotin"},(0,a.kt)("inlineCode",{parentName:"h4"},"whereNotIn()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"whereNotIn")," method removes models from the collection that have a specified attribute value that is contained within the given unordered set:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereNotIn<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n')),(0,a.kt)("p",null,"All of the models are returned if the ",(0,a.kt)("inlineCode",{parentName:"p"},"values")," argument is empty ",(0,a.kt)("inlineCode",{parentName:"p"},'whereNotIn("price", {})'),"."),(0,a.kt)("p",null,"The order of models in the collection is preserved."),(0,a.kt)("h4",{id:"method-wherenotnull"},(0,a.kt)("inlineCode",{parentName:"h4"},"whereNotNull()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"whereNotNull")," method returns models from the collection where the given column is not ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," QVariant:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'#include <orm/utils/nullvariant.hpp>\n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection<User> users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n/*\n {\n {{"name", "John"}},\n {{"name", "Jack"}},\n }\n*/\n')),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"NullVariant")," class returns the correct ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," QVariant for both Qt 5 ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariant(QVariant::String)")," and also Qt 6 ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariant(QMetaType(QMetaType::QString))"),".")),(0,a.kt)("h4",{id:"method-wherenull"},(0,a.kt)("inlineCode",{parentName:"h4"},"whereNull()")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"whereNull")," method returns models from the collection where the given column is ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," QVariant:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'#include <orm/utils/nullvariant.hpp>\n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection<User> users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n// {{"name", NullVariant::QString()}}\n')),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"The ",(0,a.kt)("inlineCode",{parentName:"p"},"NullVariant")," class returns the correct ",(0,a.kt)("inlineCode",{parentName:"p"},"null")," QVariant for both Qt 5 ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariant(QVariant::String)")," and also Qt 6 ",(0,a.kt)("inlineCode",{parentName:"p"},"QVariant(QMetaType(QMetaType::QString))"),"."))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3dd307b5.7d5f3256.js b/assets/js/3dd307b5.7d5f3256.js new file mode 100644 index 000000000..7c7d56860 --- /dev/null +++ b/assets/js/3dd307b5.7d5f3256.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[117],{1126:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>i,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>d,toc:()=>c});var o=t(4848),s=t(8453);const r={sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},l="TinyORM: Collections",d={id:"tinyorm/collections",title:"TinyORM: Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",source:"@site/docs/tinyorm/collections.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/collections",permalink:"/tinyorm/collections",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Collections",description:"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.",keywords:["c++ orm","orm","collections","collection","model","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Relationships",permalink:"/tinyorm/relationships"},next:{title:"Casts",permalink:"/tinyorm/casts"}},i={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Collection Conversion",id:"collection-conversion",level:4},{value:"Creating Collections",id:"creating-collections",level:3},{value:"Available Methods",id:"available-methods",level:2},{value:"<code>all()</code>",id:"method-all",level:4},{value:"<code>contains()</code>",id:"method-contains",level:4},{value:"<code>doesntContain()</code>",id:"method-doesntcontain",level:4},{value:"<code>each()</code>",id:"method-each",level:4},{value:"<code>except()</code>",id:"method-except",level:4},{value:"<code>filter()</code>",id:"method-filter",level:4},{value:"<code>find()</code>",id:"method-find",level:4},{value:"<code>first()</code>",id:"method-first",level:4},{value:"<code>firstWhere()</code>",id:"method-first-where",level:4},{value:"<code>fresh()</code>",id:"method-fresh",level:4},{value:"<code>implode()</code>",id:"method-implode",level:4},{value:"<code>isEmpty()</code>",id:"method-isempty",level:4},{value:"<code>isNotEmpty()</code>",id:"method-isnotempty",level:4},{value:"<code>last()</code>",id:"method-last",level:4},{value:"<code>load()</code>",id:"method-load",level:4},{value:"<code>map()</code>",id:"method-map",level:4},{value:"<code>mapWithKeys()</code>",id:"method-mapwithkeys",level:4},{value:"<code>mapWithModelKeys()</code>",id:"method-mapwithmodelkeys",level:4},{value:"<code>modelKeys()</code>",id:"method-modelkeys",level:4},{value:"<code>only()</code>",id:"method-only",level:4},{value:"<code>pluck()</code>",id:"method-pluck",level:4},{value:"<code>reject()</code>",id:"method-reject",level:4},{value:"<code>sort()</code>",id:"method-sort",level:4},{value:"<code>sortBy()</code>",id:"method-sortby",level:4},{value:"<code>sortByDesc()</code>",id:"method-sortbydesc",level:4},{value:"<code>sortDesc()</code>",id:"method-sortdesc",level:4},{value:"<code>stableSort()</code>",id:"method-stablesort",level:4},{value:"<code>stableSortBy()</code>",id:"method-stablesortby",level:4},{value:"<code>stableSortByDesc()</code>",id:"method-stablesortbydesc",level:4},{value:"<code>stableSortDesc()</code>",id:"method-stablesortdesc",level:4},{value:"<code>tap()</code>",id:"method-tap",level:4},{value:"<code>toBase()</code>",id:"method-tobase",level:4},{value:"<code>toJson()</code>",id:"method-tojson",level:4},{value:"<code>toJsonArray()</code>",id:"method-tojsonarray",level:4},{value:"<code>toJsonDocument()</code>",id:"method-tojsondocument",level:4},{value:"<code>toMap()</code>",id:"method-tomap",level:4},{value:"<code>toMapVariantList()</code>",id:"method-tomapvariantlist",level:4},{value:"<code>toQuery()</code>",id:"method-toquery",level:4},{value:"<code>toVector()</code>",id:"method-tovector",level:4},{value:"<code>toVectorVariantList()</code>",id:"method-tovectorvariantlist",level:4},{value:"<code>unique()</code>",id:"method-unique",level:4},{value:"<code>uniqueBy()</code>",id:"method-uniqueby",level:4},{value:"<code>uniqueRelaxed()</code>",id:"method-uniquerelaxed",level:4},{value:"<code>uniqueRelaxedBy()</code>",id:"method-uniquerelaxedby",level:4},{value:"<code>value()</code>",id:"method-value",level:4},{value:"<code>where()</code>",id:"method-where",level:4},{value:"<code>whereBetween()</code>",id:"method-wherebetween",level:4},{value:"<code>whereIn()</code>",id:"method-wherein",level:4},{value:"<code>whereNotBetween()</code>",id:"method-wherenotbetween",level:4},{value:"<code>whereNotIn()</code>",id:"method-wherenotin",level:4},{value:"<code>whereNotNull()</code>",id:"method-wherenotnull",level:4},{value:"<code>whereNull()</code>",id:"method-wherenull",level:4}];function a(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,s.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"tinyorm-collections",children:"TinyORM: Collections"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"#introduction",children:"Introduction"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#creating-collections",children:"Creating Collections"})}),"\n"]}),"\n"]}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#available-methods",children:"Available Methods"})}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"Orm::Tiny::Types::ModelsCollection"})," is specialized container which provides a fluent, convenient wrapper for working with vector of models. All TinyORM methods that return more than one model result, will return instances of the ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," class, including results retrieved via the ",(0,o.jsx)(n.code,{children:"get"})," method or methods that return relationships like the ",(0,o.jsx)(n.code,{children:"getRelation"})," and ",(0,o.jsx)(n.code,{children:"getRelationValue"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," class extends ",(0,o.jsx)(n.code,{children:"QVector<Model>"}),", so it naturally inherits dozens of methods used to work with the underlying vector of TinyORM models. Be sure to review the ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html",children:(0,o.jsx)(n.code,{children:"QList"})})," documentation to learn all about these helpful methods!"]}),"\n",(0,o.jsx)(n.admonition,{type:"info",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," template parameter can be declared only with the model type or a model type pointer, it also can't be ",(0,o.jsx)(n.code,{children:"const"})," and can't be a reference. It's constrained using the ",(0,o.jsx)(n.code,{children:"DerivedCollectionModel"})," concept."]})}),"\n",(0,o.jsxs)(n.p,{children:["You can iterate over the ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," the same way as over the ",(0,o.jsx)(n.code,{children:"QVector"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nModelsCollection<User> users = User::whereEq("active", true)->get();\n\nfor (const auto &user : users)\n qDebug() << user.getAttribute<QString>("name");\n'})}),"\n",(0,o.jsx)(n.p,{children:"However, as previously mentioned, collections are much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, we may remove all active users and then gather the first name of each remaining user:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto names = User::all().reject([](User *const user)\n{\n return user->getAttribute<bool>("active");\n})\n .pluck("name");\n'})}),"\n",(0,o.jsxs)(n.p,{children:["As you can see, the ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," class allows you to chain its methods to perform fluent mapping and reducing of the underlying vector. In general, collections are immutable, meaning every ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," method returns an entirely new ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," instance."]}),"\n",(0,o.jsx)(n.admonition,{type:"info",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"ModelsCollection<Model>"})," is returning from the Models' methods like ",(0,o.jsx)(n.code,{children:"get"}),", ",(0,o.jsx)(n.code,{children:"all"}),", ",(0,o.jsx)(n.code,{children:"findMany"}),", ",(0,o.jsx)(n.code,{children:"chunk"}),"; the ",(0,o.jsx)(n.code,{children:"ModelsCollection<Model *>"})," is returning from the relationship-related methods as ",(0,o.jsx)(n.code,{children:"getRelation"})," and ",(0,o.jsx)(n.code,{children:"getRelationValue"}),"."]})}),"\n",(0,o.jsx)(n.h4,{id:"collection-conversion",children:"Collection Conversion"}),"\n",(0,o.jsxs)(n.p,{children:["While most TinyORM collection methods return a new instance of ",(0,o.jsx)(n.code,{children:"ModelsCollection"}),", the ",(0,o.jsx)(n.code,{children:"modelKeys"}),", ",(0,o.jsx)(n.code,{children:"mapWithKeys"}),", and ",(0,o.jsx)(n.code,{children:"pluck"})," methods return a base QVector or std unordered/map instances. Likewise, one of the ",(0,o.jsx)(n.code,{children:"map"})," methods overload returns the ",(0,o.jsx)(n.code,{children:"QVector<T>"}),"."]}),"\n",(0,o.jsx)(n.h3,{id:"creating-collections",children:"Creating Collections"}),"\n",(0,o.jsxs)(n.p,{children:["Creating a ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," is as simple as:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n'})}),"\n",(0,o.jsxs)(n.p,{children:["You can also create a collection of pointers, eg. ",(0,o.jsx)(n.code,{children:"ModelsCollection<User *>"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection<User *> userPointers {\n &users[0], &users[1],\n};\n"})}),"\n",(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"ModelsCollection<Model>"})," is implicitly convertible and assignable from the ",(0,o.jsx)(n.code,{children:"QVector<Model>"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'QVector<User> usersVector {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n};\n\nModelsCollection<User> users(usersVector);\nusers = usersVector;\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Alternatively, you can use the ",(0,o.jsx)(n.code,{children:"Orm::collect<Model>"})," helper function to create a ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," from the given attributes:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users = Orm::collect<User>({\n {{"name", "Kate"}, {"added_on", QDateTime::currentDateTimeUtc()}},\n {{"name", "John"}, {"added_on", QDateTime({2023, 6, 1}, {13, 46, 15}, Qt::UTC)}},\n});\n'})}),"\n",(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"Orm::collect<Model>"})," function is ",(0,o.jsx)(n.strong,{children:"mandatory"})," if your attributes contain the ",(0,o.jsx)(n.code,{children:"QDateTime"})," instance, you can read more about this problem ",(0,o.jsx)(n.a,{href:"/tinyorm/getting-started#qdatetime-and-connection-name-problem",children:"here"}),"."]})}),"\n",(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The results of ",(0,o.jsx)(n.a,{href:"/tinyorm/getting-started",children:"TinyORM"})," queries are always returned as ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," instances."]})}),"\n",(0,o.jsx)(n.h2,{id:"available-methods",children:"Available Methods"}),"\n",(0,o.jsxs)(n.p,{children:["For the majority of the remaining collection documentation, we'll discuss each method available on the ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," class. Remember, all of these methods may be chained to fluently manipulate the underlying vector."]}),"\n",(0,o.jsxs)(n.p,{children:["Furthermore, almost every method returns a new ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," instance, allowing you to preserve the original copy of the collection when necessary:"]}),"\n",(0,o.jsx)("div",{className:"collection-methods-list",children:(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.a,{href:"#method-all",children:"all"}),"\n",(0,o.jsx)(n.a,{href:"#method-contains",children:"contains"}),"\n",(0,o.jsx)(n.a,{href:"#method-doesntcontain",children:"doesntContain"}),"\n",(0,o.jsx)(n.a,{href:"#method-each",children:"each"}),"\n",(0,o.jsx)(n.a,{href:"#method-except",children:"except"}),"\n",(0,o.jsx)(n.a,{href:"#method-filter",children:"filter"}),"\n",(0,o.jsx)(n.a,{href:"#method-find",children:"find"}),"\n",(0,o.jsx)(n.a,{href:"#method-first",children:"first"}),"\n",(0,o.jsx)(n.a,{href:"#method-first-where",children:"firstWhere"}),"\n",(0,o.jsx)(n.a,{href:"#method-fresh",children:"fresh"}),"\n",(0,o.jsx)(n.a,{href:"#method-implode",children:"implode"}),"\n",(0,o.jsx)(n.a,{href:"#method-isempty",children:"isEmpty"}),"\n",(0,o.jsx)(n.a,{href:"#method-isnotempty",children:"isNotEmpty"}),"\n",(0,o.jsx)(n.a,{href:"#method-last",children:"last"}),"\n",(0,o.jsx)(n.a,{href:"#method-load",children:"load"}),"\n",(0,o.jsx)(n.a,{href:"#method-map",children:"map"}),"\n",(0,o.jsx)(n.a,{href:"#method-mapwithkeys",children:"mapWithKeys"}),"\n",(0,o.jsx)(n.a,{href:"#method-mapwithmodelkeys",children:"mapWithModelKeys"}),"\n",(0,o.jsx)(n.a,{href:"#method-modelkeys",children:"modelKeys"}),"\n",(0,o.jsx)(n.a,{href:"#method-only",children:"only"}),"\n",(0,o.jsx)(n.a,{href:"#method-pluck",children:"pluck"}),"\n",(0,o.jsx)(n.a,{href:"#method-reject",children:"reject"}),"\n",(0,o.jsx)(n.a,{href:"#method-sort",children:"sort"}),"\n",(0,o.jsx)(n.a,{href:"#method-sortby",children:"sortBy"}),"\n",(0,o.jsx)(n.a,{href:"#method-sortbydesc",children:"sortByDesc"}),"\n",(0,o.jsx)(n.a,{href:"#method-sortdesc",children:"sortDesc"}),"\n",(0,o.jsx)(n.a,{href:"#method-stablesort",children:"stableSort"}),"\n",(0,o.jsx)(n.a,{href:"#method-stablesortby",children:"stableSortBy"}),"\n",(0,o.jsx)(n.a,{href:"#method-stablesortbydesc",children:"stableSortByDesc"}),"\n",(0,o.jsx)(n.a,{href:"#method-stablesortdesc",children:"stableSortDesc"}),"\n",(0,o.jsx)(n.a,{href:"#method-tap",children:"tap"}),"\n",(0,o.jsx)(n.a,{href:"#method-tobase",children:"toBase"}),"\n",(0,o.jsx)(n.a,{href:"#method-tojson",children:"toJson"}),"\n",(0,o.jsx)(n.a,{href:"#method-tojsonarray",children:"toJsonArray"}),"\n",(0,o.jsx)(n.a,{href:"#method-tojsondocument",children:"toJsonDocument"}),"\n",(0,o.jsx)(n.a,{href:"#method-tomap",children:"toMap"}),"\n",(0,o.jsx)(n.a,{href:"#method-tomapvariantlist",children:"toMapVariantList"}),"\n",(0,o.jsx)(n.a,{href:"#method-toquery",children:"toQuery"}),"\n",(0,o.jsx)(n.a,{href:"#method-tovector",children:"toVector"}),"\n",(0,o.jsx)(n.a,{href:"#method-tovectorvariantlist",children:"toVectorVariantList"}),"\n",(0,o.jsx)(n.a,{href:"#method-unique",children:"unique"}),"\n",(0,o.jsx)(n.a,{href:"#method-uniqueby",children:"uniqueBy"}),"\n",(0,o.jsx)(n.a,{href:"#method-uniquerelaxed",children:"uniqueRelaxed"}),"\n",(0,o.jsx)(n.a,{href:"#method-uniquerelaxedby",children:"uniqueRelaxedBy"}),"\n",(0,o.jsx)(n.a,{href:"#method-value",children:"value"}),"\n",(0,o.jsx)(n.a,{href:"#method-where",children:"where"}),"\n",(0,o.jsx)(n.a,{href:"#method-wherebetween",children:"whereBetween"}),"\n",(0,o.jsx)(n.a,{href:"#method-wherein",children:"whereIn"}),"\n",(0,o.jsx)(n.a,{href:"#method-wherenotbetween",children:"whereNotBetween"}),"\n",(0,o.jsx)(n.a,{href:"#method-wherenotin",children:"whereNotIn"}),"\n",(0,o.jsx)(n.a,{href:"#method-wherenotnull",children:"whereNotNull"}),"\n",(0,o.jsx)(n.a,{href:"#method-wherenull",children:"whereNull"})]})}),"\n",(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["For a better understanding of the following examples, many of the variable declarations below use actual types instead of the ",(0,o.jsx)(n.code,{children:"auto"})," keyword."]})}),"\n",(0,o.jsxs)("div",{className:"collection-methods",children:[(0,o.jsx)(n.h4,{id:"method-all",children:(0,o.jsx)(n.code,{children:"all()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"all"})," method returns a copy of the underlying vector represented by the collection:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"QVector<User> = users.all();\n"})}),(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.a,{href:"#method-tobase",children:(0,o.jsx)(n.code,{children:"toBase"})})," is an alias to the ",(0,o.jsx)(n.code,{children:"all"})," method."]})}),(0,o.jsx)(n.h4,{id:"method-contains",children:(0,o.jsx)(n.code,{children:"contains()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"contains"})," method may be used to determine if a given model instance is contained by the collection. This method accepts a primary key or a model instance:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"users.contains(1);\n\nusers.contains(User::find(1));\n"})}),(0,o.jsxs)(n.p,{children:["Alternatively, you may pass a lambda expression to the ",(0,o.jsx)(n.code,{children:"contains"})," method to determine if a model exists in the collection matching a given truth test:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"users.contains([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n"})}),(0,o.jsxs)(n.p,{children:["For the inverse of ",(0,o.jsx)(n.code,{children:"contains"}),", see the ",(0,o.jsx)(n.a,{href:"#method-doesntcontain",children:"doesntContain"})," method."]}),(0,o.jsx)(n.h4,{id:"method-doesntcontain",children:(0,o.jsx)(n.code,{children:"doesntContain()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"doesntContain"})," method determines whether the collection does not contain a given item. This method accepts a primary key or a model instance:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"users.doesntContain(1);\n\nusers.doesntContain(User::find(1));\n"})}),(0,o.jsxs)(n.p,{children:["Alternatively, you may pass a lambda expression to the ",(0,o.jsx)(n.code,{children:"doesntContain"})," method to determine if a model does not exist in the collection matching a given truth test:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"users.doesntContain([](const User *const user)\n{\n return user->getKeyCasted() == 2;\n});\n"})}),(0,o.jsxs)(n.p,{children:["For the inverse of ",(0,o.jsx)(n.code,{children:"doesntContain"}),", see the ",(0,o.jsx)(n.a,{href:"#method-contains",children:"contains"})," method."]}),(0,o.jsx)(n.h4,{id:"method-each",children:(0,o.jsx)(n.code,{children:"each()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"each"})," method iterates over the models in the collection and passes each model to the lambda expression:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users = Post::whereEq("user_id", 1)->get();\n\nusers.each([](User *const user)\n{\n // ...\n});\n'})}),(0,o.jsxs)(n.p,{children:["If you would like to stop iterating through the models, you may return ",(0,o.jsx)(n.code,{children:"false"})," from your lambda expression:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"users.each([](User *const user)\n{\n if (/* condition */)\n return false;\n\n // Some logic\n\n return true;\n});\n"})}),(0,o.jsx)(n.p,{children:"You may also pass the lambda expression with two parameters, whereas the second one is an index:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"users.each([](User *const user, const std::size_t index)\n{\n // ...\n});\n"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"each"})," method returns an lvalue ",(0,o.jsx)(n.strong,{children:"reference"})," to the currently processed collection."]}),(0,o.jsxs)(n.p,{children:["It can be also called on ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," rvalues, it returns an rvalue reference in this case."]}),(0,o.jsx)(n.h4,{id:"method-except",children:(0,o.jsx)(n.code,{children:"except()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"except"})," method returns all of the models that do not have the given primary keys:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection<User *> usersResult = users.except({1, 2, 3});\n"})}),(0,o.jsxs)(n.p,{children:["All of the models are returned if the ",(0,o.jsx)(n.code,{children:"ids"})," argument is empty ",(0,o.jsx)(n.code,{children:"except({})"}),"."]}),(0,o.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,o.jsxs)(n.p,{children:["For the inverse of ",(0,o.jsx)(n.code,{children:"except"}),", see the ",(0,o.jsx)(n.a,{href:"#method-only",children:"only"})," method."]}),(0,o.jsx)(n.h4,{id:"method-filter",children:(0,o.jsx)(n.code,{children:"filter()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"filter"})," method filters the collection using the lambda expression, keeping only those models that pass a given truth test:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto usersBanned = users.filter([](const User *const user)\n{\n return user->getAttribute<bool>("is_banned");\n});\n'})}),(0,o.jsx)(n.p,{children:"You may also pass the lambda expression with two parameters, whereas the second one is an index:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto usersBanned = users.filter([](const User *const user,\n const std::size_t index)\n{\n return index < 10 && user->getAttribute<bool>("is_banned");\n});\n'})}),(0,o.jsxs)(n.p,{children:["If no lambda expression is supplied, all models of the collection that are equivalent to the ",(0,o.jsx)(n.code,{children:"nullptr"})," will be removed:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection<User> usersRaw = User::findMany({1, 2});\nModelsCollection<User *> users {&usersRaw[0], nullptr, &usersRaw[1]};\n\nModelsCollection<User *> filtered = users.filter();\n\n// {1, 2}\n"})}),(0,o.jsxs)(n.p,{children:["For the inverse of ",(0,o.jsx)(n.code,{children:"filter"}),", see the ",(0,o.jsx)(n.a,{href:"#method-reject",children:"reject"})," method."]}),(0,o.jsx)(n.h4,{id:"method-find",children:(0,o.jsx)(n.code,{children:"find()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"find"})," method returns the model that has a primary key matching the given key:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"User *const user = users.find(1);\n"})}),(0,o.jsxs)(n.p,{children:["If you pass a model instance, ",(0,o.jsx)(n.code,{children:"find"})," will attempt to return a model matching the primary key:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"User *user = users.find(anotherUser);\n"})}),(0,o.jsxs)(n.p,{children:["The two overloads above also accept the second ",(0,o.jsx)(n.code,{children:"defaultModel"})," model argument, which will be returned if a model was not found in the collection, its default value is the ",(0,o.jsx)(n.code,{children:"nullptr"}),"."]}),(0,o.jsxs)(n.p,{children:["Alternatively, may pass more IDs and ",(0,o.jsx)(n.code,{children:"find"})," will return all models which have a primary key within the given unordered set:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection<User *> usersMany = users.find({1, 2});\n"})}),(0,o.jsxs)(n.p,{children:["This overload internally calls the ",(0,o.jsx)(n.a,{href:"#method-only",children:(0,o.jsx)(n.code,{children:"only"})})," method."]}),(0,o.jsx)(n.h4,{id:"method-first",children:(0,o.jsx)(n.code,{children:"first()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"first"})," method returns the first model in the collection that passes a given truth test:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute<quint64>("votes") > 150;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n'})}),(0,o.jsxs)(n.p,{children:["If no model passes a given truth test then the value of the second ",(0,o.jsx)(n.code,{children:"defaultModel"})," argument will be returned, its default value is the ",(0,o.jsx)(n.code,{children:"nullptr"}),"."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.first([](User *const user)\n{\n return user->getAttribute<quint64>("votes") > 500;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n'})}),(0,o.jsxs)(n.p,{children:["You can also call all ",(0,o.jsx)(n.code,{children:"first"})," overloads provided by the ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#first",children:(0,o.jsx)(n.code,{children:"QList::first"})}),"."]}),(0,o.jsx)(n.h4,{id:"method-first-where",children:(0,o.jsx)(n.code,{children:"firstWhere()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"firstWhere"})," method returns the first model in the collection with the given column / value pair:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection<User> users {\n {{"name", "Leon"}, {"age", NullVariant::UShort()}},\n {{"name", "Jill"}, {"age", 14}},\n {{"name", "Jack"}, {"age", 23}},\n {{"name", "Jill"}, {"age", 84}},\n};\n\nauto user = users.firstWhereEq("name", "Linda");\n\n// {{"name", "Jill"}, {"age", 14}}\n'})}),(0,o.jsxs)(n.p,{children:["You may also call the ",(0,o.jsx)(n.code,{children:"firstWhere"})," method with a comparison operator:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'users.firstWhere("age", ">=", 18);\n\n// {{"name", "Jack"}, {"age", 23}}\n'})}),(0,o.jsx)(n.h4,{id:"method-fresh",children:(0,o.jsx)(n.code,{children:"fresh()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"fresh"})," method retrieves a fresh instance of each model in the collection from the database. In addition, any specified relationships will be eager loaded:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto usersFresh = users.fresh();\n\nauto usersFresh = users.fresh("comments");\n\nauto usersFresh = users.fresh("posts:id,name");\n\nauto usersFresh = users.fresh({"comments", "posts:id,name"});\n'})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"relations"})," argument format is the same as for TinyBuilder's ",(0,o.jsx)(n.a,{href:"/tinyorm/relationships#lazy-eager-loading",children:(0,o.jsx)(n.code,{children:"load"})})," method."]}),(0,o.jsx)(n.h4,{id:"method-implode",children:(0,o.jsx)(n.code,{children:"implode()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"implode"}),' method joins attributes by the given column and the "glue" string you wish to place between the values:']}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n};\n\nproducts.implode("product", ", ");\n\n// {Desk, Chair}\n'})}),(0,o.jsx)(n.p,{children:'The default "glue" value is an empty string "".'}),(0,o.jsx)(n.h4,{id:"method-isempty",children:(0,o.jsx)(n.code,{children:"isEmpty()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"isEmpty"})," method returns ",(0,o.jsx)(n.code,{children:"true"})," if the collection is empty; otherwise, ",(0,o.jsx)(n.code,{children:"false"})," is returned:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection<User>().isEmpty();\n\n// true\n"})}),(0,o.jsx)(n.h4,{id:"method-isnotempty",children:(0,o.jsx)(n.code,{children:"isNotEmpty()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"isNotEmpty"})," method returns ",(0,o.jsx)(n.code,{children:"true"})," if the collection is not empty; otherwise, ",(0,o.jsx)(n.code,{children:"false"})," is returned:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection<User>().isNotEmpty();\n\n// false\n"})}),(0,o.jsx)(n.h4,{id:"method-last",children:(0,o.jsx)(n.code,{children:"last()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"last"})," method returns the last model in the collection that passes a given truth test:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "Rose"}, {"votes", 350}},\n};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute<quint64>("votes") < 300;\n});\n\n// {{"name", "John"}, {"votes", 200}}\n'})}),(0,o.jsxs)(n.p,{children:["If no model passes a given truth test then the value of the second ",(0,o.jsx)(n.code,{children:"defaultModel"})," argument will be returned, its default value is the ",(0,o.jsx)(n.code,{children:"nullptr"}),"."]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'using NullVariant = Orm::Utils::NullVariant;\n\nUser defaultUser {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}};\n\nUser *user = users.last([](User *const user)\n{\n return user->getAttribute<quint64>("votes") < 100;\n},\n &defaultUser);\n\n/*\n {{"name", NullVariant::QString()},\n {"votes", NullVariant::ULongLong()}}\n*/\n'})}),(0,o.jsxs)(n.p,{children:["You can also call all ",(0,o.jsx)(n.code,{children:"last"})," overloads provided by the ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#last",children:(0,o.jsx)(n.code,{children:"QList::last"})}),"."]}),(0,o.jsx)(n.h4,{id:"method-load",children:(0,o.jsx)(n.code,{children:"load()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"load"})," method eager loads the given relationships for all models in the collection:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'users.load({"comments", "posts"});\n\nusers.load("comments.author");\n\nusers.load({{"comments"}, {"posts", [](auto &query)\n{\n query.whereEq("active", true);\n}}});\n'})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"relations"})," argument format is the same as for TinyBuilder's ",(0,o.jsx)(n.a,{href:"/tinyorm/relationships#lazy-eager-loading",children:(0,o.jsx)(n.code,{children:"load"})})," method."]}),(0,o.jsx)(n.h4,{id:"method-map",children:(0,o.jsx)(n.code,{children:"map()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"map"})," method iterates through the collection and passes a ",(0,o.jsx)(n.strong,{children:"copy"})," of each model to the given lambda expression. The lambda expression is free to modify the model and return it, thus forming a new collection of modified models:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto usersAdded = users.map([](User &&userCopy)\n{\n if (userCopy.getAttribute<QString>("name") == "John")\n userCopy["votes"] = userCopy.getAttribute<quint64>("votes") + 1;\n\n return std::move(userCopy);\n});\n\n/*\n {\n {{"name", "John"}, {"price", 201}},\n {{"name", "Jack"}, {"price", 400}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["The second ",(0,o.jsx)(n.code,{children:"map"})," overload allows to return the ",(0,o.jsx)(n.code,{children:"QVector<T>"}),":"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'QVector<quint64> usersAdded = users.map<quint64>([](User &&userCopy)\n{\n const auto votesRef = userCopy["votes"];\n\n if (userCopy.getAttribute<QString>("name") == "John")\n votesRef = userCopy.getAttribute<quint64>("votes") + 1;\n\n return votesRef->value<quint64>();\n});\n\n// {201, 400}\n'})}),(0,o.jsxs)(n.p,{children:["Both overloads allow to pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,o.jsx)(n.code,{children:"std::size_t"})," type."]}),(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsxs)(n.p,{children:["Like most other collection methods, ",(0,o.jsx)(n.code,{children:"map"})," returns a new collection instance; it does not modify the collection it is called on. If you want to modify the original collection in place, use the ",(0,o.jsx)(n.a,{href:"#method-each",children:(0,o.jsx)(n.code,{children:"each"})})," method."]})}),(0,o.jsx)(n.admonition,{type:"info",children:(0,o.jsxs)(n.p,{children:["The model copy is passed to the lambda expression even if the ",(0,o.jsx)(n.code,{children:"map"})," iterates over a collection of model pointers ",(0,o.jsx)(n.code,{children:"ModelsCollection<Model *>"}),". The models are dereferenced behind the scene."]})}),(0,o.jsx)(n.h4,{id:"method-mapwithkeys",children:(0,o.jsx)(n.code,{children:"mapWithKeys()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"mapWithKeys"})," method iterates through the collection and passes each model to the given lambda expression. It returns the ",(0,o.jsx)(n.code,{children:"std::unordered_map<K, V>"})," and the lambda expression should return the ",(0,o.jsx)(n.code,{children:"std::pair<K, V>"})," containing a single column / value pair:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"id", 1}, {"name", "John"}, {"email", "john@example.com"}},\n {{"id", 2}, {"name", "Jill"}, {"email", "jill@example.com"}},\n};\n\nauto usersMap = users.mapWithKeys<quint64, QString>(\n [](User *const user) -> std::pair<quint64, QString>\n{\n return {user->getKeyCasted(), user->getAttribute<QString>("name")};\n});\n\n// {{1, \'John\'}, {2, \'Jill\'}}\n'})}),(0,o.jsx)(n.p,{children:"You can also map IDs to the model pointers:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"auto usersMap = users.mapWithKeys<quint64, User *>(\n [](User *const user) -> std::pair<quint64, User *>\n{\n return {user->getKeyCasted(), user};\n});\n"})}),(0,o.jsx)(n.h4,{id:"method-mapwithmodelkeys",children:(0,o.jsx)(n.code,{children:"mapWithModelKeys()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"mapWithModelKeys"})," maps the primary keys to the ",(0,o.jsx)(n.code,{children:"Model *"}),", it returns the ",(0,o.jsx)(n.code,{children:"std::unordered_map<Model::KeyType, Model *>"}),":"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"auto usersMap = users.mapWithModelKeys();\n"})}),(0,o.jsx)(n.h4,{id:"method-modelkeys",children:(0,o.jsx)(n.code,{children:"modelKeys()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"modelKeys"})," method returns the primary keys for all models in the collection:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"id", 1}, {"name", "John"}},\n {{"id", 2}, {"name", "Jill"}},\n {{"id", 3}, {"name", "Kate"}},\n {{"id", 5}, {"name", "Rose"}},\n};\n\nusers.modelKeys(); // Returns QVector<QVariant>\nusers.modelKeys<quint64>();\n\n// {1, 2, 3, 5}\n'})}),(0,o.jsx)(n.h4,{id:"method-only",children:(0,o.jsx)(n.code,{children:"only()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"only"})," method returns all of the models that have the given primary keys:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"ModelsCollection<User *> usersResult = users.only({1, 2, 3});\n"})}),(0,o.jsxs)(n.p,{children:["An empty collection is returned if the ",(0,o.jsx)(n.code,{children:"ids"})," argument is empty ",(0,o.jsx)(n.code,{children:"only({})"}),"."]}),(0,o.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,o.jsxs)(n.p,{children:["For the inverse of ",(0,o.jsx)(n.code,{children:"only"}),", see the ",(0,o.jsx)(n.a,{href:"#method-except",children:"except"})," method."]}),(0,o.jsx)(n.h4,{id:"method-pluck",children:(0,o.jsx)(n.code,{children:"pluck()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"pluck"})," method retrieves all of the values for a given column, the following overload returns the ",(0,o.jsx)(n.code,{children:"QVector<QVariant>"}),":"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"id", 1}, {"name", "Desk"}},\n {{"id", 2}, {"name", "Chair"}},\n};\n\nauto plucked = products.pluck("name");\n\n// {Desk, Chair}\n'})}),(0,o.jsxs)(n.p,{children:["The second overload allows returning the custom type ",(0,o.jsx)(n.code,{children:"QVector<T>"}),":"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto plucked = products.pluck<QString>("name");\n'})}),(0,o.jsxs)(n.p,{children:["You may also specify how you wish the resulting collection to be keyed, this overload returns the ",(0,o.jsx)(n.code,{children:"std::map<T, QVariant>"}),":"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto plucked = products.pluck<quint64>("name", "id");\n\n// {{1, "Desk"}, {2, "Chair"}}\n'})}),(0,o.jsx)(n.p,{children:"If duplicate keys exist, the last matching attribute will be inserted into the plucked collection:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> collection {\n {{"brand", "Tesla"}, {"color", "red"}},\n {{"brand", "Pagani"}, {"color", "white"}},\n {{"brand", "Tesla"}, {"color", "black"}},\n {{"brand", "Pagani"}, {"color", "orange"}},\n};\n\nauto plucked = collection.pluck<QString>("color", "brand");\n\n// {{\'Tesla\', \'black\'}, {\'Pagani\', \'orange"}}\n'})}),(0,o.jsx)(n.h4,{id:"method-reject",children:(0,o.jsx)(n.code,{children:"reject()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"reject"})," method filters the collection using the given lambda expression. The lambda should return ",(0,o.jsx)(n.code,{children:"true"})," if the model should be removed from the resulting collection:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto usersWithNote = users.reject([](const User *const user)\n{\n return user->getAttribute("note").isNull();\n});\n'})}),(0,o.jsxs)(n.p,{children:["You may also pass the lambda expression with two arguments, whereas the second argument can be an index of the ",(0,o.jsx)(n.code,{children:"std::size_t"})," type."]}),(0,o.jsxs)(n.p,{children:["For the inverse of the ",(0,o.jsx)(n.code,{children:"reject"})," method, see the ",(0,o.jsx)(n.a,{href:"#method-filter",children:(0,o.jsx)(n.code,{children:"filter"})})," method."]}),(0,o.jsx)(n.h4,{id:"method-sort",children:(0,o.jsx)(n.code,{children:"sort()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"sort"})," method sorts the models collection by primary keys:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sort();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["You may pass a predicate and projection callbacks to the ",(0,o.jsx)(n.code,{children:"sort"})," method with your own algorithms. Refer to the CPP reference documentation on ",(0,o.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/sort",children:(0,o.jsx)(n.code,{children:"ranges::sort"})}),", which is what the ",(0,o.jsx)(n.code,{children:"sort"})," method calls internally."]}),(0,o.jsxs)(n.p,{children:["You can eg. sort by multiple columns, for an alternative method of multi-column sorting look at ",(0,o.jsx)(n.a,{href:"#method-sortby",children:"sortBy"}),":"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sort([](const User *const left,\n const User *const right)\n{\n const auto leftValue = left->getAttribute<QString>("name");\n const auto rightValue = right->getAttribute<QString>("name");\n\n if (leftValue == rightValue)\n return left->getAttribute<quint64>("votes") <\n right->getAttribute<quint64>("votes");\n\n return leftValue < rightValue;\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 350}},\n }\n*/\n'})}),(0,o.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,o.jsx)(n.admonition,{type:"info",children:(0,o.jsxs)(n.p,{children:["You can use the ",(0,o.jsx)(n.a,{href:"#method-stablesort",children:"stable"})," sort method variants to preserve the order of equal models."]})}),(0,o.jsx)(n.h4,{id:"method-sortby",children:(0,o.jsx)(n.code,{children:"sortBy()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"sortBy"})," method sorts the collection by the given column, this overload needs the template argument so it can cast the attribute value before comparing:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nauto sorted = users.sortBy<QString>("name");\n\n/*\n {\n {{"name", "Jack"}, {"votes", 400}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Kate"}, {"votes", 150}},\n }\n*/\n'})}),(0,o.jsx)(n.p,{children:"You may pass the projection callback to determine how to sort the collection's models:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto sorted = users.sortBy([](User *const user)\n{\n return user->getAttribute<quint64>("votes");\n});\n\n/*\n {\n {{"name", "Kate"}, {"votes", 150}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["If you would like to sort your collection by multiple columns, you may pass a vector of comparison lambda expressions that define each sort operation to the ",(0,o.jsx)(n.code,{children:"sortBy"})," method, in the following example is the ",(0,o.jsx)(n.code,{children:"name"})," column sorted in ascending order and the second ",(0,o.jsx)(n.code,{children:"votes"})," column is sorted in descending order:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'using AttributeUtils = Orm::Tiny::Utils::Attribute;\n\nModelsCollection<User> users {\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 200}},\n};\n\nauto sorted = users.sortBy({\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortBy(\n left->getAttribute<QString>("name"),\n right->getAttribute<QString>("name"));\n },\n [](const User *const left, const User *const right)\n {\n return AttributeUtils::compareForSortByDesc(\n left->getAttribute<quint64>("votes"),\n right->getAttribute<quint64>("votes"));\n },\n});\n\n/*\n {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "John"}, {"votes", 150}},\n {{"name", "Kate"}, {"votes", 350}},\n {{"name", "Kate"}, {"votes", 200}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"AttributeUtils::compareForSortBy"})," and ",(0,o.jsx)(n.code,{children:"compareForSortByDesc"})," methods are helper methods, they are needed because the Qt framework doesn't define ",(0,o.jsx)(n.code,{children:"<=>"})," spaceship operator on its types, it doesn't support the three-way comparison."]}),(0,o.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,o.jsx)(n.h4,{id:"method-sortbydesc",children:(0,o.jsx)(n.code,{children:"sortByDesc()"})}),(0,o.jsxs)(n.p,{children:["This method has the same signature as the ",(0,o.jsx)(n.a,{href:"#method-sortby",children:(0,o.jsx)(n.code,{children:"sortBy"})})," method but will sort the collection in the opposite order."]}),(0,o.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,o.jsx)(n.h4,{id:"method-sortdesc",children:(0,o.jsx)(n.code,{children:"sortDesc()"})}),(0,o.jsxs)(n.p,{children:["This method will sort the collection in the opposite order as the ",(0,o.jsx)(n.a,{href:"#method-sort",children:(0,o.jsx)(n.code,{children:"sort"})})," method:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto sorted = users.sortDesc();\n\n/*\n {\n {{"id", 3}, {"name", "John"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n }\n*/\n'})}),(0,o.jsx)(n.p,{children:"The order of equal elements is not guaranteed to be preserved."}),(0,o.jsx)(n.h4,{id:"method-stablesort",children:(0,o.jsx)(n.code,{children:"stableSort()"})}),(0,o.jsxs)(n.p,{children:["This method has the same signature as the ",(0,o.jsx)(n.a,{href:"#method-sort",children:(0,o.jsx)(n.code,{children:"sort"})})," method but will preserve the order of equal elements (guaranteed to be preserved)."]}),(0,o.jsx)(n.h4,{id:"method-stablesortby",children:(0,o.jsx)(n.code,{children:"stableSortBy()"})}),(0,o.jsxs)(n.p,{children:["This method has the same signature as the ",(0,o.jsx)(n.a,{href:"#method-sortby",children:(0,o.jsx)(n.code,{children:"sortBy"})})," method but will preserve the order of equal elements (guaranteed to be preserved)."]}),(0,o.jsx)(n.h4,{id:"method-stablesortbydesc",children:(0,o.jsx)(n.code,{children:"stableSortByDesc()"})}),(0,o.jsxs)(n.p,{children:["This method has the same signature as the ",(0,o.jsx)(n.a,{href:"#method-sortbydesc",children:(0,o.jsx)(n.code,{children:"sortByDesc"})})," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."]}),(0,o.jsx)(n.h4,{id:"method-stablesortdesc",children:(0,o.jsx)(n.code,{children:"stableSortDesc()"})}),(0,o.jsxs)(n.p,{children:["This method has the same signature as the ",(0,o.jsx)(n.a,{href:"#method-sortdesc",children:(0,o.jsx)(n.code,{children:"sortDesc"})})," method but will sort the collection in the opposite order and preserve the order of equal elements (guaranteed to be preserved)."]}),(0,o.jsx)(n.h4,{id:"method-tap",children:(0,o.jsx)(n.code,{children:"tap()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"tap"}),' method passes a collection to the given lambda expression, allowing you to "tap" into the collection at a specific point and do something with the models while not affecting the collection itself:']}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nusers.sort()\n .tap([](/*const */ModelsCollection<User *> &usersRef)\n{\n qDebug() << "IDs after sorting:"\n << usersRef.template modelKeys<quint64>();\n})\n .value<quint64>("id");\n\n// 1\n'})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"tap"})," method returns an lvalue ",(0,o.jsx)(n.strong,{children:"reference"})," to the currently processed collection."]}),(0,o.jsxs)(n.p,{children:["It can be also called on ",(0,o.jsx)(n.code,{children:"ModelsCollection"})," rvalues, it returns an rvalue reference in this case."]}),(0,o.jsx)(n.h4,{id:"method-tobase",children:(0,o.jsx)(n.code,{children:"toBase()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toBase"})," method returns a copy of the underlying vector represented by the collection:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:"QVector<User> = users.toBase();\n"})}),(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.a,{href:"#method-tobase",children:(0,o.jsx)(n.code,{children:"toBase"})})," is an alias to the ",(0,o.jsx)(n.code,{children:"all"})," method."]})}),(0,o.jsx)(n.h4,{id:"method-tojson",children:(0,o.jsx)(n.code,{children:"toJson()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toJson"})," method converts the collection of models with all nested relations into a JSON serialized ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qbytearray.html",children:(0,o.jsx)(n.code,{children:"QByteArray"})}),"."]}),(0,o.jsxs)(n.p,{children:["It returns an empty array for empty ",(0,o.jsx)(n.code,{children:"many"})," type relations and ",(0,o.jsx)(n.code,{children:"null"})," for empty ",(0,o.jsx)(n.code,{children:"one"})," type relations."]}),(0,o.jsx)(n.admonition,{type:"info",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toJson"})," method accepts the ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html#JsonFormat-enum",children:(0,o.jsx)(n.code,{children:"QJsonDocument::JsonFormat"})}),", possible values are ",(0,o.jsx)(n.code,{children:"QJsonDocument::Indented"})," or ",(0,o.jsx)(n.code,{children:"QJsonDocument::Compact"}),"."]})}),(0,o.jsx)(n.h4,{id:"method-tojsonarray",children:(0,o.jsx)(n.code,{children:"toJsonArray()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toJsonArray"})," method converts the collection of models with all nested relations into a ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsonarray.html",children:(0,o.jsx)(n.code,{children:"QJsonArray"})}),"."]}),(0,o.jsx)(n.h4,{id:"method-tojsondocument",children:(0,o.jsx)(n.code,{children:"toJsonDocument()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toJsonDocument"})," method converts the collection of models with all nested relations into a ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qjsondocument.html",children:(0,o.jsx)(n.code,{children:"QJsonDocument"})}),"."]}),(0,o.jsx)(n.h4,{id:"method-tomap",children:(0,o.jsx)(n.code,{children:"toMap()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toMap"})," method converts the collection of models with all nested relations into an attributes map ",(0,o.jsx)(n.code,{children:"QVector<QVariantMap>"}),"."]}),(0,o.jsxs)(n.p,{children:["It returns an empty ",(0,o.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,o.jsx)(n.code,{children:"many"})," type relations and a null ",(0,o.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,o.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,o.jsx)(n.code,{children:"one"})," type relations."]}),(0,o.jsx)(n.h4,{id:"method-tomapvariantlist",children:(0,o.jsx)(n.code,{children:"toMapVariantList()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toMapVariantList"})," method converts the collection of models with all nested relations into an attributes map, but it returns the ",(0,o.jsx)("abbr",{title:"QList<QVariant>",children:(0,o.jsx)(n.code,{children:"QVariantList"})})," instead of the ",(0,o.jsx)(n.code,{children:"QVector<QVariantMap>"}),"."]}),(0,o.jsxs)(n.p,{children:["It returns an empty ",(0,o.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,o.jsx)(n.code,{children:"many"})," type relations and a null ",(0,o.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,o.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,o.jsx)(n.code,{children:"one"})," type relations."]}),(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toMapVariantList"})," method is internally needed by the ",(0,o.jsx)(n.code,{children:"toJson"})," related methods."]})}),(0,o.jsx)(n.h4,{id:"method-toquery",children:(0,o.jsx)(n.code,{children:"toQuery()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toQuery"})," method returns the ",(0,o.jsx)(n.code,{children:"TinyBuilder"})," instance containing a ",(0,o.jsx)(n.code,{children:"whereIn"})," constraint with the collection of models' primary keys:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'using Models::User;\n\nModelsCollection<User> users = User::whereEq("status", "VIP")->get();\n\nusers.toQuery()->update({\n {"status", "Administrator"},\n});\n'})}),(0,o.jsx)(n.h4,{id:"method-tovector",children:(0,o.jsx)(n.code,{children:"toVector()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toVector"})," method converts the collection of models with all nested relations into an attributes vector ",(0,o.jsx)(n.code,{children:"QVector<QVector<AttributeItem>>"}),"."]}),(0,o.jsxs)(n.p,{children:["It returns an empty ",(0,o.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,o.jsx)(n.code,{children:"many"})," type relations and a null ",(0,o.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,o.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,o.jsx)(n.code,{children:"one"})," type relations."]}),(0,o.jsx)(n.h4,{id:"method-tovectorvariantlist",children:(0,o.jsx)(n.code,{children:"toVectorVariantList()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toVectorVariantList"})," method converts the collection of models with all nested relations into an attributes vector, but it returns the ",(0,o.jsx)("abbr",{title:"QList<QVariant>",children:(0,o.jsx)(n.code,{children:"QVariantList"})})," instead of the ",(0,o.jsx)(n.code,{children:"QVector<QVector<AttributeItem>>"}),"."]}),(0,o.jsxs)(n.p,{children:["It returns an empty ",(0,o.jsx)(n.code,{children:"QVariantList"})," for empty ",(0,o.jsx)(n.code,{children:"many"})," type relations and a null ",(0,o.jsx)("abbr",{title:"QVariant::fromValue(nullptr)",children:(0,o.jsx)(n.code,{children:"QVariant"})})," for empty ",(0,o.jsx)(n.code,{children:"one"})," type relations."]}),(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"toVectorVariantList"})," method is internally needed by the ",(0,o.jsx)(n.code,{children:"toJson"})," related methods."]})}),(0,o.jsx)(n.h4,{id:"method-unique",children:(0,o.jsx)(n.code,{children:"unique()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"unique"})," method returns all of the unique models in the ",(0,o.jsx)(n.strong,{children:"sorted"})," collection. Any models with the same primary key as another model in the collection are removed:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.unique();\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["It sorts the collection internally because the ",(0,o.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique",children:(0,o.jsx)(n.code,{children:"ranges::unique"})})," can correctly operate only on the sorted container. You can disable it by passing ",(0,o.jsx)(n.code,{children:"false"})," using the first ",(0,o.jsx)(n.code,{children:"sort"})," parameter:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto unique = users.sort().unique(false);\n\n/*\n {\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,o.jsx)(n.h4,{id:"method-uniqueby",children:(0,o.jsx)(n.code,{children:"uniqueBy()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"uniqueBy"})," method returns all of the unique models in the ",(0,o.jsx)(n.strong,{children:"sorted"})," collection by the given column. Any models with the same column value as another model in the collection are removed. It needs the template argument, so it can cast the attribute value before comparing:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueBy<QString>("name");\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["It sorts the collection internally because the ",(0,o.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/algorithm/ranges/unique",children:(0,o.jsx)(n.code,{children:"ranges::unique"})})," can correctly operate only on the sorted container. You can disable it by passing ",(0,o.jsx)(n.code,{children:"false"})," using the second ",(0,o.jsx)(n.code,{children:"sort"})," parameter:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto unique = users.sortBy<QString>("name")\n .uniqueBy<QString>("name", false);\n\n/*\n {\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Kate"}},\n }\n*/\n'})}),(0,o.jsx)(n.h4,{id:"method-uniquerelaxed",children:(0,o.jsx)(n.code,{children:"uniqueRelaxed()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"uniqueRelaxed"})," method returns all of the unique models in the collection, it doesn't need a sorted collection. Any models with the same primary key as another model in the collection are removed:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n {{"id", 1}, {"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxed();\n\n/*\n {\n {{"id", 2}, {"name", "Kate"}},\n {{"id", 1}, {"name", "Jack"}},\n {{"id", 3}, {"name", "John"}},\n }\n*/\n'})}),(0,o.jsx)(n.h4,{id:"method-uniquerelaxedby",children:(0,o.jsx)(n.code,{children:"uniqueRelaxedBy()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"uniqueRelaxedBy"})," method returns all of the unique models in the collection by the given column, it doesn't need a sorted collection, but it needs the template argument, so it can cast the attribute value before comparing:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n {{"name", "Jack"}},\n};\n\nauto unique = users.uniqueRelaxedBy<QString>("name");\n\n/*\n {\n {{"name", "Kate"}},\n {{"name", "Jack"}},\n {{"name", "John"}},\n }\n*/\n'})}),(0,o.jsx)(n.h4,{id:"method-value",children:(0,o.jsx)(n.code,{children:"value()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"value"})," method retrieves a given value from the first model of the collection:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<User> users {\n {{"name", "John"}, {"votes", 200}},\n {{"name", "Jack"}, {"votes", 400}},\n};\n\nQVariant votes = users.value("votes");\n\n// 200\n'})}),(0,o.jsxs)(n.p,{children:["Alternatively, you can cast an obtained ",(0,o.jsx)(n.code,{children:"QVariant"})," value to the given type by the second ",(0,o.jsx)(n.code,{children:"value"})," overload:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'quint64 votes = users.value<quint64>("votes");\n'})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"value"})," method also accepts the second ",(0,o.jsx)(n.code,{children:"defaultValue"})," argument, which will be returned if a collection is empty, the first model is ",(0,o.jsx)(n.code,{children:"nullptr"}),", or a model doesn't contain the given column:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'auto votes = ModelsCollection<User>().value("votes", 0);\n\n// 0\n'})}),(0,o.jsxs)(n.p,{children:["You can also call all ",(0,o.jsx)(n.code,{children:"value"})," overloads provided by the ",(0,o.jsx)(n.a,{href:"https://doc.qt.io/qt/qlist.html#value",children:(0,o.jsx)(n.code,{children:"QList::value"})}),"."]}),(0,o.jsx)(n.h4,{id:"method-where",children:(0,o.jsx)(n.code,{children:"where()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"where"})," method filters the collection by a given column / value pair:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.where("price", "=", 100);\n\n/*\n {\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["For convenience, if you want to verify that a column is ",(0,o.jsx)(n.code,{children:"="})," to a given value, you may call ",(0,o.jsx)(n.code,{children:"whereEq"})," method. Similar ",(0,o.jsx)(n.code,{children:"XxxEq"})," methods are also defined for other commands:"]}),(0,o.jsx)(n.p,{children:'auto filtered = products.whereEq("price", 100);'}),(0,o.jsxs)(n.p,{children:["Optionally, you may pass a comparison operator as the second argument.",(0,o.jsx)("br",{}),"Supported operators are ",(0,o.jsx)(n.code,{children:"="}),", ",(0,o.jsx)(n.code,{children:"!="}),", ",(0,o.jsx)(n.code,{children:"<"}),", ",(0,o.jsx)(n.code,{children:">"}),", ",(0,o.jsx)(n.code,{children:"<="}),", and ",(0,o.jsx)(n.code,{children:">="}),":"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.where("price", ">", 150);\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n'})}),(0,o.jsx)(n.h4,{id:"method-wherebetween",children:(0,o.jsx)(n.code,{children:"whereBetween()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"whereBetween"})," method filters the collection by determining if a specified models' attribute value is within a given range:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereBetween<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 100}},\n }\n*/\n'})}),(0,o.jsx)(n.h4,{id:"method-wherein",children:(0,o.jsx)(n.code,{children:"whereIn()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"whereIn"})," method filters models from the collection that have a specified attribute value that is contained within the given unordered set:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereIn<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["An empty collection is returned if the ",(0,o.jsx)(n.code,{children:"values"})," argument is empty ",(0,o.jsx)(n.code,{children:'whereIn("price", {})'}),"."]}),(0,o.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,o.jsx)(n.h4,{id:"method-wherenotbetween",children:(0,o.jsx)(n.code,{children:"whereNotBetween()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"whereNotBetween"})," method filters the collection by determining if a specified models' attribute value is outside of a given range:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Pencil"}, {"price", 30}},\n {{"product", "Door"}, {"price", 100}},\n};\n\nauto filtered = products.whereNotBetween<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Chair"}, {"price", 80}},\n {{"product", "Pencil"}, {"price", 30}},\n }\n*/\n'})}),(0,o.jsx)(n.h4,{id:"method-wherenotin",children:(0,o.jsx)(n.code,{children:"whereNotIn()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"whereNotIn"})," method removes models from the collection that have a specified attribute value that is contained within the given unordered set:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'ModelsCollection<Product> products {\n {{"product", "Desk"}, {"price", 200}},\n {{"product", "Chair"}, {"price", 100}},\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n};\n\nauto filtered = products.whereNotIn<quint64>("price", {100, 200});\n\n/*\n {\n {{"product", "Bookcase"}, {"price", 150}},\n {{"product", "Door"}, {"price", 250}},\n }\n*/\n'})}),(0,o.jsxs)(n.p,{children:["All of the models are returned if the ",(0,o.jsx)(n.code,{children:"values"})," argument is empty ",(0,o.jsx)(n.code,{children:'whereNotIn("price", {})'}),"."]}),(0,o.jsx)(n.p,{children:"The order of models in the collection is preserved."}),(0,o.jsx)(n.h4,{id:"method-wherenotnull",children:(0,o.jsx)(n.code,{children:"whereNotNull()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"whereNotNull"})," method returns models from the collection where the given column is not ",(0,o.jsx)(n.code,{children:"null"})," QVariant:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'#include <orm/utils/nullvariant.hpp>\n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection<User> users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n/*\n {\n {{"name", "John"}},\n {{"name", "Jack"}},\n }\n*/\n'})}),(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"NullVariant"})," class returns the correct ",(0,o.jsx)(n.code,{children:"null"})," QVariant for both Qt 5 ",(0,o.jsx)(n.code,{children:"QVariant(QVariant::String)"})," and also Qt 6 ",(0,o.jsx)(n.code,{children:"QVariant(QMetaType(QMetaType::QString))"}),"."]})}),(0,o.jsx)(n.h4,{id:"method-wherenull",children:(0,o.jsx)(n.code,{children:"whereNull()"})}),(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"whereNull"})," method returns models from the collection where the given column is ",(0,o.jsx)(n.code,{children:"null"})," QVariant:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-cpp",children:'#include <orm/utils/nullvariant.hpp>\n\nusing NullVariant = Orm::Utils::NullVariant;\n\nModelsCollection<User> users {\n {{"name", "John"}},\n {{"name", NullVariant::QString()}},\n {{"name", "Jack"}},\n};\n\nauto filtered = users.whereNotNull("name");\n\n// {{"name", NullVariant::QString()}}\n'})}),(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The ",(0,o.jsx)(n.code,{children:"NullVariant"})," class returns the correct ",(0,o.jsx)(n.code,{children:"null"})," QVariant for both Qt 5 ",(0,o.jsx)(n.code,{children:"QVariant(QVariant::String)"})," and also Qt 6 ",(0,o.jsx)(n.code,{children:"QVariant(QMetaType(QMetaType::QString))"}),"."]})})]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(a,{...e})}):a(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>l,x:()=>d});var o=t(6540);const s={},r=o.createContext(s);function l(e){const n=o.useContext(r);return o.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),o.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/894.1afcfcdd.js b/assets/js/416.a3ad28f7.js similarity index 55% rename from assets/js/894.1afcfcdd.js rename to assets/js/416.a3ad28f7.js index 790d846d3..c3a6501d9 100644 --- a/assets/js/894.1afcfcdd.js +++ b/assets/js/416.a3ad28f7.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[894],{8894:(r,e,s)=>{s.r(e)}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[416],{416:(r,e,s)=>{s.r(e)}}]); \ No newline at end of file diff --git a/assets/js/446.d7af1da2.js b/assets/js/446.d7af1da2.js new file mode 100644 index 000000000..f86a9046d --- /dev/null +++ b/assets/js/446.d7af1da2.js @@ -0,0 +1 @@ +(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[446],{2364:(e,t,n)=>{"use strict";n.d(t,{A:()=>V});var o=n(6540),s=n(2303),c=n(4164),r=n(5293),a=n(6342);function l(){const{prism:e}=(0,a.p)(),{colorMode:t}=(0,r.G)(),n=e.theme,o=e.darkTheme||n;return"dark"===t?o:n}var i=n(7559),u=n(8426),d=n.n(u);const m=/title=(?<quote>["'])(?<title>.*?)\1/,p=/\{(?<range>[\d,-]+)\}/,b={js:{start:"\\/\\/",end:""},jsBlock:{start:"\\/\\*",end:"\\*\\/"},jsx:{start:"\\{\\s*\\/\\*",end:"\\*\\/\\s*\\}"},bash:{start:"#",end:""},html:{start:"\x3c!--",end:"--\x3e"}},f={...b,lua:{start:"--",end:""},wasm:{start:"\\;\\;",end:""},tex:{start:"%",end:""},vb:{start:"['\u2018\u2019]",end:""},vbnet:{start:"(?:_\\s*)?['\u2018\u2019]",end:""},rem:{start:"[Rr][Ee][Mm]\\b",end:""},f90:{start:"!",end:""},ml:{start:"\\(\\*",end:"\\*\\)"},cobol:{start:"\\*>",end:""}},h=Object.keys(b);function g(e,t){const n=e.map((e=>{const{start:n,end:o}=f[e];return`(?:${n}\\s*(${t.flatMap((e=>[e.line,e.block?.start,e.block?.end].filter(Boolean))).join("|")})\\s*${o})`})).join("|");return new RegExp(`^\\s*(?:${n})\\s*$`)}function k(e,t){let n=e.replace(/\n$/,"");const{language:o,magicComments:s,metastring:c}=t;if(c&&p.test(c)){const e=c.match(p).groups.range;if(0===s.length)throw new Error(`A highlight range has been given in code block's metastring (\`\`\` ${c}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`);const t=s[0].className,o=d()(e).filter((e=>e>0)).map((e=>[e-1,[t]]));return{lineClassNames:Object.fromEntries(o),code:n}}if(void 0===o)return{lineClassNames:{},code:n};const r=function(e,t){switch(e){case"js":case"javascript":case"ts":case"typescript":return g(["js","jsBlock"],t);case"jsx":case"tsx":return g(["js","jsBlock","jsx"],t);case"html":return g(["js","jsBlock","html"],t);case"python":case"py":case"bash":return g(["bash"],t);case"markdown":case"md":return g(["html","jsx","bash"],t);case"tex":case"latex":case"matlab":return g(["tex"],t);case"lua":case"haskell":case"sql":return g(["lua"],t);case"wasm":return g(["wasm"],t);case"vb":case"vba":case"visual-basic":return g(["vb","rem"],t);case"vbnet":return g(["vbnet","rem"],t);case"batch":return g(["rem"],t);case"basic":return g(["rem","f90"],t);case"fsharp":return g(["js","ml"],t);case"ocaml":case"sml":return g(["ml"],t);case"fortran":return g(["f90"],t);case"cobol":return g(["cobol"],t);default:return g(h,t)}}(o,s),a=n.split("\n"),l=Object.fromEntries(s.map((e=>[e.className,{start:0,range:""}]))),i=Object.fromEntries(s.filter((e=>e.line)).map((e=>{let{className:t,line:n}=e;return[n,t]}))),u=Object.fromEntries(s.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.start,t]}))),m=Object.fromEntries(s.filter((e=>e.block)).map((e=>{let{className:t,block:n}=e;return[n.end,t]})));for(let d=0;d<a.length;){const e=a[d].match(r);if(!e){d+=1;continue}const t=e.slice(1).find((e=>void 0!==e));i[t]?l[i[t]].range+=`${d},`:u[t]?l[u[t]].start=d:m[t]&&(l[m[t]].range+=`${l[m[t]].start}-${d-1},`),a.splice(d,1)}n=a.join("\n");const b={};return Object.entries(l).forEach((e=>{let[t,{range:n}]=e;d()(n).forEach((e=>{b[e]??=[],b[e].push(t)}))})),{lineClassNames:b,code:n}}const x={codeBlockContainer:"codeBlockContainer_Ckt0"};var B=n(4848);function j(e){let{as:t,...n}=e;const o=function(e){const t={color:"--prism-color",backgroundColor:"--prism-background-color"},n={};return Object.entries(e.plain).forEach((e=>{let[o,s]=e;const c=t[o];c&&"string"==typeof s&&(n[c]=s)})),n}(l());return(0,B.jsx)(t,{...n,style:o,className:(0,c.A)(n.className,x.codeBlockContainer,i.G.common.codeBlock)})}const y={codeBlockContent:"codeBlockContent_biex",codeBlockTitle:"codeBlockTitle_Ktv7",codeBlock:"codeBlock_bY9V",codeBlockStandalone:"codeBlockStandalone_MEMb",codeBlockLines:"codeBlockLines_e6Vv",codeBlockLinesWithNumbering:"codeBlockLinesWithNumbering_o6Pm",buttonGroup:"buttonGroup__atx"};function v(e){let{children:t,className:n}=e;return(0,B.jsx)(j,{as:"pre",tabIndex:0,className:(0,c.A)(y.codeBlockStandalone,"thin-scrollbar",n),children:(0,B.jsx)("code",{className:y.codeBlockLines,children:t})})}var C=n(9532);const N={attributes:!0,characterData:!0,childList:!0,subtree:!0};function w(e,t){const[n,s]=(0,o.useState)(),c=(0,o.useCallback)((()=>{s(e.current?.closest("[role=tabpanel][hidden]"))}),[e,s]);(0,o.useEffect)((()=>{c()}),[c]),function(e,t,n){void 0===n&&(n=N);const s=(0,C._q)(t),c=(0,C.Be)(n);(0,o.useEffect)((()=>{const t=new MutationObserver(s);return e&&t.observe(e,c),()=>t.disconnect()}),[e,s,c])}(n,(e=>{e.forEach((e=>{"attributes"===e.type&&"hidden"===e.attributeName&&(t(),c())}))}),{attributes:!0,characterData:!1,childList:!1,subtree:!1})}var E=n(1765);const L={codeLine:"codeLine_lJS_",codeLineNumber:"codeLineNumber_Tfdd",codeLineContent:"codeLineContent_feaV"};function A(e){let{line:t,classNames:n,showLineNumbers:o,getLineProps:s,getTokenProps:r}=e;1===t.length&&"\n"===t[0].content&&(t[0].content="");const a=s({line:t,className:(0,c.A)(n,o&&L.codeLine)}),l=t.map(((e,t)=>(0,B.jsx)("span",{...r({token:e})},t)));return(0,B.jsxs)("span",{...a,children:[o?(0,B.jsxs)(B.Fragment,{children:[(0,B.jsx)("span",{className:L.codeLineNumber}),(0,B.jsx)("span",{className:L.codeLineContent,children:l})]}):l,(0,B.jsx)("br",{})]})}var _=n(1312);function S(e){return(0,B.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,B.jsx)("path",{fill:"currentColor",d:"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"})})}function T(e){return(0,B.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,B.jsx)("path",{fill:"currentColor",d:"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"})})}const I={copyButtonCopied:"copyButtonCopied_obH4",copyButtonIcons:"copyButtonIcons_eSgA",copyButtonIcon:"copyButtonIcon_y97N",copyButtonSuccessIcon:"copyButtonSuccessIcon_LjdS"};function $(e){let{code:t,className:n}=e;const[s,r]=(0,o.useState)(!1),a=(0,o.useRef)(void 0),l=(0,o.useCallback)((()=>{!function(e,{target:t=document.body}={}){if("string"!=typeof e)throw new TypeError(`Expected parameter \`text\` to be a \`string\`, got \`${typeof e}\`.`);const n=document.createElement("textarea"),o=document.activeElement;n.value=e,n.setAttribute("readonly",""),n.style.contain="strict",n.style.position="absolute",n.style.left="-9999px",n.style.fontSize="12pt";const s=document.getSelection(),c=s.rangeCount>0&&s.getRangeAt(0);t.append(n),n.select(),n.selectionStart=0,n.selectionEnd=e.length;let r=!1;try{r=document.execCommand("copy")}catch{}n.remove(),c&&(s.removeAllRanges(),s.addRange(c)),o&&o.focus()}(t),r(!0),a.current=window.setTimeout((()=>{r(!1)}),1e3)}),[t]);return(0,o.useEffect)((()=>()=>window.clearTimeout(a.current)),[]),(0,B.jsx)("button",{type:"button","aria-label":s?(0,_.T)({id:"theme.CodeBlock.copied",message:"Copied",description:"The copied button label on code blocks"}):(0,_.T)({id:"theme.CodeBlock.copyButtonAriaLabel",message:"Copy code to clipboard",description:"The ARIA label for copy code blocks button"}),title:(0,_.T)({id:"theme.CodeBlock.copy",message:"Copy",description:"The copy button label on code blocks"}),className:(0,c.A)("clean-btn",n,I.copyButton,s&&I.copyButtonCopied),onClick:l,children:(0,B.jsxs)("span",{className:I.copyButtonIcons,"aria-hidden":"true",children:[(0,B.jsx)(S,{className:I.copyButtonIcon}),(0,B.jsx)(T,{className:I.copyButtonSuccessIcon})]})})}function W(e){return(0,B.jsx)("svg",{viewBox:"0 0 24 24",...e,children:(0,B.jsx)("path",{fill:"currentColor",d:"M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"})})}const M={wordWrapButtonIcon:"wordWrapButtonIcon_Bwma",wordWrapButtonEnabled:"wordWrapButtonEnabled_EoeP"};function H(e){let{className:t,onClick:n,isEnabled:o}=e;const s=(0,_.T)({id:"theme.CodeBlock.wordWrapToggle",message:"Toggle word wrap",description:"The title attribute for toggle word wrapping button of code block lines"});return(0,B.jsx)("button",{type:"button",onClick:n,className:(0,c.A)("clean-btn",t,o&&M.wordWrapButtonEnabled),"aria-label":s,title:s,children:(0,B.jsx)(W,{className:M.wordWrapButtonIcon,"aria-hidden":"true"})})}function R(e){let{children:t,className:n="",metastring:s,title:r,showLineNumbers:i,language:u}=e;const{prism:{defaultLanguage:d,magicComments:p}}=(0,a.p)(),b=function(e){return e?.toLowerCase()}(u??function(e){const t=e.split(" ").find((e=>e.startsWith("language-")));return t?.replace(/language-/,"")}(n)??d),f=l(),h=function(){const[e,t]=(0,o.useState)(!1),[n,s]=(0,o.useState)(!1),c=(0,o.useRef)(null),r=(0,o.useCallback)((()=>{const n=c.current.querySelector("code");e?n.removeAttribute("style"):(n.style.whiteSpace="pre-wrap",n.style.overflowWrap="anywhere"),t((e=>!e))}),[c,e]),a=(0,o.useCallback)((()=>{const{scrollWidth:e,clientWidth:t}=c.current,n=e>t||c.current.querySelector("code").hasAttribute("style");s(n)}),[c]);return w(c,a),(0,o.useEffect)((()=>{a()}),[e,a]),(0,o.useEffect)((()=>(window.addEventListener("resize",a,{passive:!0}),()=>{window.removeEventListener("resize",a)})),[a]),{codeBlockRef:c,isEnabled:e,isCodeScrollable:n,toggle:r}}(),g=function(e){return e?.match(m)?.groups.title??""}(s)||r,{lineClassNames:x,code:v}=k(t,{metastring:s,language:b,magicComments:p}),C=i??function(e){return Boolean(e?.includes("showLineNumbers"))}(s);return(0,B.jsxs)(j,{as:"div",className:(0,c.A)(n,b&&!n.includes(`language-${b}`)&&`language-${b}`),children:[g&&(0,B.jsx)("div",{className:y.codeBlockTitle,children:g}),(0,B.jsxs)("div",{className:y.codeBlockContent,children:[(0,B.jsx)(E.f4,{theme:f,code:v,language:b??"text",children:e=>{let{className:t,style:n,tokens:o,getLineProps:s,getTokenProps:r}=e;return(0,B.jsx)("pre",{tabIndex:0,ref:h.codeBlockRef,className:(0,c.A)(t,y.codeBlock,"thin-scrollbar"),style:n,children:(0,B.jsx)("code",{className:(0,c.A)(y.codeBlockLines,C&&y.codeBlockLinesWithNumbering),children:o.map(((e,t)=>(0,B.jsx)(A,{line:e,getLineProps:s,getTokenProps:r,classNames:x[t],showLineNumbers:C},t)))})})}}),(0,B.jsxs)("div",{className:y.buttonGroup,children:[(h.isEnabled||h.isCodeScrollable)&&(0,B.jsx)(H,{className:y.codeButton,onClick:()=>h.toggle(),isEnabled:h.isEnabled}),(0,B.jsx)($,{className:y.codeButton,code:v})]})]})]})}function V(e){let{children:t,...n}=e;const c=(0,s.A)(),r=function(e){return o.Children.toArray(e).some((e=>(0,o.isValidElement)(e)))?e:Array.isArray(e)?e.join(""):e}(t),a="string"==typeof r?R:v;return(0,B.jsx)(a,{...n,children:r},String(c))}},8426:(e,t)=>{function n(e){let t,n=[];for(let o of e.split(",").map((e=>e.trim())))if(/^-?\d+$/.test(o))n.push(parseInt(o,10));else if(t=o.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)){let[e,o,s,c]=t;if(o&&c){o=parseInt(o),c=parseInt(c);const e=o<c?1:-1;"-"!==s&&".."!==s&&"\u2025"!==s||(c+=e);for(let t=o;t!==c;t+=e)n.push(t)}}return n}t.default=n,e.exports=n},8453:(e,t,n)=>{"use strict";n.d(t,{R:()=>r,x:()=>a});var o=n(6540);const s={},c=o.createContext(s);function r(e){const t=o.useContext(c);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(c.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/426.97069429.js b/assets/js/462.0011555c.js similarity index 81% rename from assets/js/426.97069429.js rename to assets/js/462.0011555c.js index 3fd4bfd32..61621e71e 100644 --- a/assets/js/426.97069429.js +++ b/assets/js/462.0011555c.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[426],{1426:(e,t,r)=>{function n(e,t){var r=void 0;return function(){for(var n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];r&&clearTimeout(r),r=setTimeout((function(){return e.apply(void 0,o)}),t)}}function o(e){return e!==Object(e)}function i(e,t){if(e===t)return!0;if(o(e)||o(t)||"function"==typeof e||"function"==typeof t)return e===t;if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var r=0,n=Object.keys(e);r<n.length;r++){var a=n[r];if(!(a in t))return!1;if(!i(e[a],t[a]))return!1}return!0}r.r(t),r.d(t,{DocSearchModal:()=>pn});var a=function(){};function c(e){var t=e.item,r=e.items;return{index:t.__autocomplete_indexName,items:[t],positions:[1+r.findIndex((function(e){return e.objectID===t.objectID}))],queryID:t.__autocomplete_queryID,algoliaSource:["autocomplete"]}}function l(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i,a,c=[],l=!0,u=!1;try{if(i=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;l=!1}else for(;!(l=(n=i.call(r)).done)&&(c.push(n.value),c.length!==t);l=!0);}catch(s){u=!0,o=s}finally{try{if(!l&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(u)throw o}}return c}}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return u(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return u(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}var s=["items"],f=["items"];function m(e){return m="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},m(e)}function p(e){return function(e){if(Array.isArray(e))return v(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return v(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return v(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function v(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function d(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function y(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function h(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?y(Object(r),!0).forEach((function(t){b(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):y(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function b(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==m(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==m(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===m(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function g(e){return e.map((function(e){var t=e.items,r=d(e,s);return h(h({},r),{},{objectIDs:(null==t?void 0:t.map((function(e){return e.objectID})))||r.objectIDs})}))}function O(e){var t,r,n,o=(t=l((e.version||"").split(".").map(Number),2),r=t[0],n=t[1],r>=3||2===r&&n>=4||1===r&&n>=10);function i(t,r,n){if(o&&void 0!==n){var i=n[0].__autocomplete_algoliaCredentials,a={"X-Algolia-Application-Id":i.appId,"X-Algolia-API-Key":i.apiKey};e.apply(void 0,[t].concat(p(r),[{headers:a}]))}else e.apply(void 0,[t].concat(p(r)))}return{init:function(t,r){e("init",{appId:t,apiKey:r})},setUserToken:function(t){e("setUserToken",t)},clickedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("clickedObjectIDsAfterSearch",g(t),t[0].items)},clickedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("clickedObjectIDs",g(t),t[0].items)},clickedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];r.length>0&&e.apply(void 0,["clickedFilters"].concat(r))},convertedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("convertedObjectIDsAfterSearch",g(t),t[0].items)},convertedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("convertedObjectIDs",g(t),t[0].items)},convertedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];r.length>0&&e.apply(void 0,["convertedFilters"].concat(r))},viewedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&t.reduce((function(e,t){var r=t.items,n=d(t,f);return[].concat(p(e),p(function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,r=[],n=0;n<e.objectIDs.length;n+=t)r.push(h(h({},e),{},{objectIDs:e.objectIDs.slice(n,n+t)}));return r}(h(h({},n),{},{objectIDs:(null==r?void 0:r.map((function(e){return e.objectID})))||n.objectIDs})).map((function(e){return{items:r,payload:e}}))))}),[]).forEach((function(e){var t=e.items;return i("viewedObjectIDs",[e.payload],t)}))},viewedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];r.length>0&&e.apply(void 0,["viewedFilters"].concat(r))}}}function S(e){var t=e.items.reduce((function(e,t){var r;return e[t.__autocomplete_indexName]=(null!==(r=e[t.__autocomplete_indexName])&&void 0!==r?r:[]).concat(t),e}),{});return Object.keys(t).map((function(e){return{index:e,items:t[e],algoliaSource:["autocomplete"]}}))}function j(e){return e.objectID&&e.__autocomplete_indexName&&e.__autocomplete_queryID}function w(e){return w="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},w(e)}function E(e){return function(e){if(Array.isArray(e))return P(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return P(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return P(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function P(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function I(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function D(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?I(Object(r),!0).forEach((function(t){A(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):I(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function A(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==w(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==w(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===w(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var k="2.6.0",x="https://cdn.jsdelivr.net/npm/search-insights@".concat(k,"/dist/search-insights.min.js"),C=n((function(e){var t=e.onItemsChange,r=e.items,n=e.insights,o=e.state;t({insights:n,insightsEvents:S({items:r}).map((function(e){return D({eventName:"Items Viewed"},e)})),state:o})}),400);function _(e){var t=function(e){return D({onItemsChange:function(e){var t=e.insights,r=e.insightsEvents;t.viewedObjectIDs.apply(t,E(r.map((function(e){return D(D({},e),{},{algoliaSource:[].concat(E(e.algoliaSource||[]),["autocomplete-internal"])})}))))},onSelect:function(e){var t=e.insights,r=e.insightsEvents;t.clickedObjectIDsAfterSearch.apply(t,E(r.map((function(e){return D(D({},e),{},{algoliaSource:[].concat(E(e.algoliaSource||[]),["autocomplete-internal"])})}))))},onActive:a},e)}(e),r=t.insightsClient,o=t.onItemsChange,l=t.onSelect,u=t.onActive,s=r;r||function(e){if("undefined"!=typeof window)e({window:window})}((function(e){var t=e.window,r=t.AlgoliaAnalyticsObject||"aa";"string"==typeof r&&(s=t[r]),s||(t.AlgoliaAnalyticsObject=r,t[r]||(t[r]=function(){t[r].queue||(t[r].queue=[]);for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];t[r].queue.push(n)}),t[r].version=k,s=t[r],function(e){var t="[Autocomplete]: Could not load search-insights.js. Please load it manually following https://alg.li/insights-autocomplete";try{var r=e.document.createElement("script");r.async=!0,r.src=x,r.onerror=function(){console.error(t)},document.body.appendChild(r)}catch(n){console.error(t)}}(t))}));var f=O(s),m={current:[]},p=n((function(e){var t=e.state;if(t.isOpen){var r=t.collections.reduce((function(e,t){return[].concat(E(e),E(t.items))}),[]).filter(j);i(m.current.map((function(e){return e.objectID})),r.map((function(e){return e.objectID})))||(m.current=r,r.length>0&&C({onItemsChange:o,items:r,insights:f,state:t}))}}),0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(e){var t=e.setContext,r=e.onSelect,n=e.onActive;s("addAlgoliaAgent","insights-plugin"),t({algoliaInsightsPlugin:{__algoliaSearchParameters:{clickAnalytics:!0},insights:f}}),r((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&l({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Selected"},c({item:t,items:m.current}))]})})),n((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&u({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Active"},c({item:t,items:m.current}))]})}))},onStateChange:function(e){var t=e.state;p({state:t})},__autocomplete_pluginOptions:e}}function N(e){return N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},N(e)}function T(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function q(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==N(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==N(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===N(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function R(e,t,r){var n,o=t.initialState;return{getState:function(){return o},dispatch:function(n,i){var a=function(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?T(Object(r),!0).forEach((function(t){q(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):T(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}({},o);o=e(o,{type:n,props:t,payload:i}),r({state:o,prevState:a})},pendingRequests:(n=[],{add:function(e){return n.push(e),e.finally((function(){n=n.filter((function(t){return t!==e}))}))},cancelAll:function(){n.forEach((function(e){return e.cancel()}))},isEmpty:function(){return 0===n.length}})}}function L(e){return e.reduce((function(e,t){return e.concat(t)}),[])}function M(e){return M="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},M(e)}function H(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function F(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?H(Object(r),!0).forEach((function(t){U(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):H(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function U(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==M(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==M(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===M(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function B(e){return 0===e.collections.length?0:e.collections.reduce((function(e,t){return e+t.items.length}),0)}var V=0;function K(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function $(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?K(Object(r),!0).forEach((function(t){J(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):K(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function J(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==z(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==z(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===z(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function z(e){return z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},z(e)}function W(e){return W="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},W(e)}function Q(e){return function(e){if(Array.isArray(e))return Z(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Z(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Z(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Z(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function G(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function X(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?G(Object(r),!0).forEach((function(t){Y(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):G(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Y(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==W(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==W(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===W(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ee(e,t){var r,n="undefined"!=typeof window?window:{},o=e.plugins||[];return X(X({debug:!1,openOnFocus:!1,placeholder:"",autoFocus:!1,defaultActiveItemId:null,stallThreshold:300,insights:!1,environment:n,shouldPanelOpen:function(e){return B(e.state)>0},reshape:function(e){return e.sources}},e),{},{id:null!==(r=e.id)&&void 0!==r?r:"autocomplete-".concat(V++),plugins:o,initialState:X({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var r;null===(r=e.onStateChange)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onStateChange)||void 0===r?void 0:r.call(e,t)}))},onSubmit:function(t){var r;null===(r=e.onSubmit)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onSubmit)||void 0===r?void 0:r.call(e,t)}))},onReset:function(t){var r;null===(r=e.onReset)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onReset)||void 0===r?void 0:r.call(e,t)}))},getSources:function(r){return Promise.all([].concat(Q(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return function(e,t){var r=[];return Promise.resolve(e(t)).then((function(e){return Array.isArray(e),Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,r.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));r.push(e.sourceId);var t={getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:a,onResolve:a};Object.keys(t).forEach((function(e){t[e].__default=!0}));var n=$($({},t),e);return Promise.resolve(n)})))}))}(e,r)}))).then((function(e){return L(e)})).then((function(e){return e.map((function(e){return X(X({},e),{},{onSelect:function(r){e.onSelect(r),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,r)}))},onActive:function(r){e.onActive(r),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,r)}))},onResolve:function(r){e.onResolve(r),t.forEach((function(e){var t;return null===(t=e.onResolve)||void 0===t?void 0:t.call(e,r)}))}})}))}))},navigator:X({navigate:function(e){var t=e.itemUrl;n.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,r=n.open(t,"_blank","noopener");null==r||r.focus()},navigateNewWindow:function(e){var t=e.itemUrl;n.open(t,"_blank","noopener")}},e.navigator)})}function te(e){return te="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},te(e)}function re(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function ne(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?re(Object(r),!0).forEach((function(t){oe(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):re(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function oe(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==te(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==te(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===te(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ie(e){return ie="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},ie(e)}function ae(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function ce(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?ae(Object(r),!0).forEach((function(t){le(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ae(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function le(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==ie(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==ie(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===ie(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ue(e){return function(e){if(Array.isArray(e))return se(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return se(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return se(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function se(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function fe(e){return Boolean(e.execute)}function me(e,t,r){if(o=e,Boolean(null==o?void 0:o.execute)){var n="algolia"===e.requesterId?Object.assign.apply(Object,[{}].concat(ue(Object.keys(r.context).map((function(e){var t;return null===(t=r.context[e])||void 0===t?void 0:t.__algoliaSearchParameters}))))):{};return ce(ce({},e),{},{requests:e.queries.map((function(r){return{query:"algolia"===e.requesterId?ce(ce({},r),{},{params:ce(ce({},n),r.params)}):r,sourceId:t,transformResponse:e.transformResponse}}))})}var o;return{items:e,sourceId:t}}function pe(e){var t=e.reduce((function(e,t){if(!fe(t))return e.push(t),e;var r=t.searchClient,n=t.execute,o=t.requesterId,i=t.requests,a=e.find((function(e){return fe(t)&&fe(e)&&e.searchClient===r&&Boolean(o)&&e.requesterId===o}));if(a){var c;(c=a.items).push.apply(c,ue(i))}else{var l={execute:n,requesterId:o,items:i,searchClient:r};e.push(l)}return e}),[]).map((function(e){if(!fe(e))return Promise.resolve(e);var t=e,r=t.execute,n=t.items;return r({searchClient:t.searchClient,requests:n})}));return Promise.all(t).then((function(e){return L(e)}))}function ve(e,t,r){return t.map((function(t){var n,o=e.filter((function(e){return e.sourceId===t.sourceId})),i=o.map((function(e){return e.items})),a=o[0].transformResponse,c=a?a({results:n=i,hits:n.map((function(e){return e.hits})).filter(Boolean),facetHits:n.map((function(e){var t;return null===(t=e.facetHits)||void 0===t?void 0:t.map((function(e){return{label:e.value,count:e.count,_highlightResult:{label:{value:e.highlighted}}}}))})).filter(Boolean)}):i;return t.onResolve({source:t,results:i,items:c,state:r.getState()}),Array.isArray(c),c.every(Boolean),'The `getItems` function from source "'.concat(t.sourceId,'" must return an array of items but returned ').concat(JSON.stringify(void 0),".\n\nDid you forget to return items?\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems"),{source:t,items:c}}))}function de(e,t){var r=t;return{then:function(t,n){return de(e.then(be(t,r,e),be(n,r,e)),r)},catch:function(t){return de(e.catch(be(t,r,e)),r)},finally:function(t){return t&&r.onCancelList.push(t),de(e.finally(be(t&&function(){return r.onCancelList=[],t()},r,e)),r)},cancel:function(){r.isCanceled=!0;var e=r.onCancelList;r.onCancelList=[],e.forEach((function(e){e()}))},isCanceled:function(){return!0===r.isCanceled}}}function ye(e){return de(new Promise((function(t,r){return e(t,r)})),{isCanceled:!1,onCancelList:[]})}function he(e){return de(e,{isCanceled:!1,onCancelList:[]})}function be(e,t,r){return e?function(r){return t.isCanceled?r:e(r)}:r}function ge(e){var t=function(e){var t=e.collections.map((function(e){return e.items.length})).reduce((function(e,t,r){var n=(e[r-1]||0)+t;return e.push(n),e}),[]).reduce((function(t,r){return r<=e.activeItemId?t+1:t}),0);return e.collections[t]}(e);if(!t)return null;var r=t.items[function(e){for(var t=e.state,r=e.collection,n=!1,o=0,i=0;!1===n;){var a=t.collections[o];if(a===r){n=!0;break}i+=a.items.length,o++}return t.activeItemId-i}({state:e,collection:t})],n=t.source;return{item:r,itemInputValue:n.getItemInputValue({item:r,state:e}),itemUrl:n.getItemUrl({item:r,state:e}),source:n}}function Oe(e){return Oe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Oe(e)}ye.resolve=function(e){return he(Promise.resolve(e))},ye.reject=function(e){return he(Promise.reject(e))};var Se=["event","nextState","props","query","refresh","store"];function je(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function we(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?je(Object(r),!0).forEach((function(t){Ee(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):je(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Ee(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==Oe(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==Oe(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Oe(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Pe(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Ie,De,Ae,ke=null,xe=(Ie=-1,De=-1,Ae=void 0,function(e){var t=++Ie;return Promise.resolve(e).then((function(e){return Ae&&t<De?Ae:(De=t,Ae=e,e)}))});function Ce(e){var t=e.event,r=e.nextState,n=void 0===r?{}:r,o=e.props,i=e.query,a=e.refresh,c=e.store,l=Pe(e,Se);ke&&o.environment.clearTimeout(ke);var u=l.setCollections,s=l.setIsOpen,f=l.setQuery,m=l.setActiveItemId,p=l.setStatus;if(f(i),m(o.defaultActiveItemId),!i&&!1===o.openOnFocus){var v,d=c.getState().collections.map((function(e){return we(we({},e),{},{items:[]})}));p("idle"),u(d),s(null!==(v=n.isOpen)&&void 0!==v?v:o.shouldPanelOpen({state:c.getState()}));var y=he(xe(d).then((function(){return Promise.resolve()})));return c.pendingRequests.add(y)}p("loading"),ke=o.environment.setTimeout((function(){p("stalled")}),o.stallThreshold);var h=he(xe(o.getSources(we({query:i,refresh:a,state:c.getState()},l)).then((function(e){return Promise.all(e.map((function(e){return Promise.resolve(e.getItems(we({query:i,refresh:a,state:c.getState()},l))).then((function(t){return me(t,e.sourceId,c.getState())}))}))).then(pe).then((function(t){return ve(t,e,c)})).then((function(e){return function(e){var t=e.collections,r=e.props,n=e.state,o=t.reduce((function(e,t){return ne(ne({},e),{},oe({},t.source.sourceId,ne(ne({},t.source),{},{getItems:function(){return L(t.items)}})))}),{}),i=r.plugins.reduce((function(e,t){return t.reshape?t.reshape(e):e}),{sourcesBySourceId:o,state:n}).sourcesBySourceId;return L(r.reshape({sourcesBySourceId:i,sources:Object.values(i),state:n})).filter(Boolean).map((function(e){return{source:e,items:e.getItems()}}))}({collections:e,props:o,state:c.getState()})}))})))).then((function(e){var r;p("idle"),u(e);var f=o.shouldPanelOpen({state:c.getState()});s(null!==(r=n.isOpen)&&void 0!==r?r:o.openOnFocus&&!i&&f||f);var m=ge(c.getState());if(null!==c.getState().activeItemId&&m){var v=m.item,d=m.itemInputValue,y=m.itemUrl,h=m.source;h.onActive(we({event:t,item:v,itemInputValue:d,itemUrl:y,refresh:a,source:h,state:c.getState()},l))}})).finally((function(){p("idle"),ke&&o.environment.clearTimeout(ke)}));return c.pendingRequests.add(h)}function _e(e){return _e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},_e(e)}var Ne=["event","props","refresh","store"];function Te(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function qe(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?Te(Object(r),!0).forEach((function(t){Re(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):Te(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Re(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==_e(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==_e(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===_e(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Le(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Me=/((gt|sm)-|galaxy nexus)|samsung[- ]|samsungbrowser/i;function He(e){return He="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},He(e)}var Fe=["props","refresh","store"],Ue=["inputElement","formElement","panelElement"],Be=["inputElement"],Ve=["inputElement","maxLength"],Ke=["sourceIndex"],$e=["sourceIndex"],Je=["item","source","sourceIndex"];function ze(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function We(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?ze(Object(r),!0).forEach((function(t){Qe(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ze(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Qe(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==He(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==He(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===He(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Ze(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ge(e){var t=e.props,r=e.refresh,n=e.store,o=Ze(e,Fe),i=function(e,t){return void 0!==t?"".concat(e,"-").concat(t):e};return{getEnvironmentProps:function(e){var r=e.inputElement,o=e.formElement,i=e.panelElement;function a(e){!n.getState().isOpen&&n.pendingRequests.isEmpty()||e.target===r||!1===[o,i].some((function(t){return r=t,n=e.target,r===n||r.contains(n);var r,n}))&&(n.dispatch("blur",null),t.debug||n.pendingRequests.cancelAll())}return We({onTouchStart:a,onMouseDown:a,onTouchMove:function(e){!1!==n.getState().isOpen&&r===t.environment.document.activeElement&&e.target!==r&&r.blur()}},Ze(e,Ue))},getRootProps:function(e){return We({role:"combobox","aria-expanded":n.getState().isOpen,"aria-haspopup":"listbox","aria-owns":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){e.inputElement;return We({action:"",noValidate:!0,role:"search",onSubmit:function(i){var a;i.preventDefault(),t.onSubmit(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("submit",null),null===(a=e.inputElement)||void 0===a||a.blur()},onReset:function(i){var a;i.preventDefault(),t.onReset(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("reset",null),null===(a=e.inputElement)||void 0===a||a.focus()}},Ze(e,Be))},getLabelProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,Ke);return We({htmlFor:"".concat(i(t.id,n),"-input"),id:"".concat(i(t.id,n),"-label")},o)},getInputProps:function(e){var i;function c(e){(t.openOnFocus||Boolean(n.getState().query))&&Ce(We({event:e,props:t,query:n.getState().completion||n.getState().query,refresh:r,store:n},o)),n.dispatch("focus",null)}var l=e||{},u=(l.inputElement,l.maxLength),s=void 0===u?512:u,f=Ze(l,Ve),m=ge(n.getState()),p=function(e){return Boolean(e&&e.match(Me))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),v=null!=m&&m.itemUrl&&!p?"go":"search";return We({"aria-autocomplete":"both","aria-activedescendant":n.getState().isOpen&&null!==n.getState().activeItemId?"".concat(t.id,"-item-").concat(n.getState().activeItemId):void 0,"aria-controls":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:n.getState().completion||n.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:v,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:s,type:"search",onChange:function(e){Ce(We({event:e,props:t,query:e.currentTarget.value.slice(0,s),refresh:r,store:n},o))},onKeyDown:function(e){!function(e){var t=e.event,r=e.props,n=e.refresh,o=e.store,i=Le(e,Ne);if("ArrowUp"===t.key||"ArrowDown"===t.key){var a=function(){var e=r.environment.document.getElementById("".concat(r.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},c=function(){var e=ge(o.getState());if(null!==o.getState().activeItemId&&e){var r=e.item,a=e.itemInputValue,c=e.itemUrl,l=e.source;l.onActive(qe({event:t,item:r,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(r.openOnFocus||Boolean(o.getState().query))?Ce(qe({event:t,props:r,query:o.getState().query,refresh:n,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:r.defaultActiveItemId}),c(),setTimeout(a,0)})):(o.dispatch(t.key,{}),c(),a())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(r.debug||o.pendingRequests.cancelAll());t.preventDefault();var l=ge(o.getState()),u=l.item,s=l.itemInputValue,f=l.itemUrl,m=l.source;if(t.metaKey||t.ctrlKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewTab({itemUrl:f,item:u,state:o.getState()}));else if(t.shiftKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewWindow({itemUrl:f,item:u,state:o.getState()}));else if(t.altKey);else{if(void 0!==f)return m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),void r.navigator.navigate({itemUrl:f,item:u,state:o.getState()});Ce(qe({event:t,nextState:{isOpen:!1},props:r,query:s,refresh:n,store:o},i)).then((function(){m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i))}))}}}(We({event:e,props:t,refresh:r,store:n},o))},onFocus:c,onBlur:a,onClick:function(r){e.inputElement!==t.environment.document.activeElement||n.getState().isOpen||c(r)}},f)},getPanelProps:function(e){return We({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){n.dispatch("mouseleave",null)}},e)},getListProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,$e);return We({role:"listbox","aria-labelledby":"".concat(i(t.id,n),"-label"),id:"".concat(i(t.id,n),"-list")},o)},getItemProps:function(e){var a=e.item,c=e.source,l=e.sourceIndex,u=Ze(e,Je);return We({id:"".concat(i(t.id,l),"-item-").concat(a.__autocomplete_id),role:"option","aria-selected":n.getState().activeItemId===a.__autocomplete_id,onMouseMove:function(e){if(a.__autocomplete_id!==n.getState().activeItemId){n.dispatch("mousemove",a.__autocomplete_id);var t=ge(n.getState());if(null!==n.getState().activeItemId&&t){var i=t.item,c=t.itemInputValue,l=t.itemUrl,u=t.source;u.onActive(We({event:e,item:i,itemInputValue:c,itemUrl:l,refresh:r,source:u,state:n.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var i=c.getItemInputValue({item:a,state:n.getState()}),l=c.getItemUrl({item:a,state:n.getState()});(l?Promise.resolve():Ce(We({event:e,nextState:{isOpen:!1},props:t,query:i,refresh:r,store:n},o))).then((function(){c.onSelect(We({event:e,item:a,itemInputValue:i,itemUrl:l,refresh:r,source:c,state:n.getState()},o))}))}},u)}}}var Xe=[{segment:"autocomplete-core",version:"1.9.3"}];function Ye(e){return Ye="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Ye(e)}function et(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function tt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?et(Object(r),!0).forEach((function(t){rt(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):et(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function rt(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==Ye(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==Ye(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Ye(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function nt(e){var t,r,n,o,i=e.plugins,a=e.options,c=null===(t=((null===(r=a.__autocomplete_metadata)||void 0===r?void 0:r.userAgents)||[])[0])||void 0===t?void 0:t.segment,l=c?rt({},c,Object.keys((null===(n=a.__autocomplete_metadata)||void 0===n?void 0:n.options)||{})):{};return{plugins:i.map((function(e){return{name:e.name,options:Object.keys(e.__autocomplete_pluginOptions||[])}})),options:tt({"autocomplete-core":Object.keys(a)},l),ua:Xe.concat((null===(o=a.__autocomplete_metadata)||void 0===o?void 0:o.userAgents)||[])}}function ot(e){var t,r=e.state;return!1===r.isOpen||null===r.activeItemId?null:(null===(t=ge(r))||void 0===t?void 0:t.itemInputValue)||null}function it(e,t,r,n){if(!r)return null;if(e<0&&(null===t||null!==n&&0===t))return r+e;var o=(null===t?-1:t)+e;return o<=-1||o>=r?null===n?null:0:o}function at(e){return at="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},at(e)}function ct(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function lt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?ct(Object(r),!0).forEach((function(t){ut(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ct(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function ut(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==at(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==at(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===at(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var st=function(e,t){switch(t.type){case"setActiveItemId":case"mousemove":return lt(lt({},e),{},{activeItemId:t.payload});case"setQuery":return lt(lt({},e),{},{query:t.payload,completion:null});case"setCollections":return lt(lt({},e),{},{collections:t.payload});case"setIsOpen":return lt(lt({},e),{},{isOpen:t.payload});case"setStatus":return lt(lt({},e),{},{status:t.payload});case"setContext":return lt(lt({},e),{},{context:lt(lt({},e.context),t.payload)});case"ArrowDown":var r=lt(lt({},e),{},{activeItemId:t.payload.hasOwnProperty("nextActiveItemId")?t.payload.nextActiveItemId:it(1,e.activeItemId,B(e),t.props.defaultActiveItemId)});return lt(lt({},r),{},{completion:ot({state:r})});case"ArrowUp":var n=lt(lt({},e),{},{activeItemId:it(-1,e.activeItemId,B(e),t.props.defaultActiveItemId)});return lt(lt({},n),{},{completion:ot({state:n})});case"Escape":return e.isOpen?lt(lt({},e),{},{activeItemId:null,isOpen:!1,completion:null}):lt(lt({},e),{},{activeItemId:null,query:"",status:"idle",collections:[]});case"submit":return lt(lt({},e),{},{activeItemId:null,isOpen:!1,status:"idle"});case"reset":return lt(lt({},e),{},{activeItemId:!0===t.props.openOnFocus?t.props.defaultActiveItemId:null,status:"idle",query:""});case"focus":return lt(lt({},e),{},{activeItemId:t.props.defaultActiveItemId,isOpen:(t.props.openOnFocus||Boolean(e.query))&&t.props.shouldPanelOpen({state:e})});case"blur":return t.props.debug?e:lt(lt({},e),{},{isOpen:!1,activeItemId:null});case"mouseleave":return lt(lt({},e),{},{activeItemId:t.props.defaultActiveItemId});default:return"The reducer action ".concat(JSON.stringify(t.type)," is not supported."),e}};function ft(e){return ft="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},ft(e)}function mt(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function pt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?mt(Object(r),!0).forEach((function(t){vt(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):mt(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function vt(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==ft(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==ft(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===ft(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function dt(e){var t=[],r=ee(e,t),n=R(st,r,(function(e){var t=e.prevState,n=e.state;r.onStateChange(pt({prevState:t,state:n,refresh:a,navigator:r.navigator},o))})),o=function(e){var t=e.store;return{setActiveItemId:function(e){t.dispatch("setActiveItemId",e)},setQuery:function(e){t.dispatch("setQuery",e)},setCollections:function(e){var r=0,n=e.map((function(e){return F(F({},e),{},{items:L(e.items).map((function(e){return F(F({},e),{},{__autocomplete_id:r++})}))})}));t.dispatch("setCollections",n)},setIsOpen:function(e){t.dispatch("setIsOpen",e)},setStatus:function(e){t.dispatch("setStatus",e)},setContext:function(e){t.dispatch("setContext",e)}}}({store:n}),i=Ge(pt({props:r,refresh:a,store:n,navigator:r.navigator},o));function a(){return Ce(pt({event:new Event("input"),nextState:{isOpen:n.getState().isOpen},props:r,navigator:r.navigator,query:n.getState().query,refresh:a,store:n},o))}if(e.insights&&!r.plugins.some((function(e){return"aa.algoliaInsightsPlugin"===e.name}))){var c="boolean"==typeof e.insights?{}:e.insights;r.plugins.push(_(c))}return r.plugins.forEach((function(e){var n;return null===(n=e.subscribe)||void 0===n?void 0:n.call(e,pt(pt({},o),{},{navigator:r.navigator,refresh:a,onSelect:function(e){t.push({onSelect:e})},onActive:function(e){t.push({onActive:e})},onResolve:function(e){t.push({onResolve:e})}}))})),function(e){var t,r,n=e.metadata,o=e.environment;if(null===(t=o.navigator)||void 0===t||null===(r=t.userAgent)||void 0===r?void 0:r.includes("Algolia Crawler")){var i=o.document.createElement("meta"),a=o.document.querySelector("head");i.name="algolia:metadata",setTimeout((function(){i.content=JSON.stringify(n),a.appendChild(i)}),0)}}({metadata:nt({plugins:r.plugins,options:e}),environment:r.environment}),pt(pt({refresh:a,navigator:r.navigator},i),o)}var yt=r(7294),ht=64;function bt(e){var t=e.translations,r=(void 0===t?{}:t).searchByText,n=void 0===r?"Search by":r;return yt.createElement("a",{href:"https://www.algolia.com/ref/docsearch/?utm_source=".concat(window.location.hostname,"&utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch"),target:"_blank",rel:"noopener noreferrer"},yt.createElement("span",{className:"DocSearch-Label"},n),yt.createElement("svg",{width:"77",height:"19","aria-label":"Algolia",role:"img",id:"Layer_1",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 2196.2 500"},yt.createElement("defs",null,yt.createElement("style",null,".cls-1,.cls-2{fill:#003dff;}.cls-2{fill-rule:evenodd;}")),yt.createElement("path",{className:"cls-2",d:"M1070.38,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"}),yt.createElement("rect",{className:"cls-1",x:"1845.88",y:"104.73",width:"62.58",height:"277.9",rx:"5.9",ry:"5.9"}),yt.createElement("path",{className:"cls-2",d:"M1851.78,71.38h50.77c3.26,0,5.9-2.64,5.9-5.9V5.9c0-3.62-3.24-6.39-6.82-5.83l-50.77,7.95c-2.87,.45-4.99,2.92-4.99,5.83v51.62c0,3.26,2.64,5.9,5.9,5.9Z"}),yt.createElement("path",{className:"cls-2",d:"M1764.03,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"}),yt.createElement("path",{className:"cls-2",d:"M1631.95,142.72c-11.14-12.25-24.83-21.65-40.78-28.31-15.92-6.53-33.26-9.85-52.07-9.85-18.78,0-36.15,3.17-51.92,9.85-15.59,6.66-29.29,16.05-40.76,28.31-11.47,12.23-20.38,26.87-26.76,44.03-6.38,17.17-9.24,37.37-9.24,58.36,0,20.99,3.19,36.87,9.55,54.21,6.38,17.32,15.14,32.11,26.45,44.36,11.29,12.23,24.83,21.62,40.6,28.46,15.77,6.83,40.12,10.33,52.4,10.48,12.25,0,36.78-3.82,52.7-10.48,15.92-6.68,29.46-16.23,40.78-28.46,11.29-12.25,20.05-27.04,26.25-44.36,6.22-17.34,9.24-33.22,9.24-54.21,0-20.99-3.34-41.19-10.03-58.36-6.38-17.17-15.14-31.8-26.43-44.03Zm-44.43,163.75c-11.47,15.75-27.56,23.7-48.09,23.7-20.55,0-36.63-7.8-48.1-23.7-11.47-15.75-17.21-34.01-17.21-61.2,0-26.89,5.59-49.14,17.06-64.87,11.45-15.75,27.54-23.52,48.07-23.52,20.55,0,36.63,7.78,48.09,23.52,11.47,15.57,17.36,37.98,17.36,64.87,0,27.19-5.72,45.3-17.19,61.2Z"}),yt.createElement("path",{className:"cls-2",d:"M894.42,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"}),yt.createElement("path",{className:"cls-2",d:"M2133.97,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"}),yt.createElement("path",{className:"cls-2",d:"M1314.05,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-11.79,18.34-19.6,39.64-22.11,62.59-.58,5.3-.88,10.68-.88,16.14s.31,11.15,.93,16.59c4.28,38.09,23.14,71.61,50.66,94.52,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47h0c17.99,0,34.61-5.93,48.16-15.97,16.29-11.58,28.88-28.54,34.48-47.75v50.26h-.11v11.08c0,21.84-5.71,38.27-17.34,49.36-11.61,11.08-31.04,16.63-58.25,16.63-11.12,0-28.79-.59-46.6-2.41-2.83-.29-5.46,1.5-6.27,4.22l-12.78,43.11c-1.02,3.46,1.27,7.02,4.83,7.53,21.52,3.08,42.52,4.68,54.65,4.68,48.91,0,85.16-10.75,108.89-32.21,21.48-19.41,33.15-48.89,35.2-88.52V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,64.1s.65,139.13,0,143.36c-12.08,9.77-27.11,13.59-43.49,14.7-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-1.32,0-2.63-.03-3.94-.1-40.41-2.11-74.52-37.26-74.52-79.38,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33Z"}),yt.createElement("path",{className:"cls-1",d:"M249.83,0C113.3,0,2,110.09,.03,246.16c-2,138.19,110.12,252.7,248.33,253.5,42.68,.25,83.79-10.19,120.3-30.03,3.56-1.93,4.11-6.83,1.08-9.51l-23.38-20.72c-4.75-4.21-11.51-5.4-17.36-2.92-25.48,10.84-53.17,16.38-81.71,16.03-111.68-1.37-201.91-94.29-200.13-205.96,1.76-110.26,92-199.41,202.67-199.41h202.69V407.41l-115-102.18c-3.72-3.31-9.42-2.66-12.42,1.31-18.46,24.44-48.53,39.64-81.93,37.34-46.33-3.2-83.87-40.5-87.34-86.81-4.15-55.24,39.63-101.52,94-101.52,49.18,0,89.68,37.85,93.91,85.95,.38,4.28,2.31,8.27,5.52,11.12l29.95,26.55c3.4,3.01,8.79,1.17,9.63-3.3,2.16-11.55,2.92-23.58,2.07-35.92-4.82-70.34-61.8-126.93-132.17-131.26-80.68-4.97-148.13,58.14-150.27,137.25-2.09,77.1,61.08,143.56,138.19,145.26,32.19,.71,62.03-9.41,86.14-26.95l150.26,133.2c6.44,5.71,16.61,1.14,16.61-7.47V9.48C499.66,4.25,495.42,0,490.18,0H249.83Z"})))}function gt(e){return yt.createElement("svg",{width:"15",height:"15","aria-label":e.ariaLabel,role:"img"},yt.createElement("g",{fill:"none",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"1.2"},e.children))}function Ot(e){var t=e.translations,r=void 0===t?{}:t,n=r.selectText,o=void 0===n?"to select":n,i=r.selectKeyAriaLabel,a=void 0===i?"Enter key":i,c=r.navigateText,l=void 0===c?"to navigate":c,u=r.navigateUpKeyAriaLabel,s=void 0===u?"Arrow up":u,f=r.navigateDownKeyAriaLabel,m=void 0===f?"Arrow down":f,p=r.closeText,v=void 0===p?"to close":p,d=r.closeKeyAriaLabel,y=void 0===d?"Escape key":d,h=r.searchByText,b=void 0===h?"Search by":h;return yt.createElement(yt.Fragment,null,yt.createElement("div",{className:"DocSearch-Logo"},yt.createElement(bt,{translations:{searchByText:b}})),yt.createElement("ul",{className:"DocSearch-Commands"},yt.createElement("li",null,yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:a},yt.createElement("path",{d:"M12 3.53088v3c0 1-1 2-2 2H4M7 11.53088l-3-3 3-3"}))),yt.createElement("span",{className:"DocSearch-Label"},o)),yt.createElement("li",null,yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:m},yt.createElement("path",{d:"M7.5 3.5v8M10.5 8.5l-3 3-3-3"}))),yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:s},yt.createElement("path",{d:"M7.5 11.5v-8M10.5 6.5l-3-3-3 3"}))),yt.createElement("span",{className:"DocSearch-Label"},l)),yt.createElement("li",null,yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:y},yt.createElement("path",{d:"M13.6167 8.936c-.1065.3583-.6883.962-1.4875.962-.7993 0-1.653-.9165-1.653-2.1258v-.5678c0-1.2548.7896-2.1016 1.653-2.1016.8634 0 1.3601.4778 1.4875 1.0724M9 6c-.1352-.4735-.7506-.9219-1.46-.8972-.7092.0246-1.344.57-1.344 1.2166s.4198.8812 1.3445.9805C8.465 7.3992 8.968 7.9337 9 8.5c.032.5663-.454 1.398-1.4595 1.398C6.6593 9.898 6 9 5.963 8.4851m-1.4748.5368c-.2635.5941-.8099.876-1.5443.876s-1.7073-.6248-1.7073-2.204v-.4603c0-1.0416.721-2.131 1.7073-2.131.9864 0 1.6425 1.031 1.5443 2.2492h-2.956"}))),yt.createElement("span",{className:"DocSearch-Label"},v))))}function St(e){var t=e.hit,r=e.children;return yt.createElement("a",{href:t.url},r)}function jt(){return yt.createElement("svg",{width:"40",height:"40",viewBox:"0 0 20 20",fill:"none",fillRule:"evenodd",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M19 4.8a16 16 0 00-2-1.2m-3.3-1.2A16 16 0 001.1 4.7M16.7 8a12 12 0 00-2.8-1.4M10 6a12 12 0 00-6.7 2M12.3 14.7a4 4 0 00-4.5 0M14.5 11.4A8 8 0 0010 10M3 16L18 2M10 18h0"}))}function wt(e){var t=e.translations,r=void 0===t?{}:t,n=r.titleText,o=void 0===n?"Unable to fetch results":n,i=r.helpText,a=void 0===i?"You might want to check your network connection.":i;return yt.createElement("div",{className:"DocSearch-ErrorScreen"},yt.createElement("div",{className:"DocSearch-Screen-Icon"},yt.createElement(jt,null)),yt.createElement("p",{className:"DocSearch-Title"},o),yt.createElement("p",{className:"DocSearch-Help"},a))}function Et(){return yt.createElement("svg",{width:"40",height:"40",viewBox:"0 0 20 20",fill:"none",fillRule:"evenodd",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M15.5 4.8c2 3 1.7 7-1 9.7h0l4.3 4.3-4.3-4.3a7.8 7.8 0 01-9.8 1m-2.2-2.2A7.8 7.8 0 0113.2 2.4M2 18L18 2"}))}var Pt=["translations"];function It(e){return function(e){if(Array.isArray(e))return Dt(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Dt(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Dt(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Dt(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function At(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function kt(e){var t=e.translations,r=void 0===t?{}:t,n=At(e,Pt),o=r.noResultsText,i=void 0===o?"No results for":o,a=r.suggestedQueryText,c=void 0===a?"Try searching for":a,l=r.reportMissingResultsText,u=void 0===l?"Believe this query should return results?":l,s=r.reportMissingResultsLinkText,f=void 0===s?"Let us know.":s,m=n.state.context.searchSuggestions;return yt.createElement("div",{className:"DocSearch-NoResults"},yt.createElement("div",{className:"DocSearch-Screen-Icon"},yt.createElement(Et,null)),yt.createElement("p",{className:"DocSearch-Title"},i,' "',yt.createElement("strong",null,n.state.query),'"'),m&&m.length>0&&yt.createElement("div",{className:"DocSearch-NoResults-Prefill-List"},yt.createElement("p",{className:"DocSearch-Help"},c,":"),yt.createElement("ul",null,m.slice(0,3).reduce((function(e,t){return[].concat(It(e),[yt.createElement("li",{key:t},yt.createElement("button",{className:"DocSearch-Prefill",key:t,type:"button",onClick:function(){n.setQuery(t.toLowerCase()+" "),n.refresh(),n.inputRef.current.focus()}},t))])}),[]))),n.getMissingResultsUrl&&yt.createElement("p",{className:"DocSearch-Help"},"".concat(u," "),yt.createElement("a",{href:n.getMissingResultsUrl({query:n.state.query}),target:"_blank",rel:"noopener noreferrer"},f)))}var xt=function(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 6v12c0 .52-.2 1-1 1H4c-.7 0-1-.33-1-1V2c0-.55.42-1 1-1h8l5 5zM14 8h-3.13c-.51 0-.87-.34-.87-.87V4",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))};function Ct(e){switch(e.type){case"lvl1":return yt.createElement(xt,null);case"content":return yt.createElement(Nt,null);default:return yt.createElement(_t,null)}}function _t(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M13 13h4-4V8H7v5h6v4-4H7V8H3h4V3v5h6V3v5h4-4v5zm-6 0v4-4H3h4z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}function Nt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 5H3h14zm0 5H3h14zm0 5H3h14z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function Tt(){return yt.createElement("svg",{className:"DocSearch-Hit-Select-Icon",width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M18 3v4c0 2-2 4-4 4H2"}),yt.createElement("path",{d:"M8 17l-6-6 6-6"})))}var qt=["hit","attribute","tagName"];function Rt(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function Lt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?Rt(Object(r),!0).forEach((function(t){Mt(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):Rt(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Mt(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Ht(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ft(e,t){return t.split(".").reduce((function(e,t){return null!=e&&e[t]?e[t]:null}),e)}function Ut(e){var t=e.hit,r=e.attribute,n=e.tagName,o=void 0===n?"span":n,i=Ht(e,qt);return(0,yt.createElement)(o,Lt(Lt({},i),{},{dangerouslySetInnerHTML:{__html:Ft(t,"_snippetResult.".concat(r,".value"))||Ft(t,r)}}))}function Bt(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==r)return;var n,o,i=[],a=!0,c=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(l){c=!0,o=l}finally{try{a||null==r.return||r.return()}finally{if(c)throw o}}return i}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return Vt(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Vt(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Vt(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function Kt(){return Kt=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Kt.apply(this,arguments)}function $t(e){return e.collection&&0!==e.collection.items.length?yt.createElement("section",{className:"DocSearch-Hits"},yt.createElement("div",{className:"DocSearch-Hit-source"},e.title),yt.createElement("ul",e.getListProps(),e.collection.items.map((function(t,r){return yt.createElement(Jt,Kt({key:[e.title,t.objectID].join(":"),item:t,index:r},e))})))):null}function Jt(e){var t=e.item,r=e.index,n=e.renderIcon,o=e.renderAction,i=e.getItemProps,a=e.onItemClick,c=e.collection,l=e.hitComponent,u=Bt(yt.useState(!1),2),s=u[0],f=u[1],m=Bt(yt.useState(!1),2),p=m[0],v=m[1],d=yt.useRef(null),y=l;return yt.createElement("li",Kt({className:["DocSearch-Hit",t.__docsearch_parent&&"DocSearch-Hit--Child",s&&"DocSearch-Hit--deleting",p&&"DocSearch-Hit--favoriting"].filter(Boolean).join(" "),onTransitionEnd:function(){d.current&&d.current()}},i({item:t,source:c.source,onClick:function(e){a(t,e)}})),yt.createElement(y,{hit:t},yt.createElement("div",{className:"DocSearch-Hit-Container"},n({item:t,index:r}),t.hierarchy[t.type]&&"lvl1"===t.type&&yt.createElement("div",{className:"DocSearch-Hit-content-wrapper"},yt.createElement(Ut,{className:"DocSearch-Hit-title",hit:t,attribute:"hierarchy.lvl1"}),t.content&&yt.createElement(Ut,{className:"DocSearch-Hit-path",hit:t,attribute:"content"})),t.hierarchy[t.type]&&("lvl2"===t.type||"lvl3"===t.type||"lvl4"===t.type||"lvl5"===t.type||"lvl6"===t.type)&&yt.createElement("div",{className:"DocSearch-Hit-content-wrapper"},yt.createElement(Ut,{className:"DocSearch-Hit-title",hit:t,attribute:"hierarchy.".concat(t.type)}),yt.createElement(Ut,{className:"DocSearch-Hit-path",hit:t,attribute:"hierarchy.lvl1"})),"content"===t.type&&yt.createElement("div",{className:"DocSearch-Hit-content-wrapper"},yt.createElement(Ut,{className:"DocSearch-Hit-title",hit:t,attribute:"content"}),yt.createElement(Ut,{className:"DocSearch-Hit-path",hit:t,attribute:"hierarchy.lvl1"})),o({item:t,runDeleteTransition:function(e){f(!0),d.current=e},runFavoriteTransition:function(e){v(!0),d.current=e}}))))}var zt=/(<mark>|<\/mark>)/g,Wt=RegExp(zt.source);function Qt(e){var t,r,n=e;if(!n.__docsearch_parent&&!e._highlightResult)return e.hierarchy.lvl0;var o=((n.__docsearch_parent?null===(t=n.__docsearch_parent)||void 0===t||null===(t=t._highlightResult)||void 0===t||null===(t=t.hierarchy)||void 0===t?void 0:t.lvl0:null===(r=e._highlightResult)||void 0===r||null===(r=r.hierarchy)||void 0===r?void 0:r.lvl0)||{}).value;return o&&Wt.test(o)?o.replace(zt,""):o}function Zt(){return Zt=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Zt.apply(this,arguments)}function Gt(e){return yt.createElement("div",{className:"DocSearch-Dropdown-Container"},e.state.collections.map((function(t){if(0===t.items.length)return null;var r=Qt(t.items[0]);return yt.createElement($t,Zt({},e,{key:t.source.sourceId,title:r,collection:t,renderIcon:function(e){var r,n=e.item,o=e.index;return yt.createElement(yt.Fragment,null,n.__docsearch_parent&&yt.createElement("svg",{className:"DocSearch-Hit-Tree",viewBox:"0 0 24 54"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},n.__docsearch_parent!==(null===(r=t.items[o+1])||void 0===r?void 0:r.__docsearch_parent)?yt.createElement("path",{d:"M8 6v21M20 27H8.3"}):yt.createElement("path",{d:"M8 6v42M20 27H8.3"}))),yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Ct,{type:n.type})))},renderAction:function(){return yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement(Tt,null))}}))})),e.resultsFooterComponent&&yt.createElement("section",{className:"DocSearch-HitsFooter"},yt.createElement(e.resultsFooterComponent,{state:e.state})))}function Xt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M3.18 6.6a8.23 8.23 0 1112.93 9.94h0a8.23 8.23 0 01-11.63 0"}),yt.createElement("path",{d:"M6.44 7.25H2.55V3.36M10.45 6v5.6M10.45 11.6L13 13"})))}function Yt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M10 14.2L5 17l1-5.6-4-4 5.5-.7 2.5-5 2.5 5 5.6.8-4 4 .9 5.5z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function er(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M10 10l5.09-5.09L10 10l5.09 5.09L10 10zm0 0L4.91 4.91 10 10l-5.09 5.09L10 10z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}var tr=["translations"];function rr(){return rr=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},rr.apply(this,arguments)}function nr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function or(e){var t=e.translations,r=void 0===t?{}:t,n=nr(e,tr),o=r.recentSearchesTitle,i=void 0===o?"Recent":o,a=r.noRecentSearchesText,c=void 0===a?"No recent searches":a,l=r.saveRecentSearchButtonTitle,u=void 0===l?"Save this search":l,s=r.removeRecentSearchButtonTitle,f=void 0===s?"Remove this search from history":s,m=r.favoriteSearchesTitle,p=void 0===m?"Favorite":m,v=r.removeFavoriteSearchButtonTitle,d=void 0===v?"Remove this search from favorites":v;return"idle"===n.state.status&&!1===n.hasCollections?n.disableUserPersonalization?null:yt.createElement("div",{className:"DocSearch-StartScreen"},yt.createElement("p",{className:"DocSearch-Help"},c)):!1===n.hasCollections?null:yt.createElement("div",{className:"DocSearch-Dropdown-Container"},yt.createElement($t,rr({},n,{title:i,collection:n.state.collections[0],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Xt,null))},renderAction:function(e){var t=e.item,r=e.runFavoriteTransition,o=e.runDeleteTransition;return yt.createElement(yt.Fragment,null,yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:u,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.add(t),n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(Yt,null))),yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:f,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),o((function(){n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(er,null))))}})),yt.createElement($t,rr({},n,{title:p,collection:n.state.collections[1],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Yt,null))},renderAction:function(e){var t=e.item,r=e.runDeleteTransition;return yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:d,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.remove(t),n.refresh()}))}},yt.createElement(er,null)))}})))}var ir=["translations"];function ar(){return ar=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},ar.apply(this,arguments)}function cr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var lr=yt.memo((function(e){var t=e.translations,r=void 0===t?{}:t,n=cr(e,ir);if("error"===n.state.status)return yt.createElement(wt,{translations:null==r?void 0:r.errorScreen});var o=n.state.collections.some((function(e){return e.items.length>0}));return n.state.query?!1===o?yt.createElement(kt,ar({},n,{translations:null==r?void 0:r.noResultsScreen})):yt.createElement(Gt,n):yt.createElement(or,ar({},n,{hasCollections:o,translations:null==r?void 0:r.startScreen}))}),(function(e,t){return"loading"===t.state.status||"stalled"===t.state.status}));function ur(){return yt.createElement("svg",{viewBox:"0 0 38 38",stroke:"currentColor",strokeOpacity:".5"},yt.createElement("g",{fill:"none",fillRule:"evenodd"},yt.createElement("g",{transform:"translate(1 1)",strokeWidth:"2"},yt.createElement("circle",{strokeOpacity:".3",cx:"18",cy:"18",r:"18"}),yt.createElement("path",{d:"M36 18c0-9.94-8.06-18-18-18"},yt.createElement("animateTransform",{attributeName:"transform",type:"rotate",from:"0 18 18",to:"360 18 18",dur:"1s",repeatCount:"indefinite"})))))}var sr=r(830),fr=["translations"];function mr(){return mr=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},mr.apply(this,arguments)}function pr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function vr(e){var t=e.translations,r=void 0===t?{}:t,n=pr(e,fr),o=r.resetButtonTitle,i=void 0===o?"Clear the query":o,a=r.resetButtonAriaLabel,c=void 0===a?"Clear the query":a,l=r.cancelButtonText,u=void 0===l?"Cancel":l,s=r.cancelButtonAriaLabel,f=void 0===s?"Cancel":s,m=n.getFormProps({inputElement:n.inputRef.current}).onReset;return yt.useEffect((function(){n.autoFocus&&n.inputRef.current&&n.inputRef.current.focus()}),[n.autoFocus,n.inputRef]),yt.useEffect((function(){n.isFromSelection&&n.inputRef.current&&n.inputRef.current.select()}),[n.isFromSelection,n.inputRef]),yt.createElement(yt.Fragment,null,yt.createElement("form",{className:"DocSearch-Form",onSubmit:function(e){e.preventDefault()},onReset:m},yt.createElement("label",mr({className:"DocSearch-MagnifierLabel"},n.getLabelProps()),yt.createElement(sr.W,null)),yt.createElement("div",{className:"DocSearch-LoadingIndicator"},yt.createElement(ur,null)),yt.createElement("input",mr({className:"DocSearch-Input",ref:n.inputRef},n.getInputProps({inputElement:n.inputRef.current,autoFocus:n.autoFocus,maxLength:ht}))),yt.createElement("button",{type:"reset",title:i,className:"DocSearch-Reset","aria-label":c,hidden:!n.state.query},yt.createElement(er,null))),yt.createElement("button",{className:"DocSearch-Cancel",type:"reset","aria-label":f,onClick:n.onClose},u))}var dr=["_highlightResult","_snippetResult"];function yr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function hr(e){return!1===function(){var e="__TEST_KEY__";try{return localStorage.setItem(e,""),localStorage.removeItem(e),!0}catch(t){return!1}}()?{setItem:function(){},getItem:function(){return[]}}:{setItem:function(t){return window.localStorage.setItem(e,JSON.stringify(t))},getItem:function(){var t=window.localStorage.getItem(e);return t?JSON.parse(t):[]}}}function br(e){var t=e.key,r=e.limit,n=void 0===r?5:r,o=hr(t),i=o.getItem().slice(0,n);return{add:function(e){var t=e,r=(t._highlightResult,t._snippetResult,yr(t,dr)),a=i.findIndex((function(e){return e.objectID===r.objectID}));a>-1&&i.splice(a,1),i.unshift(r),i=i.slice(0,n),o.setItem(i)},remove:function(e){i=i.filter((function(t){return t.objectID!==e.objectID})),o.setItem(i)},getAll:function(){return i}}}function gr(e){const t=`algoliasearch-client-js-${e.key}`;let r;const n=()=>(void 0===r&&(r=e.localStorage||window.localStorage),r),o=()=>JSON.parse(n().getItem(t)||"{}"),i=e=>{n().setItem(t,JSON.stringify(e))};return{get:(t,r,n={miss:()=>Promise.resolve()})=>Promise.resolve().then((()=>{(()=>{const t=e.timeToLive?1e3*e.timeToLive:null,r=o(),n=Object.fromEntries(Object.entries(r).filter((([,e])=>void 0!==e.timestamp)));if(i(n),!t)return;const a=Object.fromEntries(Object.entries(n).filter((([,e])=>{const r=(new Date).getTime();return!(e.timestamp+t<r)})));i(a)})();const r=JSON.stringify(t);return o()[r]})).then((e=>Promise.all([e?e.value:r(),void 0!==e]))).then((([e,t])=>Promise.all([e,t||n.miss(e)]))).then((([e])=>e)),set:(e,r)=>Promise.resolve().then((()=>{const i=o();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:r},n().setItem(t,JSON.stringify(i)),r})),delete:e=>Promise.resolve().then((()=>{const r=o();delete r[JSON.stringify(e)],n().setItem(t,JSON.stringify(r))})),clear:()=>Promise.resolve().then((()=>{n().removeItem(t)}))}}function Or(e){const t=[...e.caches],r=t.shift();return void 0===r?{get:(e,t,r={miss:()=>Promise.resolve()})=>t().then((e=>Promise.all([e,r.miss(e)]))).then((([e])=>e)),set:(e,t)=>Promise.resolve(t),delete:e=>Promise.resolve(),clear:()=>Promise.resolve()}:{get:(e,n,o={miss:()=>Promise.resolve()})=>r.get(e,n,o).catch((()=>Or({caches:t}).get(e,n,o))),set:(e,n)=>r.set(e,n).catch((()=>Or({caches:t}).set(e,n))),delete:e=>r.delete(e).catch((()=>Or({caches:t}).delete(e))),clear:()=>r.clear().catch((()=>Or({caches:t}).clear()))}}function Sr(e={serializable:!0}){let t={};return{get(r,n,o={miss:()=>Promise.resolve()}){const i=JSON.stringify(r);if(i in t)return Promise.resolve(e.serializable?JSON.parse(t[i]):t[i]);const a=n(),c=o&&o.miss||(()=>Promise.resolve());return a.then((e=>c(e))).then((()=>a))},set:(r,n)=>(t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)),delete:e=>(delete t[JSON.stringify(e)],Promise.resolve()),clear:()=>(t={},Promise.resolve())}}function jr(e){let t=e.length-1;for(;t>0;t--){const r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function wr(e,t){return t?(Object.keys(t).forEach((r=>{e[r]=t[r](e)})),e):e}function Er(e,...t){let r=0;return e.replace(/%s/g,(()=>encodeURIComponent(t[r++])))}const Pr="4.20.0",Ir={WithinQueryParameters:0,WithinHeaders:1};function Dr(e,t){const r=e||{},n=r.data||{};return Object.keys(r).forEach((e=>{-1===["timeout","headers","queryParameters","data","cacheable"].indexOf(e)&&(n[e]=r[e])})),{data:Object.entries(n).length>0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}const Ar={Read:1,Write:2,Any:3},kr={Up:1,Down:2,Timeouted:3},xr=12e4;function Cr(e,t=kr.Up){return{...e,status:t,lastUpdate:Date.now()}}function _r(e){return"string"==typeof e?{protocol:"https",url:e,accept:Ar.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||Ar.Any}}const Nr={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};function Tr(e,t){return Promise.all(t.map((t=>e.get(t,(()=>Promise.resolve(Cr(t))))))).then((e=>{const r=e.filter((e=>function(e){return e.status===kr.Up||Date.now()-e.lastUpdate>xr}(e))),n=e.filter((e=>function(e){return e.status===kr.Timeouted&&Date.now()-e.lastUpdate<=xr}(e))),o=[...r,...n];return{getTimeout:(e,t)=>(0===n.length&&0===e?1:n.length+3+e)*t,statelessHosts:o.length>0?o.map((e=>_r(e))):t}}))}const qr=(e,t)=>(e=>{const t=e.status;return e.isTimedOut||(({isTimedOut:e,status:t})=>!e&&0==~~t)(e)||2!=~~(t/100)&&4!=~~(t/100)})(e)?t.onRetry(e):(({status:e})=>2==~~(e/100))(e)?t.onSuccess(e):t.onFail(e);function Rr(e,t,r,n){const o=[],i=function(e,t){if(e.method===Nr.Get||void 0===e.data&&void 0===t.data)return;const r=Array.isArray(e.data)?e.data:{...e.data,...t.data};return JSON.stringify(r)}(r,n),a=function(e,t){const r={...e.headers,...t.headers},n={};return Object.keys(r).forEach((e=>{const t=r[e];n[e.toLowerCase()]=t})),n}(e,n),c=r.method,l=r.method!==Nr.Get?{}:{...r.data,...n.data},u={"x-algolia-agent":e.userAgent.value,...e.queryParameters,...l,...n.queryParameters};let s=0;const f=(t,l)=>{const m=t.pop();if(void 0===m)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:Fr(o)};const p={data:i,headers:a,method:c,url:Mr(m,r.path,u),connectTimeout:l(s,e.timeouts.connect),responseTimeout:l(s,n.timeout)},v=e=>{const r={request:p,response:e,host:m,triesLeft:t.length};return o.push(r),r},d={onSuccess:e=>function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e),onRetry(r){const n=v(r);return r.isTimedOut&&s++,Promise.all([e.logger.info("Retryable failure",Ur(n)),e.hostsCache.set(m,Cr(m,r.isTimedOut?kr.Timeouted:kr.Down))]).then((()=>f(t,l)))},onFail(e){throw v(e),function({content:e,status:t},r){let n=e;try{n=JSON.parse(e).message}catch(o){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(n,t,r)}(e,Fr(o))}};return e.requester.send(p).then((e=>qr(e,d)))};return Tr(e.hostsCache,t).then((e=>f([...e.statelessHosts].reverse(),e.getTimeout)))}function Lr(e){const t={value:`Algolia for JavaScript (${e})`,add(e){const r=`; ${e.segment}${void 0!==e.version?` (${e.version})`:""}`;return-1===t.value.indexOf(r)&&(t.value=`${t.value}${r}`),t}};return t}function Mr(e,t,r){const n=Hr(r);let o=`${e.protocol}://${e.url}/${"/"===t.charAt(0)?t.substr(1):t}`;return n.length&&(o+=`?${n}`),o}function Hr(e){return Object.keys(e).map((t=>{return Er("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function Fr(e){return e.map((e=>Ur(e)))}function Ur(e){const t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return{...e,request:{...e.request,headers:{...e.request.headers,...t}}}}const Br=e=>{const t=e.appId,r=function(e,t,r){const n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:()=>e===Ir.WithinHeaders?n:{},queryParameters:()=>e===Ir.WithinQueryParameters?n:{}}}(void 0!==e.authMode?e.authMode:Ir.WithinHeaders,t,e.apiKey),n=function(e){const{hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,hosts:l,queryParameters:u,headers:s}=e,f={hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,headers:s,queryParameters:u,hosts:l.map((e=>_r(e))),read(e,t){const r=Dr(t,f.timeouts.read),n=()=>Rr(f,f.hosts.filter((e=>0!=(e.accept&Ar.Read))),e,r);if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();const o={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(o,(()=>f.requestsCache.get(o,(()=>f.requestsCache.set(o,n()).then((e=>Promise.all([f.requestsCache.delete(o),e])),(e=>Promise.all([f.requestsCache.delete(o),Promise.reject(e)]))).then((([e,t])=>t))))),{miss:e=>f.responsesCache.set(o,e)})},write:(e,t)=>Rr(f,f.hosts.filter((e=>0!=(e.accept&Ar.Write))),e,Dr(t,f.timeouts.write))};return f}({hosts:[{url:`${t}-dsn.algolia.net`,accept:Ar.Read},{url:`${t}.algolia.net`,accept:Ar.Write}].concat(jr([{url:`${t}-1.algolianet.com`},{url:`${t}-2.algolianet.com`},{url:`${t}-3.algolianet.com`}])),...e,headers:{...r.headers(),"content-type":"application/x-www-form-urlencoded",...e.headers},queryParameters:{...r.queryParameters(),...e.queryParameters}}),o={transporter:n,appId:t,addAlgoliaAgent(e,t){n.userAgent.add({segment:e,version:t})},clearCache:()=>Promise.all([n.requestsCache.clear(),n.responsesCache.clear()]).then((()=>{}))};return wr(o,e.methods)},Vr=e=>(t,r)=>t.method===Nr.Get?e.transporter.read(t,r):e.transporter.write(t,r),Kr=e=>(t,r={})=>wr({transporter:e.transporter,appId:e.appId,indexName:t},r.methods),$r=e=>(t,r)=>{const n=t.map((e=>({...e,params:Hr(e.params||{})})));return e.transporter.read({method:Nr.Post,path:"1/indexes/*/queries",data:{requests:n},cacheable:!0},r)},Jr=e=>(t,r)=>Promise.all(t.map((t=>{const{facetName:n,facetQuery:o,...i}=t.params;return Kr(e)(t.indexName,{methods:{searchForFacetValues:Qr}}).searchForFacetValues(n,o,{...r,...i})}))),zr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n),Wr=e=>(t,r)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r),Qr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n),Zr={Debug:1,Info:2,Error:3};function Gr(e,t,r){const n={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:e=>new Promise((t=>{const r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((t=>r.setRequestHeader(t,e.headers[t])));const n=(e,n)=>setTimeout((()=>{r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e),o=n(e.connectTimeout,"Connection timeout");let i;r.onreadystatechange=()=>{r.readyState>r.OPENED&&void 0===i&&(clearTimeout(o),i=n(e.responseTimeout,"Socket timeout"))},r.onerror=()=>{0===r.status&&(clearTimeout(o),clearTimeout(i),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=()=>{clearTimeout(o),clearTimeout(i),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))},logger:(o=Zr.Error,{debug:(e,t)=>(Zr.Debug>=o&&console.debug(e,t),Promise.resolve()),info:(e,t)=>(Zr.Info>=o&&console.info(e,t),Promise.resolve()),error:(e,t)=>(console.error(e,t),Promise.resolve())}),responsesCache:Sr(),requestsCache:Sr({serializable:!1}),hostsCache:Or({caches:[gr({key:`${Pr}-${e}`}),Sr()]}),userAgent:Lr(Pr).add({segment:"Browser",version:"lite"}),authMode:Ir.WithinQueryParameters};var o;return Br({...n,...r,methods:{search:$r,searchForFacetValues:Jr,multipleQueries:$r,multipleSearchForFacetValues:Jr,customRequest:Vr,initIndex:e=>t=>Kr(e)(t,{methods:{search:Wr,searchForFacetValues:Qr,findAnswers:zr}})}})}Gr.version=Pr;const Xr=Gr;var Yr="3.5.2";function en(){}function tn(e){return e}function rn(e){return 1===e.button||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey}function nn(e,t,r){return e.reduce((function(e,n){var o=t(n);return e.hasOwnProperty(o)||(e[o]=[]),e[o].length<(r||5)&&e[o].push(n),e}),{})}var on=["footer","searchBox"];function an(){return an=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},an.apply(this,arguments)}function cn(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function ln(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?cn(Object(r),!0).forEach((function(t){un(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):cn(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function un(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function sn(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==r)return;var n,o,i=[],a=!0,c=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(l){c=!0,o=l}finally{try{a||null==r.return||r.return()}finally{if(c)throw o}}return i}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return fn(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return fn(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function fn(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function mn(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function pn(e){var t=e.appId,r=e.apiKey,n=e.indexName,o=e.placeholder,i=void 0===o?"Search docs":o,a=e.searchParameters,c=e.maxResultsPerGroup,l=e.onClose,u=void 0===l?en:l,s=e.transformItems,f=void 0===s?tn:s,m=e.hitComponent,p=void 0===m?St:m,v=e.resultsFooterComponent,d=void 0===v?function(){return null}:v,y=e.navigator,h=e.initialScrollY,b=void 0===h?0:h,g=e.transformSearchClient,O=void 0===g?tn:g,S=e.disableUserPersonalization,j=void 0!==S&&S,w=e.initialQuery,E=void 0===w?"":w,P=e.translations,I=void 0===P?{}:P,D=e.getMissingResultsUrl,A=e.insights,k=void 0!==A&&A,x=I.footer,C=I.searchBox,_=mn(I,on),N=sn(yt.useState({query:"",collections:[],completion:null,context:{},isOpen:!1,activeItemId:null,status:"idle"}),2),T=N[0],q=N[1],R=yt.useRef(null),L=yt.useRef(null),M=yt.useRef(null),H=yt.useRef(null),F=yt.useRef(null),U=yt.useRef(10),B=yt.useRef("undefined"!=typeof window?window.getSelection().toString().slice(0,ht):"").current,V=yt.useRef(E||B).current,K=function(e,t,r){return yt.useMemo((function(){var n=Xr(e,t);return n.addAlgoliaAgent("docsearch",Yr),!1===/docsearch.js \(.*\)/.test(n.transporter.userAgent.value)&&n.addAlgoliaAgent("docsearch-react",Yr),r(n)}),[e,t,r])}(t,r,O),$=yt.useRef(br({key:"__DOCSEARCH_FAVORITE_SEARCHES__".concat(n),limit:10})).current,J=yt.useRef(br({key:"__DOCSEARCH_RECENT_SEARCHES__".concat(n),limit:0===$.getAll().length?7:4})).current,z=yt.useCallback((function(e){if(!j){var t="content"===e.type?e.__docsearch_parent:e;t&&-1===$.getAll().findIndex((function(e){return e.objectID===t.objectID}))&&J.add(t)}}),[$,J,j]),W=yt.useCallback((function(e){if(T.context.algoliaInsightsPlugin&&e.__autocomplete_id){var t=e,r={eventName:"Item Selected",index:t.__autocomplete_indexName,items:[t],positions:[e.__autocomplete_id],queryID:t.__autocomplete_queryID};T.context.algoliaInsightsPlugin.insights.clickedObjectIDsAfterSearch(r)}}),[T.context.algoliaInsightsPlugin]),Q=yt.useMemo((function(){return dt({id:"docsearch",defaultActiveItemId:0,placeholder:i,openOnFocus:!0,initialState:{query:V,context:{searchSuggestions:[]}},insights:k,navigator:y,onStateChange:function(e){q(e.state)},getSources:function(e){var o=e.query,i=e.state,l=e.setContext,s=e.setStatus;if(!o)return j?[]:[{sourceId:"recentSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),rn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return J.getAll()}},{sourceId:"favoriteSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),rn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return $.getAll()}}];var m=Boolean(k);return K.search([{query:o,indexName:n,params:ln({attributesToRetrieve:["hierarchy.lvl0","hierarchy.lvl1","hierarchy.lvl2","hierarchy.lvl3","hierarchy.lvl4","hierarchy.lvl5","hierarchy.lvl6","content","type","url"],attributesToSnippet:["hierarchy.lvl1:".concat(U.current),"hierarchy.lvl2:".concat(U.current),"hierarchy.lvl3:".concat(U.current),"hierarchy.lvl4:".concat(U.current),"hierarchy.lvl5:".concat(U.current),"hierarchy.lvl6:".concat(U.current),"content:".concat(U.current)],snippetEllipsisText:"\u2026",highlightPreTag:"<mark>",highlightPostTag:"</mark>",hitsPerPage:20,clickAnalytics:m},a)}]).catch((function(e){throw"RetryError"===e.name&&s("error"),e})).then((function(e){var o=e.results[0],a=o.hits,s=o.nbHits,p=nn(a,(function(e){return Qt(e)}),c);i.context.searchSuggestions.length<Object.keys(p).length&&l({searchSuggestions:Object.keys(p)}),l({nbHits:s});var v={};return m&&(v={__autocomplete_indexName:n,__autocomplete_queryID:o.queryID,__autocomplete_algoliaCredentials:{appId:t,apiKey:r}}),Object.values(p).map((function(e,t){return{sourceId:"hits".concat(t),onSelect:function(e){var t=e.item,r=e.event;z(t),rn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return Object.values(nn(e,(function(e){return e.hierarchy.lvl1}),c)).map(f).map((function(e){return e.map((function(t){var r=null,n=e.find((function(e){return"lvl1"===e.type&&e.hierarchy.lvl1===t.hierarchy.lvl1}));return"lvl1"!==t.type&&n&&(r=n),ln(ln({},t),{},{__docsearch_parent:r},v)}))})).flat()}}}))}))}})}),[n,a,c,K,u,J,$,z,V,i,y,f,j,k,t,r]),Z=Q.getEnvironmentProps,G=Q.getRootProps,X=Q.refresh;return function(e){var t=e.getEnvironmentProps,r=e.panelElement,n=e.formElement,o=e.inputElement;yt.useEffect((function(){if(r&&n&&o){var e=t({panelElement:r,formElement:n,inputElement:o}),i=e.onTouchStart,a=e.onTouchMove;return window.addEventListener("touchstart",i),window.addEventListener("touchmove",a),function(){window.removeEventListener("touchstart",i),window.removeEventListener("touchmove",a)}}}),[t,r,n,o])}({getEnvironmentProps:Z,panelElement:H.current,formElement:M.current,inputElement:F.current}),function(e){var t=e.container;yt.useEffect((function(){if(t){var e=t.querySelectorAll("a[href]:not([disabled]), button:not([disabled]), input:not([disabled])"),r=e[0],n=e[e.length-1];return t.addEventListener("keydown",o),function(){t.removeEventListener("keydown",o)}}function o(e){"Tab"===e.key&&(e.shiftKey?document.activeElement===r&&(e.preventDefault(),n.focus()):document.activeElement===n&&(e.preventDefault(),r.focus()))}}),[t])}({container:R.current}),yt.useEffect((function(){return document.body.classList.add("DocSearch--active"),function(){var e,t;document.body.classList.remove("DocSearch--active"),null===(e=(t=window).scrollTo)||void 0===e||e.call(t,0,b)}}),[]),yt.useEffect((function(){window.matchMedia("(max-width: 768px)").matches&&(U.current=5)}),[]),yt.useEffect((function(){H.current&&(H.current.scrollTop=0)}),[T.query]),yt.useEffect((function(){V.length>0&&(X(),F.current&&F.current.focus())}),[V,X]),yt.useEffect((function(){function e(){if(L.current){var e=.01*window.innerHeight;L.current.style.setProperty("--docsearch-vh","".concat(e,"px"))}}return e(),window.addEventListener("resize",e),function(){window.removeEventListener("resize",e)}}),[]),yt.createElement("div",an({ref:R},G({"aria-expanded":!0}),{className:["DocSearch","DocSearch-Container","stalled"===T.status&&"DocSearch-Container--Stalled","error"===T.status&&"DocSearch-Container--Errored"].filter(Boolean).join(" "),role:"button",tabIndex:0,onMouseDown:function(e){e.target===e.currentTarget&&u()}}),yt.createElement("div",{className:"DocSearch-Modal",ref:L},yt.createElement("header",{className:"DocSearch-SearchBar",ref:M},yt.createElement(vr,an({},Q,{state:T,autoFocus:0===V.length,inputRef:F,isFromSelection:Boolean(V)&&V===B,translations:C,onClose:u}))),yt.createElement("div",{className:"DocSearch-Dropdown",ref:H},yt.createElement(lr,an({},Q,{indexName:n,state:T,hitComponent:p,resultsFooterComponent:d,disableUserPersonalization:j,recentSearches:J,favoriteSearches:$,inputRef:F,translations:_,getMissingResultsUrl:D,onItemClick:function(e,t){W(e),z(e),rn(t)||u()}}))),yt.createElement("footer",{className:"DocSearch-Footer"},yt.createElement(Ot,{translations:x}))))}}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[462],{9462:(e,t,r)=>{function n(e,t){var r=void 0;return function(){for(var n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];r&&clearTimeout(r),r=setTimeout((function(){return e.apply(void 0,o)}),t)}}function o(e){return e!==Object(e)}function i(e,t){if(e===t)return!0;if(o(e)||o(t)||"function"==typeof e||"function"==typeof t)return e===t;if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var r=0,n=Object.keys(e);r<n.length;r++){var a=n[r];if(!(a in t))return!1;if(!i(e[a],t[a]))return!1}return!0}r.r(t),r.d(t,{DocSearchModal:()=>vn});var a=function(){};function c(e){var t=e.item,r=e.items;return{index:t.__autocomplete_indexName,items:[t],positions:[1+r.findIndex((function(e){return e.objectID===t.objectID}))],queryID:t.__autocomplete_queryID,algoliaSource:["autocomplete"]}}function l(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i,a,c=[],l=!0,u=!1;try{if(i=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;l=!1}else for(;!(l=(n=i.call(r)).done)&&(c.push(n.value),c.length!==t);l=!0);}catch(s){u=!0,o=s}finally{try{if(!l&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(u)throw o}}return c}}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return u(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return u(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}var s=["items"],f=["items"];function m(e){return m="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},m(e)}function p(e){return function(e){if(Array.isArray(e))return v(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return v(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return v(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function v(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function d(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function y(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function h(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?y(Object(r),!0).forEach((function(t){b(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):y(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function b(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==m(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==m(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===m(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function g(e){return e.map((function(e){var t=e.items,r=d(e,s);return h(h({},r),{},{objectIDs:(null==t?void 0:t.map((function(e){return e.objectID})))||r.objectIDs})}))}function O(e){var t,r,n,o=(t=l((e.version||"").split(".").map(Number),2),r=t[0],n=t[1],r>=3||2===r&&n>=4||1===r&&n>=10);function i(t,r,n){if(o&&void 0!==n){var i=n[0].__autocomplete_algoliaCredentials,a={"X-Algolia-Application-Id":i.appId,"X-Algolia-API-Key":i.apiKey};e.apply(void 0,[t].concat(p(r),[{headers:a}]))}else e.apply(void 0,[t].concat(p(r)))}return{init:function(t,r){e("init",{appId:t,apiKey:r})},setUserToken:function(t){e("setUserToken",t)},clickedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("clickedObjectIDsAfterSearch",g(t),t[0].items)},clickedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("clickedObjectIDs",g(t),t[0].items)},clickedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];r.length>0&&e.apply(void 0,["clickedFilters"].concat(r))},convertedObjectIDsAfterSearch:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("convertedObjectIDsAfterSearch",g(t),t[0].items)},convertedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&i("convertedObjectIDs",g(t),t[0].items)},convertedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];r.length>0&&e.apply(void 0,["convertedFilters"].concat(r))},viewedObjectIDs:function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];t.length>0&&t.reduce((function(e,t){var r=t.items,n=d(t,f);return[].concat(p(e),p(function(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,r=[],n=0;n<e.objectIDs.length;n+=t)r.push(h(h({},e),{},{objectIDs:e.objectIDs.slice(n,n+t)}));return r}(h(h({},n),{},{objectIDs:(null==r?void 0:r.map((function(e){return e.objectID})))||n.objectIDs})).map((function(e){return{items:r,payload:e}}))))}),[]).forEach((function(e){var t=e.items;return i("viewedObjectIDs",[e.payload],t)}))},viewedFilters:function(){for(var t=arguments.length,r=new Array(t),n=0;n<t;n++)r[n]=arguments[n];r.length>0&&e.apply(void 0,["viewedFilters"].concat(r))}}}function S(e){var t=e.items.reduce((function(e,t){var r;return e[t.__autocomplete_indexName]=(null!==(r=e[t.__autocomplete_indexName])&&void 0!==r?r:[]).concat(t),e}),{});return Object.keys(t).map((function(e){return{index:e,items:t[e],algoliaSource:["autocomplete"]}}))}function j(e){return e.objectID&&e.__autocomplete_indexName&&e.__autocomplete_queryID}function w(e){return w="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},w(e)}function E(e){return function(e){if(Array.isArray(e))return P(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return P(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return P(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function P(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function I(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function D(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?I(Object(r),!0).forEach((function(t){A(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):I(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function A(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==w(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==w(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===w(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var k="2.6.0",x="https://cdn.jsdelivr.net/npm/search-insights@".concat(k,"/dist/search-insights.min.js"),C=n((function(e){var t=e.onItemsChange,r=e.items,n=e.insights,o=e.state;t({insights:n,insightsEvents:S({items:r}).map((function(e){return D({eventName:"Items Viewed"},e)})),state:o})}),400);function _(e){var t=function(e){return D({onItemsChange:function(e){var t=e.insights,r=e.insightsEvents;t.viewedObjectIDs.apply(t,E(r.map((function(e){return D(D({},e),{},{algoliaSource:[].concat(E(e.algoliaSource||[]),["autocomplete-internal"])})}))))},onSelect:function(e){var t=e.insights,r=e.insightsEvents;t.clickedObjectIDsAfterSearch.apply(t,E(r.map((function(e){return D(D({},e),{},{algoliaSource:[].concat(E(e.algoliaSource||[]),["autocomplete-internal"])})}))))},onActive:a},e)}(e),r=t.insightsClient,o=t.onItemsChange,l=t.onSelect,u=t.onActive,s=r;r||function(e){if("undefined"!=typeof window)e({window:window})}((function(e){var t=e.window,r=t.AlgoliaAnalyticsObject||"aa";"string"==typeof r&&(s=t[r]),s||(t.AlgoliaAnalyticsObject=r,t[r]||(t[r]=function(){t[r].queue||(t[r].queue=[]);for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];t[r].queue.push(n)}),t[r].version=k,s=t[r],function(e){var t="[Autocomplete]: Could not load search-insights.js. Please load it manually following https://alg.li/insights-autocomplete";try{var r=e.document.createElement("script");r.async=!0,r.src=x,r.onerror=function(){console.error(t)},document.body.appendChild(r)}catch(n){console.error(t)}}(t))}));var f=O(s),m={current:[]},p=n((function(e){var t=e.state;if(t.isOpen){var r=t.collections.reduce((function(e,t){return[].concat(E(e),E(t.items))}),[]).filter(j);i(m.current.map((function(e){return e.objectID})),r.map((function(e){return e.objectID})))||(m.current=r,r.length>0&&C({onItemsChange:o,items:r,insights:f,state:t}))}}),0);return{name:"aa.algoliaInsightsPlugin",subscribe:function(e){var t=e.setContext,r=e.onSelect,n=e.onActive;s("addAlgoliaAgent","insights-plugin"),t({algoliaInsightsPlugin:{__algoliaSearchParameters:{clickAnalytics:!0},insights:f}}),r((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&l({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Selected"},c({item:t,items:m.current}))]})})),n((function(e){var t=e.item,r=e.state,n=e.event;j(t)&&u({state:r,event:n,insights:f,item:t,insightsEvents:[D({eventName:"Item Active"},c({item:t,items:m.current}))]})}))},onStateChange:function(e){var t=e.state;p({state:t})},__autocomplete_pluginOptions:e}}function N(e){return N="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},N(e)}function T(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function q(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==N(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==N(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===N(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function R(e,t,r){var n,o=t.initialState;return{getState:function(){return o},dispatch:function(n,i){var a=function(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?T(Object(r),!0).forEach((function(t){q(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):T(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}({},o);o=e(o,{type:n,props:t,payload:i}),r({state:o,prevState:a})},pendingRequests:(n=[],{add:function(e){return n.push(e),e.finally((function(){n=n.filter((function(t){return t!==e}))}))},cancelAll:function(){n.forEach((function(e){return e.cancel()}))},isEmpty:function(){return 0===n.length}})}}function L(e){return e.reduce((function(e,t){return e.concat(t)}),[])}function M(e){return M="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},M(e)}function H(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function F(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?H(Object(r),!0).forEach((function(t){U(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):H(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function U(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==M(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==M(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===M(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function B(e){return 0===e.collections.length?0:e.collections.reduce((function(e,t){return e+t.items.length}),0)}var V=0;function K(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function $(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?K(Object(r),!0).forEach((function(t){J(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):K(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function J(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==z(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==z(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===z(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function z(e){return z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},z(e)}function W(e){return W="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},W(e)}function Q(e){return function(e){if(Array.isArray(e))return Z(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Z(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Z(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Z(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function G(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function X(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?G(Object(r),!0).forEach((function(t){Y(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):G(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Y(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==W(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==W(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===W(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ee(e,t){var r,n="undefined"!=typeof window?window:{},o=e.plugins||[];return X(X({debug:!1,openOnFocus:!1,placeholder:"",autoFocus:!1,defaultActiveItemId:null,stallThreshold:300,insights:!1,environment:n,shouldPanelOpen:function(e){return B(e.state)>0},reshape:function(e){return e.sources}},e),{},{id:null!==(r=e.id)&&void 0!==r?r:"autocomplete-".concat(V++),plugins:o,initialState:X({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var r;null===(r=e.onStateChange)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onStateChange)||void 0===r?void 0:r.call(e,t)}))},onSubmit:function(t){var r;null===(r=e.onSubmit)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onSubmit)||void 0===r?void 0:r.call(e,t)}))},onReset:function(t){var r;null===(r=e.onReset)||void 0===r||r.call(e,t),o.forEach((function(e){var r;return null===(r=e.onReset)||void 0===r?void 0:r.call(e,t)}))},getSources:function(r){return Promise.all([].concat(Q(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return function(e,t){var r=[];return Promise.resolve(e(t)).then((function(e){return Array.isArray(e),Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,r.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));r.push(e.sourceId);var t={getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:a,onResolve:a};Object.keys(t).forEach((function(e){t[e].__default=!0}));var n=$($({},t),e);return Promise.resolve(n)})))}))}(e,r)}))).then((function(e){return L(e)})).then((function(e){return e.map((function(e){return X(X({},e),{},{onSelect:function(r){e.onSelect(r),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,r)}))},onActive:function(r){e.onActive(r),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,r)}))},onResolve:function(r){e.onResolve(r),t.forEach((function(e){var t;return null===(t=e.onResolve)||void 0===t?void 0:t.call(e,r)}))}})}))}))},navigator:X({navigate:function(e){var t=e.itemUrl;n.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,r=n.open(t,"_blank","noopener");null==r||r.focus()},navigateNewWindow:function(e){var t=e.itemUrl;n.open(t,"_blank","noopener")}},e.navigator)})}function te(e){return te="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},te(e)}function re(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function ne(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?re(Object(r),!0).forEach((function(t){oe(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):re(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function oe(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==te(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==te(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===te(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ie(e){return ie="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},ie(e)}function ae(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function ce(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?ae(Object(r),!0).forEach((function(t){le(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ae(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function le(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==ie(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==ie(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===ie(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function ue(e){return function(e){if(Array.isArray(e))return se(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return se(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return se(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function se(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function fe(e){return Boolean(e.execute)}function me(e,t,r){if(o=e,Boolean(null==o?void 0:o.execute)){var n="algolia"===e.requesterId?Object.assign.apply(Object,[{}].concat(ue(Object.keys(r.context).map((function(e){var t;return null===(t=r.context[e])||void 0===t?void 0:t.__algoliaSearchParameters}))))):{};return ce(ce({},e),{},{requests:e.queries.map((function(r){return{query:"algolia"===e.requesterId?ce(ce({},r),{},{params:ce(ce({},n),r.params)}):r,sourceId:t,transformResponse:e.transformResponse}}))})}var o;return{items:e,sourceId:t}}function pe(e){var t=e.reduce((function(e,t){if(!fe(t))return e.push(t),e;var r=t.searchClient,n=t.execute,o=t.requesterId,i=t.requests,a=e.find((function(e){return fe(t)&&fe(e)&&e.searchClient===r&&Boolean(o)&&e.requesterId===o}));if(a){var c;(c=a.items).push.apply(c,ue(i))}else{var l={execute:n,requesterId:o,items:i,searchClient:r};e.push(l)}return e}),[]).map((function(e){if(!fe(e))return Promise.resolve(e);var t=e,r=t.execute,n=t.items;return r({searchClient:t.searchClient,requests:n})}));return Promise.all(t).then((function(e){return L(e)}))}function ve(e,t,r){return t.map((function(t){var n,o=e.filter((function(e){return e.sourceId===t.sourceId})),i=o.map((function(e){return e.items})),a=o[0].transformResponse,c=a?a({results:n=i,hits:n.map((function(e){return e.hits})).filter(Boolean),facetHits:n.map((function(e){var t;return null===(t=e.facetHits)||void 0===t?void 0:t.map((function(e){return{label:e.value,count:e.count,_highlightResult:{label:{value:e.highlighted}}}}))})).filter(Boolean)}):i;return t.onResolve({source:t,results:i,items:c,state:r.getState()}),Array.isArray(c),c.every(Boolean),'The `getItems` function from source "'.concat(t.sourceId,'" must return an array of items but returned ').concat(JSON.stringify(void 0),".\n\nDid you forget to return items?\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems"),{source:t,items:c}}))}function de(e,t){var r=t;return{then:function(t,n){return de(e.then(be(t,r,e),be(n,r,e)),r)},catch:function(t){return de(e.catch(be(t,r,e)),r)},finally:function(t){return t&&r.onCancelList.push(t),de(e.finally(be(t&&function(){return r.onCancelList=[],t()},r,e)),r)},cancel:function(){r.isCanceled=!0;var e=r.onCancelList;r.onCancelList=[],e.forEach((function(e){e()}))},isCanceled:function(){return!0===r.isCanceled}}}function ye(e){return de(new Promise((function(t,r){return e(t,r)})),{isCanceled:!1,onCancelList:[]})}function he(e){return de(e,{isCanceled:!1,onCancelList:[]})}function be(e,t,r){return e?function(r){return t.isCanceled?r:e(r)}:r}function ge(e){var t=function(e){var t=e.collections.map((function(e){return e.items.length})).reduce((function(e,t,r){var n=(e[r-1]||0)+t;return e.push(n),e}),[]).reduce((function(t,r){return r<=e.activeItemId?t+1:t}),0);return e.collections[t]}(e);if(!t)return null;var r=t.items[function(e){for(var t=e.state,r=e.collection,n=!1,o=0,i=0;!1===n;){var a=t.collections[o];if(a===r){n=!0;break}i+=a.items.length,o++}return t.activeItemId-i}({state:e,collection:t})],n=t.source;return{item:r,itemInputValue:n.getItemInputValue({item:r,state:e}),itemUrl:n.getItemUrl({item:r,state:e}),source:n}}function Oe(e){return Oe="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Oe(e)}ye.resolve=function(e){return he(Promise.resolve(e))},ye.reject=function(e){return he(Promise.reject(e))};var Se=["event","nextState","props","query","refresh","store"];function je(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function we(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?je(Object(r),!0).forEach((function(t){Ee(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):je(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Ee(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==Oe(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==Oe(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Oe(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Pe(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Ie,De,Ae,ke=null,xe=(Ie=-1,De=-1,Ae=void 0,function(e){var t=++Ie;return Promise.resolve(e).then((function(e){return Ae&&t<De?Ae:(De=t,Ae=e,e)}))});function Ce(e){var t=e.event,r=e.nextState,n=void 0===r?{}:r,o=e.props,i=e.query,a=e.refresh,c=e.store,l=Pe(e,Se);ke&&o.environment.clearTimeout(ke);var u=l.setCollections,s=l.setIsOpen,f=l.setQuery,m=l.setActiveItemId,p=l.setStatus;if(f(i),m(o.defaultActiveItemId),!i&&!1===o.openOnFocus){var v,d=c.getState().collections.map((function(e){return we(we({},e),{},{items:[]})}));p("idle"),u(d),s(null!==(v=n.isOpen)&&void 0!==v?v:o.shouldPanelOpen({state:c.getState()}));var y=he(xe(d).then((function(){return Promise.resolve()})));return c.pendingRequests.add(y)}p("loading"),ke=o.environment.setTimeout((function(){p("stalled")}),o.stallThreshold);var h=he(xe(o.getSources(we({query:i,refresh:a,state:c.getState()},l)).then((function(e){return Promise.all(e.map((function(e){return Promise.resolve(e.getItems(we({query:i,refresh:a,state:c.getState()},l))).then((function(t){return me(t,e.sourceId,c.getState())}))}))).then(pe).then((function(t){return ve(t,e,c)})).then((function(e){return function(e){var t=e.collections,r=e.props,n=e.state,o=t.reduce((function(e,t){return ne(ne({},e),{},oe({},t.source.sourceId,ne(ne({},t.source),{},{getItems:function(){return L(t.items)}})))}),{}),i=r.plugins.reduce((function(e,t){return t.reshape?t.reshape(e):e}),{sourcesBySourceId:o,state:n}).sourcesBySourceId;return L(r.reshape({sourcesBySourceId:i,sources:Object.values(i),state:n})).filter(Boolean).map((function(e){return{source:e,items:e.getItems()}}))}({collections:e,props:o,state:c.getState()})}))})))).then((function(e){var r;p("idle"),u(e);var f=o.shouldPanelOpen({state:c.getState()});s(null!==(r=n.isOpen)&&void 0!==r?r:o.openOnFocus&&!i&&f||f);var m=ge(c.getState());if(null!==c.getState().activeItemId&&m){var v=m.item,d=m.itemInputValue,y=m.itemUrl,h=m.source;h.onActive(we({event:t,item:v,itemInputValue:d,itemUrl:y,refresh:a,source:h,state:c.getState()},l))}})).finally((function(){p("idle"),ke&&o.environment.clearTimeout(ke)}));return c.pendingRequests.add(h)}function _e(e){return _e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},_e(e)}var Ne=["event","props","refresh","store"];function Te(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function qe(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?Te(Object(r),!0).forEach((function(t){Re(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):Te(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Re(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==_e(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==_e(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===_e(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Le(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var Me=/((gt|sm)-|galaxy nexus)|samsung[- ]|samsungbrowser/i;function He(e){return He="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},He(e)}var Fe=["props","refresh","store"],Ue=["inputElement","formElement","panelElement"],Be=["inputElement"],Ve=["inputElement","maxLength"],Ke=["sourceIndex"],$e=["sourceIndex"],Je=["item","source","sourceIndex"];function ze(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function We(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?ze(Object(r),!0).forEach((function(t){Qe(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ze(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Qe(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==He(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==He(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===He(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Ze(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ge(e){var t=e.props,r=e.refresh,n=e.store,o=Ze(e,Fe),i=function(e,t){return void 0!==t?"".concat(e,"-").concat(t):e};return{getEnvironmentProps:function(e){var r=e.inputElement,o=e.formElement,i=e.panelElement;function a(e){!n.getState().isOpen&&n.pendingRequests.isEmpty()||e.target===r||!1===[o,i].some((function(t){return r=t,n=e.target,r===n||r.contains(n);var r,n}))&&(n.dispatch("blur",null),t.debug||n.pendingRequests.cancelAll())}return We({onTouchStart:a,onMouseDown:a,onTouchMove:function(e){!1!==n.getState().isOpen&&r===t.environment.document.activeElement&&e.target!==r&&r.blur()}},Ze(e,Ue))},getRootProps:function(e){return We({role:"combobox","aria-expanded":n.getState().isOpen,"aria-haspopup":"listbox","aria-owns":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){e.inputElement;return We({action:"",noValidate:!0,role:"search",onSubmit:function(i){var a;i.preventDefault(),t.onSubmit(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("submit",null),null===(a=e.inputElement)||void 0===a||a.blur()},onReset:function(i){var a;i.preventDefault(),t.onReset(We({event:i,refresh:r,state:n.getState()},o)),n.dispatch("reset",null),null===(a=e.inputElement)||void 0===a||a.focus()}},Ze(e,Be))},getLabelProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,Ke);return We({htmlFor:"".concat(i(t.id,n),"-input"),id:"".concat(i(t.id,n),"-label")},o)},getInputProps:function(e){var i;function c(e){(t.openOnFocus||Boolean(n.getState().query))&&Ce(We({event:e,props:t,query:n.getState().completion||n.getState().query,refresh:r,store:n},o)),n.dispatch("focus",null)}var l=e||{},u=(l.inputElement,l.maxLength),s=void 0===u?512:u,f=Ze(l,Ve),m=ge(n.getState()),p=function(e){return Boolean(e&&e.match(Me))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),v=null!=m&&m.itemUrl&&!p?"go":"search";return We({"aria-autocomplete":"both","aria-activedescendant":n.getState().isOpen&&null!==n.getState().activeItemId?"".concat(t.id,"-item-").concat(n.getState().activeItemId):void 0,"aria-controls":n.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:n.getState().completion||n.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:v,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:s,type:"search",onChange:function(e){Ce(We({event:e,props:t,query:e.currentTarget.value.slice(0,s),refresh:r,store:n},o))},onKeyDown:function(e){!function(e){var t=e.event,r=e.props,n=e.refresh,o=e.store,i=Le(e,Ne);if("ArrowUp"===t.key||"ArrowDown"===t.key){var a=function(){var e=r.environment.document.getElementById("".concat(r.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},c=function(){var e=ge(o.getState());if(null!==o.getState().activeItemId&&e){var r=e.item,a=e.itemInputValue,c=e.itemUrl,l=e.source;l.onActive(qe({event:t,item:r,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(r.openOnFocus||Boolean(o.getState().query))?Ce(qe({event:t,props:r,query:o.getState().query,refresh:n,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:r.defaultActiveItemId}),c(),setTimeout(a,0)})):(o.dispatch(t.key,{}),c(),a())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(r.debug||o.pendingRequests.cancelAll());t.preventDefault();var l=ge(o.getState()),u=l.item,s=l.itemInputValue,f=l.itemUrl,m=l.source;if(t.metaKey||t.ctrlKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewTab({itemUrl:f,item:u,state:o.getState()}));else if(t.shiftKey)void 0!==f&&(m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),r.navigator.navigateNewWindow({itemUrl:f,item:u,state:o.getState()}));else if(t.altKey);else{if(void 0!==f)return m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i)),void r.navigator.navigate({itemUrl:f,item:u,state:o.getState()});Ce(qe({event:t,nextState:{isOpen:!1},props:r,query:s,refresh:n,store:o},i)).then((function(){m.onSelect(qe({event:t,item:u,itemInputValue:s,itemUrl:f,refresh:n,source:m,state:o.getState()},i))}))}}}(We({event:e,props:t,refresh:r,store:n},o))},onFocus:c,onBlur:a,onClick:function(r){e.inputElement!==t.environment.document.activeElement||n.getState().isOpen||c(r)}},f)},getPanelProps:function(e){return We({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){n.dispatch("mouseleave",null)}},e)},getListProps:function(e){var r=e||{},n=r.sourceIndex,o=Ze(r,$e);return We({role:"listbox","aria-labelledby":"".concat(i(t.id,n),"-label"),id:"".concat(i(t.id,n),"-list")},o)},getItemProps:function(e){var a=e.item,c=e.source,l=e.sourceIndex,u=Ze(e,Je);return We({id:"".concat(i(t.id,l),"-item-").concat(a.__autocomplete_id),role:"option","aria-selected":n.getState().activeItemId===a.__autocomplete_id,onMouseMove:function(e){if(a.__autocomplete_id!==n.getState().activeItemId){n.dispatch("mousemove",a.__autocomplete_id);var t=ge(n.getState());if(null!==n.getState().activeItemId&&t){var i=t.item,c=t.itemInputValue,l=t.itemUrl,u=t.source;u.onActive(We({event:e,item:i,itemInputValue:c,itemUrl:l,refresh:r,source:u,state:n.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var i=c.getItemInputValue({item:a,state:n.getState()}),l=c.getItemUrl({item:a,state:n.getState()});(l?Promise.resolve():Ce(We({event:e,nextState:{isOpen:!1},props:t,query:i,refresh:r,store:n},o))).then((function(){c.onSelect(We({event:e,item:a,itemInputValue:i,itemUrl:l,refresh:r,source:c,state:n.getState()},o))}))}},u)}}}var Xe=[{segment:"autocomplete-core",version:"1.9.3"}];function Ye(e){return Ye="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},Ye(e)}function et(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function tt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?et(Object(r),!0).forEach((function(t){rt(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):et(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function rt(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==Ye(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==Ye(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===Ye(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function nt(e){var t,r,n,o,i=e.plugins,a=e.options,c=null===(t=((null===(r=a.__autocomplete_metadata)||void 0===r?void 0:r.userAgents)||[])[0])||void 0===t?void 0:t.segment,l=c?rt({},c,Object.keys((null===(n=a.__autocomplete_metadata)||void 0===n?void 0:n.options)||{})):{};return{plugins:i.map((function(e){return{name:e.name,options:Object.keys(e.__autocomplete_pluginOptions||[])}})),options:tt({"autocomplete-core":Object.keys(a)},l),ua:Xe.concat((null===(o=a.__autocomplete_metadata)||void 0===o?void 0:o.userAgents)||[])}}function ot(e){var t,r=e.state;return!1===r.isOpen||null===r.activeItemId?null:(null===(t=ge(r))||void 0===t?void 0:t.itemInputValue)||null}function it(e,t,r,n){if(!r)return null;if(e<0&&(null===t||null!==n&&0===t))return r+e;var o=(null===t?-1:t)+e;return o<=-1||o>=r?null===n?null:0:o}function at(e){return at="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},at(e)}function ct(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function lt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?ct(Object(r),!0).forEach((function(t){ut(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ct(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function ut(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==at(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==at(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===at(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}var st=function(e,t){switch(t.type){case"setActiveItemId":case"mousemove":return lt(lt({},e),{},{activeItemId:t.payload});case"setQuery":return lt(lt({},e),{},{query:t.payload,completion:null});case"setCollections":return lt(lt({},e),{},{collections:t.payload});case"setIsOpen":return lt(lt({},e),{},{isOpen:t.payload});case"setStatus":return lt(lt({},e),{},{status:t.payload});case"setContext":return lt(lt({},e),{},{context:lt(lt({},e.context),t.payload)});case"ArrowDown":var r=lt(lt({},e),{},{activeItemId:t.payload.hasOwnProperty("nextActiveItemId")?t.payload.nextActiveItemId:it(1,e.activeItemId,B(e),t.props.defaultActiveItemId)});return lt(lt({},r),{},{completion:ot({state:r})});case"ArrowUp":var n=lt(lt({},e),{},{activeItemId:it(-1,e.activeItemId,B(e),t.props.defaultActiveItemId)});return lt(lt({},n),{},{completion:ot({state:n})});case"Escape":return e.isOpen?lt(lt({},e),{},{activeItemId:null,isOpen:!1,completion:null}):lt(lt({},e),{},{activeItemId:null,query:"",status:"idle",collections:[]});case"submit":return lt(lt({},e),{},{activeItemId:null,isOpen:!1,status:"idle"});case"reset":return lt(lt({},e),{},{activeItemId:!0===t.props.openOnFocus?t.props.defaultActiveItemId:null,status:"idle",query:""});case"focus":return lt(lt({},e),{},{activeItemId:t.props.defaultActiveItemId,isOpen:(t.props.openOnFocus||Boolean(e.query))&&t.props.shouldPanelOpen({state:e})});case"blur":return t.props.debug?e:lt(lt({},e),{},{isOpen:!1,activeItemId:null});case"mouseleave":return lt(lt({},e),{},{activeItemId:t.props.defaultActiveItemId});default:return"The reducer action ".concat(JSON.stringify(t.type)," is not supported."),e}};function ft(e){return ft="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},ft(e)}function mt(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function pt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?mt(Object(r),!0).forEach((function(t){vt(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):mt(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function vt(e,t,r){return(t=function(e){var t=function(e,t){if("object"!==ft(e)||null===e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||"default");if("object"!==ft(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===ft(t)?t:String(t)}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function dt(e){var t=[],r=ee(e,t),n=R(st,r,(function(e){var t=e.prevState,n=e.state;r.onStateChange(pt({prevState:t,state:n,refresh:a,navigator:r.navigator},o))})),o=function(e){var t=e.store;return{setActiveItemId:function(e){t.dispatch("setActiveItemId",e)},setQuery:function(e){t.dispatch("setQuery",e)},setCollections:function(e){var r=0,n=e.map((function(e){return F(F({},e),{},{items:L(e.items).map((function(e){return F(F({},e),{},{__autocomplete_id:r++})}))})}));t.dispatch("setCollections",n)},setIsOpen:function(e){t.dispatch("setIsOpen",e)},setStatus:function(e){t.dispatch("setStatus",e)},setContext:function(e){t.dispatch("setContext",e)}}}({store:n}),i=Ge(pt({props:r,refresh:a,store:n,navigator:r.navigator},o));function a(){return Ce(pt({event:new Event("input"),nextState:{isOpen:n.getState().isOpen},props:r,navigator:r.navigator,query:n.getState().query,refresh:a,store:n},o))}if(e.insights&&!r.plugins.some((function(e){return"aa.algoliaInsightsPlugin"===e.name}))){var c="boolean"==typeof e.insights?{}:e.insights;r.plugins.push(_(c))}return r.plugins.forEach((function(e){var n;return null===(n=e.subscribe)||void 0===n?void 0:n.call(e,pt(pt({},o),{},{navigator:r.navigator,refresh:a,onSelect:function(e){t.push({onSelect:e})},onActive:function(e){t.push({onActive:e})},onResolve:function(e){t.push({onResolve:e})}}))})),function(e){var t,r,n=e.metadata,o=e.environment;if(null===(t=o.navigator)||void 0===t||null===(r=t.userAgent)||void 0===r?void 0:r.includes("Algolia Crawler")){var i=o.document.createElement("meta"),a=o.document.querySelector("head");i.name="algolia:metadata",setTimeout((function(){i.content=JSON.stringify(n),a.appendChild(i)}),0)}}({metadata:nt({plugins:r.plugins,options:e}),environment:r.environment}),pt(pt({refresh:a,navigator:r.navigator},i),o)}var yt=r(6540),ht=64;function bt(e){var t=e.translations,r=(void 0===t?{}:t).searchByText,n=void 0===r?"Search by":r;return yt.createElement("a",{href:"https://www.algolia.com/ref/docsearch/?utm_source=".concat(window.location.hostname,"&utm_medium=referral&utm_content=powered_by&utm_campaign=docsearch"),target:"_blank",rel:"noopener noreferrer"},yt.createElement("span",{className:"DocSearch-Label"},n),yt.createElement("svg",{width:"77",height:"19","aria-label":"Algolia",role:"img",id:"Layer_1",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 2196.2 500"},yt.createElement("defs",null,yt.createElement("style",null,".cls-1,.cls-2{fill:#003dff;}.cls-2{fill-rule:evenodd;}")),yt.createElement("path",{className:"cls-2",d:"M1070.38,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"}),yt.createElement("rect",{className:"cls-1",x:"1845.88",y:"104.73",width:"62.58",height:"277.9",rx:"5.9",ry:"5.9"}),yt.createElement("path",{className:"cls-2",d:"M1851.78,71.38h50.77c3.26,0,5.9-2.64,5.9-5.9V5.9c0-3.62-3.24-6.39-6.82-5.83l-50.77,7.95c-2.87,.45-4.99,2.92-4.99,5.83v51.62c0,3.26,2.64,5.9,5.9,5.9Z"}),yt.createElement("path",{className:"cls-2",d:"M1764.03,275.3V5.91c0-3.63-3.24-6.39-6.82-5.83l-50.46,7.94c-2.87,.45-4.99,2.93-4.99,5.84l.17,273.22c0,12.92,0,92.7,95.97,95.49,3.33,.1,6.09-2.58,6.09-5.91v-40.78c0-2.96-2.19-5.51-5.12-5.84-34.85-4.01-34.85-47.57-34.85-54.72Z"}),yt.createElement("path",{className:"cls-2",d:"M1631.95,142.72c-11.14-12.25-24.83-21.65-40.78-28.31-15.92-6.53-33.26-9.85-52.07-9.85-18.78,0-36.15,3.17-51.92,9.85-15.59,6.66-29.29,16.05-40.76,28.31-11.47,12.23-20.38,26.87-26.76,44.03-6.38,17.17-9.24,37.37-9.24,58.36,0,20.99,3.19,36.87,9.55,54.21,6.38,17.32,15.14,32.11,26.45,44.36,11.29,12.23,24.83,21.62,40.6,28.46,15.77,6.83,40.12,10.33,52.4,10.48,12.25,0,36.78-3.82,52.7-10.48,15.92-6.68,29.46-16.23,40.78-28.46,11.29-12.25,20.05-27.04,26.25-44.36,6.22-17.34,9.24-33.22,9.24-54.21,0-20.99-3.34-41.19-10.03-58.36-6.38-17.17-15.14-31.8-26.43-44.03Zm-44.43,163.75c-11.47,15.75-27.56,23.7-48.09,23.7-20.55,0-36.63-7.8-48.1-23.7-11.47-15.75-17.21-34.01-17.21-61.2,0-26.89,5.59-49.14,17.06-64.87,11.45-15.75,27.54-23.52,48.07-23.52,20.55,0,36.63,7.78,48.09,23.52,11.47,15.57,17.36,37.98,17.36,64.87,0,27.19-5.72,45.3-17.19,61.2Z"}),yt.createElement("path",{className:"cls-2",d:"M894.42,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"}),yt.createElement("path",{className:"cls-2",d:"M2133.97,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-14.52,22.58-22.99,49.63-22.99,78.73,0,44.89,20.13,84.92,51.59,111.1,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47,1.23,0,2.46-.03,3.68-.09,.36-.02,.71-.05,1.07-.07,.87-.05,1.75-.11,2.62-.2,.34-.03,.68-.08,1.02-.12,.91-.1,1.82-.21,2.73-.34,.21-.03,.42-.07,.63-.1,32.89-5.07,61.56-30.82,70.9-62.81v57.83c0,3.26,2.64,5.9,5.9,5.9h50.42c3.26,0,5.9-2.64,5.9-5.9V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,206.92c-12.2,10.16-27.97,13.98-44.84,15.12-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-42.24,0-77.12-35.89-77.12-79.37,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33v142.83Z"}),yt.createElement("path",{className:"cls-2",d:"M1314.05,104.73h-49.33c-48.36,0-90.91,25.48-115.75,64.1-11.79,18.34-19.6,39.64-22.11,62.59-.58,5.3-.88,10.68-.88,16.14s.31,11.15,.93,16.59c4.28,38.09,23.14,71.61,50.66,94.52,2.93,2.6,6.05,4.98,9.31,7.14,12.86,8.49,28.11,13.47,44.52,13.47h0c17.99,0,34.61-5.93,48.16-15.97,16.29-11.58,28.88-28.54,34.48-47.75v50.26h-.11v11.08c0,21.84-5.71,38.27-17.34,49.36-11.61,11.08-31.04,16.63-58.25,16.63-11.12,0-28.79-.59-46.6-2.41-2.83-.29-5.46,1.5-6.27,4.22l-12.78,43.11c-1.02,3.46,1.27,7.02,4.83,7.53,21.52,3.08,42.52,4.68,54.65,4.68,48.91,0,85.16-10.75,108.89-32.21,21.48-19.41,33.15-48.89,35.2-88.52V110.63c0-3.26-2.64-5.9-5.9-5.9h-56.32Zm0,64.1s.65,139.13,0,143.36c-12.08,9.77-27.11,13.59-43.49,14.7-.16,.01-.33,.03-.49,.04-1.12,.07-2.24,.1-3.36,.1-1.32,0-2.63-.03-3.94-.1-40.41-2.11-74.52-37.26-74.52-79.38,0-10.25,1.96-20.01,5.42-28.98,11.22-29.12,38.77-49.74,71.06-49.74h49.33Z"}),yt.createElement("path",{className:"cls-1",d:"M249.83,0C113.3,0,2,110.09,.03,246.16c-2,138.19,110.12,252.7,248.33,253.5,42.68,.25,83.79-10.19,120.3-30.03,3.56-1.93,4.11-6.83,1.08-9.51l-23.38-20.72c-4.75-4.21-11.51-5.4-17.36-2.92-25.48,10.84-53.17,16.38-81.71,16.03-111.68-1.37-201.91-94.29-200.13-205.96,1.76-110.26,92-199.41,202.67-199.41h202.69V407.41l-115-102.18c-3.72-3.31-9.42-2.66-12.42,1.31-18.46,24.44-48.53,39.64-81.93,37.34-46.33-3.2-83.87-40.5-87.34-86.81-4.15-55.24,39.63-101.52,94-101.52,49.18,0,89.68,37.85,93.91,85.95,.38,4.28,2.31,8.27,5.52,11.12l29.95,26.55c3.4,3.01,8.79,1.17,9.63-3.3,2.16-11.55,2.92-23.58,2.07-35.92-4.82-70.34-61.8-126.93-132.17-131.26-80.68-4.97-148.13,58.14-150.27,137.25-2.09,77.1,61.08,143.56,138.19,145.26,32.19,.71,62.03-9.41,86.14-26.95l150.26,133.2c6.44,5.71,16.61,1.14,16.61-7.47V9.48C499.66,4.25,495.42,0,490.18,0H249.83Z"})))}function gt(e){return yt.createElement("svg",{width:"15",height:"15","aria-label":e.ariaLabel,role:"img"},yt.createElement("g",{fill:"none",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"1.2"},e.children))}function Ot(e){var t=e.translations,r=void 0===t?{}:t,n=r.selectText,o=void 0===n?"to select":n,i=r.selectKeyAriaLabel,a=void 0===i?"Enter key":i,c=r.navigateText,l=void 0===c?"to navigate":c,u=r.navigateUpKeyAriaLabel,s=void 0===u?"Arrow up":u,f=r.navigateDownKeyAriaLabel,m=void 0===f?"Arrow down":f,p=r.closeText,v=void 0===p?"to close":p,d=r.closeKeyAriaLabel,y=void 0===d?"Escape key":d,h=r.searchByText,b=void 0===h?"Search by":h;return yt.createElement(yt.Fragment,null,yt.createElement("div",{className:"DocSearch-Logo"},yt.createElement(bt,{translations:{searchByText:b}})),yt.createElement("ul",{className:"DocSearch-Commands"},yt.createElement("li",null,yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:a},yt.createElement("path",{d:"M12 3.53088v3c0 1-1 2-2 2H4M7 11.53088l-3-3 3-3"}))),yt.createElement("span",{className:"DocSearch-Label"},o)),yt.createElement("li",null,yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:m},yt.createElement("path",{d:"M7.5 3.5v8M10.5 8.5l-3 3-3-3"}))),yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:s},yt.createElement("path",{d:"M7.5 11.5v-8M10.5 6.5l-3-3-3 3"}))),yt.createElement("span",{className:"DocSearch-Label"},l)),yt.createElement("li",null,yt.createElement("kbd",{className:"DocSearch-Commands-Key"},yt.createElement(gt,{ariaLabel:y},yt.createElement("path",{d:"M13.6167 8.936c-.1065.3583-.6883.962-1.4875.962-.7993 0-1.653-.9165-1.653-2.1258v-.5678c0-1.2548.7896-2.1016 1.653-2.1016.8634 0 1.3601.4778 1.4875 1.0724M9 6c-.1352-.4735-.7506-.9219-1.46-.8972-.7092.0246-1.344.57-1.344 1.2166s.4198.8812 1.3445.9805C8.465 7.3992 8.968 7.9337 9 8.5c.032.5663-.454 1.398-1.4595 1.398C6.6593 9.898 6 9 5.963 8.4851m-1.4748.5368c-.2635.5941-.8099.876-1.5443.876s-1.7073-.6248-1.7073-2.204v-.4603c0-1.0416.721-2.131 1.7073-2.131.9864 0 1.6425 1.031 1.5443 2.2492h-2.956"}))),yt.createElement("span",{className:"DocSearch-Label"},v))))}function St(e){var t=e.hit,r=e.children;return yt.createElement("a",{href:t.url},r)}function jt(){return yt.createElement("svg",{width:"40",height:"40",viewBox:"0 0 20 20",fill:"none",fillRule:"evenodd",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M19 4.8a16 16 0 00-2-1.2m-3.3-1.2A16 16 0 001.1 4.7M16.7 8a12 12 0 00-2.8-1.4M10 6a12 12 0 00-6.7 2M12.3 14.7a4 4 0 00-4.5 0M14.5 11.4A8 8 0 0010 10M3 16L18 2M10 18h0"}))}function wt(e){var t=e.translations,r=void 0===t?{}:t,n=r.titleText,o=void 0===n?"Unable to fetch results":n,i=r.helpText,a=void 0===i?"You might want to check your network connection.":i;return yt.createElement("div",{className:"DocSearch-ErrorScreen"},yt.createElement("div",{className:"DocSearch-Screen-Icon"},yt.createElement(jt,null)),yt.createElement("p",{className:"DocSearch-Title"},o),yt.createElement("p",{className:"DocSearch-Help"},a))}function Et(){return yt.createElement("svg",{width:"40",height:"40",viewBox:"0 0 20 20",fill:"none",fillRule:"evenodd",stroke:"currentColor",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M15.5 4.8c2 3 1.7 7-1 9.7h0l4.3 4.3-4.3-4.3a7.8 7.8 0 01-9.8 1m-2.2-2.2A7.8 7.8 0 0113.2 2.4M2 18L18 2"}))}var Pt=["translations"];function It(e){return function(e){if(Array.isArray(e))return Dt(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Dt(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Dt(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Dt(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function At(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function kt(e){var t=e.translations,r=void 0===t?{}:t,n=At(e,Pt),o=r.noResultsText,i=void 0===o?"No results for":o,a=r.suggestedQueryText,c=void 0===a?"Try searching for":a,l=r.reportMissingResultsText,u=void 0===l?"Believe this query should return results?":l,s=r.reportMissingResultsLinkText,f=void 0===s?"Let us know.":s,m=n.state.context.searchSuggestions;return yt.createElement("div",{className:"DocSearch-NoResults"},yt.createElement("div",{className:"DocSearch-Screen-Icon"},yt.createElement(Et,null)),yt.createElement("p",{className:"DocSearch-Title"},i,' "',yt.createElement("strong",null,n.state.query),'"'),m&&m.length>0&&yt.createElement("div",{className:"DocSearch-NoResults-Prefill-List"},yt.createElement("p",{className:"DocSearch-Help"},c,":"),yt.createElement("ul",null,m.slice(0,3).reduce((function(e,t){return[].concat(It(e),[yt.createElement("li",{key:t},yt.createElement("button",{className:"DocSearch-Prefill",key:t,type:"button",onClick:function(){n.setQuery(t.toLowerCase()+" "),n.refresh(),n.inputRef.current.focus()}},t))])}),[]))),n.getMissingResultsUrl&&yt.createElement("p",{className:"DocSearch-Help"},"".concat(u," "),yt.createElement("a",{href:n.getMissingResultsUrl({query:n.state.query}),target:"_blank",rel:"noopener noreferrer"},f)))}var xt=function(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 6v12c0 .52-.2 1-1 1H4c-.7 0-1-.33-1-1V2c0-.55.42-1 1-1h8l5 5zM14 8h-3.13c-.51 0-.87-.34-.87-.87V4",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))};function Ct(e){switch(e.type){case"lvl1":return yt.createElement(xt,null);case"content":return yt.createElement(Nt,null);default:return yt.createElement(_t,null)}}function _t(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M13 13h4-4V8H7v5h6v4-4H7V8H3h4V3v5h6V3v5h4-4v5zm-6 0v4-4H3h4z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}function Nt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M17 5H3h14zm0 5H3h14zm0 5H3h14z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function Tt(){return yt.createElement("svg",{className:"DocSearch-Hit-Select-Icon",width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M18 3v4c0 2-2 4-4 4H2"}),yt.createElement("path",{d:"M8 17l-6-6 6-6"})))}var qt=["hit","attribute","tagName"];function Rt(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function Lt(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?Rt(Object(r),!0).forEach((function(t){Mt(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):Rt(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function Mt(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function Ht(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function Ft(e,t){return t.split(".").reduce((function(e,t){return null!=e&&e[t]?e[t]:null}),e)}function Ut(e){var t=e.hit,r=e.attribute,n=e.tagName,o=void 0===n?"span":n,i=Ht(e,qt);return(0,yt.createElement)(o,Lt(Lt({},i),{},{dangerouslySetInnerHTML:{__html:Ft(t,"_snippetResult.".concat(r,".value"))||Ft(t,r)}}))}function Bt(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==r)return;var n,o,i=[],a=!0,c=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(l){c=!0,o=l}finally{try{a||null==r.return||r.return()}finally{if(c)throw o}}return i}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return Vt(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return Vt(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Vt(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function Kt(){return Kt=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Kt.apply(this,arguments)}function $t(e){return e.collection&&0!==e.collection.items.length?yt.createElement("section",{className:"DocSearch-Hits"},yt.createElement("div",{className:"DocSearch-Hit-source"},e.title),yt.createElement("ul",e.getListProps(),e.collection.items.map((function(t,r){return yt.createElement(Jt,Kt({key:[e.title,t.objectID].join(":"),item:t,index:r},e))})))):null}function Jt(e){var t=e.item,r=e.index,n=e.renderIcon,o=e.renderAction,i=e.getItemProps,a=e.onItemClick,c=e.collection,l=e.hitComponent,u=Bt(yt.useState(!1),2),s=u[0],f=u[1],m=Bt(yt.useState(!1),2),p=m[0],v=m[1],d=yt.useRef(null),y=l;return yt.createElement("li",Kt({className:["DocSearch-Hit",t.__docsearch_parent&&"DocSearch-Hit--Child",s&&"DocSearch-Hit--deleting",p&&"DocSearch-Hit--favoriting"].filter(Boolean).join(" "),onTransitionEnd:function(){d.current&&d.current()}},i({item:t,source:c.source,onClick:function(e){a(t,e)}})),yt.createElement(y,{hit:t},yt.createElement("div",{className:"DocSearch-Hit-Container"},n({item:t,index:r}),t.hierarchy[t.type]&&"lvl1"===t.type&&yt.createElement("div",{className:"DocSearch-Hit-content-wrapper"},yt.createElement(Ut,{className:"DocSearch-Hit-title",hit:t,attribute:"hierarchy.lvl1"}),t.content&&yt.createElement(Ut,{className:"DocSearch-Hit-path",hit:t,attribute:"content"})),t.hierarchy[t.type]&&("lvl2"===t.type||"lvl3"===t.type||"lvl4"===t.type||"lvl5"===t.type||"lvl6"===t.type)&&yt.createElement("div",{className:"DocSearch-Hit-content-wrapper"},yt.createElement(Ut,{className:"DocSearch-Hit-title",hit:t,attribute:"hierarchy.".concat(t.type)}),yt.createElement(Ut,{className:"DocSearch-Hit-path",hit:t,attribute:"hierarchy.lvl1"})),"content"===t.type&&yt.createElement("div",{className:"DocSearch-Hit-content-wrapper"},yt.createElement(Ut,{className:"DocSearch-Hit-title",hit:t,attribute:"content"}),yt.createElement(Ut,{className:"DocSearch-Hit-path",hit:t,attribute:"hierarchy.lvl1"})),o({item:t,runDeleteTransition:function(e){f(!0),d.current=e},runFavoriteTransition:function(e){v(!0),d.current=e}}))))}var zt=/(<mark>|<\/mark>)/g,Wt=RegExp(zt.source);function Qt(e){var t,r,n=e;if(!n.__docsearch_parent&&!e._highlightResult)return e.hierarchy.lvl0;var o=((n.__docsearch_parent?null===(t=n.__docsearch_parent)||void 0===t||null===(t=t._highlightResult)||void 0===t||null===(t=t.hierarchy)||void 0===t?void 0:t.lvl0:null===(r=e._highlightResult)||void 0===r||null===(r=r.hierarchy)||void 0===r?void 0:r.lvl0)||{}).value;return o&&Wt.test(o)?o.replace(zt,""):o}function Zt(){return Zt=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},Zt.apply(this,arguments)}function Gt(e){return yt.createElement("div",{className:"DocSearch-Dropdown-Container"},e.state.collections.map((function(t){if(0===t.items.length)return null;var r=Qt(t.items[0]);return yt.createElement($t,Zt({},e,{key:t.source.sourceId,title:r,collection:t,renderIcon:function(e){var r,n=e.item,o=e.index;return yt.createElement(yt.Fragment,null,n.__docsearch_parent&&yt.createElement("svg",{className:"DocSearch-Hit-Tree",viewBox:"0 0 24 54"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},n.__docsearch_parent!==(null===(r=t.items[o+1])||void 0===r?void 0:r.__docsearch_parent)?yt.createElement("path",{d:"M8 6v21M20 27H8.3"}):yt.createElement("path",{d:"M8 6v42M20 27H8.3"}))),yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Ct,{type:n.type})))},renderAction:function(){return yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement(Tt,null))}}))})),e.resultsFooterComponent&&yt.createElement("section",{className:"DocSearch-HitsFooter"},yt.createElement(e.resultsFooterComponent,{state:e.state})))}function Xt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("g",{stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"},yt.createElement("path",{d:"M3.18 6.6a8.23 8.23 0 1112.93 9.94h0a8.23 8.23 0 01-11.63 0"}),yt.createElement("path",{d:"M6.44 7.25H2.55V3.36M10.45 6v5.6M10.45 11.6L13 13"})))}function Yt(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M10 14.2L5 17l1-5.6-4-4 5.5-.7 2.5-5 2.5 5 5.6.8-4 4 .9 5.5z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinejoin:"round"}))}function er(){return yt.createElement("svg",{width:"20",height:"20",viewBox:"0 0 20 20"},yt.createElement("path",{d:"M10 10l5.09-5.09L10 10l5.09 5.09L10 10zm0 0L4.91 4.91 10 10l-5.09 5.09L10 10z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}var tr=["translations"];function rr(){return rr=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},rr.apply(this,arguments)}function nr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function or(e){var t=e.translations,r=void 0===t?{}:t,n=nr(e,tr),o=r.recentSearchesTitle,i=void 0===o?"Recent":o,a=r.noRecentSearchesText,c=void 0===a?"No recent searches":a,l=r.saveRecentSearchButtonTitle,u=void 0===l?"Save this search":l,s=r.removeRecentSearchButtonTitle,f=void 0===s?"Remove this search from history":s,m=r.favoriteSearchesTitle,p=void 0===m?"Favorite":m,v=r.removeFavoriteSearchButtonTitle,d=void 0===v?"Remove this search from favorites":v;return"idle"===n.state.status&&!1===n.hasCollections?n.disableUserPersonalization?null:yt.createElement("div",{className:"DocSearch-StartScreen"},yt.createElement("p",{className:"DocSearch-Help"},c)):!1===n.hasCollections?null:yt.createElement("div",{className:"DocSearch-Dropdown-Container"},yt.createElement($t,rr({},n,{title:i,collection:n.state.collections[0],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Xt,null))},renderAction:function(e){var t=e.item,r=e.runFavoriteTransition,o=e.runDeleteTransition;return yt.createElement(yt.Fragment,null,yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:u,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.add(t),n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(Yt,null))),yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:f,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),o((function(){n.recentSearches.remove(t),n.refresh()}))}},yt.createElement(er,null))))}})),yt.createElement($t,rr({},n,{title:p,collection:n.state.collections[1],renderIcon:function(){return yt.createElement("div",{className:"DocSearch-Hit-icon"},yt.createElement(Yt,null))},renderAction:function(e){var t=e.item,r=e.runDeleteTransition;return yt.createElement("div",{className:"DocSearch-Hit-action"},yt.createElement("button",{className:"DocSearch-Hit-action-button",title:d,type:"submit",onClick:function(e){e.preventDefault(),e.stopPropagation(),r((function(){n.favoriteSearches.remove(t),n.refresh()}))}},yt.createElement(er,null)))}})))}var ir=["translations"];function ar(){return ar=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},ar.apply(this,arguments)}function cr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var lr=yt.memo((function(e){var t=e.translations,r=void 0===t?{}:t,n=cr(e,ir);if("error"===n.state.status)return yt.createElement(wt,{translations:null==r?void 0:r.errorScreen});var o=n.state.collections.some((function(e){return e.items.length>0}));return n.state.query?!1===o?yt.createElement(kt,ar({},n,{translations:null==r?void 0:r.noResultsScreen})):yt.createElement(Gt,n):yt.createElement(or,ar({},n,{hasCollections:o,translations:null==r?void 0:r.startScreen}))}),(function(e,t){return"loading"===t.state.status||"stalled"===t.state.status}));function ur(){return yt.createElement("svg",{viewBox:"0 0 38 38",stroke:"currentColor",strokeOpacity:".5"},yt.createElement("g",{fill:"none",fillRule:"evenodd"},yt.createElement("g",{transform:"translate(1 1)",strokeWidth:"2"},yt.createElement("circle",{strokeOpacity:".3",cx:"18",cy:"18",r:"18"}),yt.createElement("path",{d:"M36 18c0-9.94-8.06-18-18-18"},yt.createElement("animateTransform",{attributeName:"transform",type:"rotate",from:"0 18 18",to:"360 18 18",dur:"1s",repeatCount:"indefinite"})))))}var sr=r(9188),fr=["translations"];function mr(){return mr=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},mr.apply(this,arguments)}function pr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function vr(e){var t=e.translations,r=void 0===t?{}:t,n=pr(e,fr),o=r.resetButtonTitle,i=void 0===o?"Clear the query":o,a=r.resetButtonAriaLabel,c=void 0===a?"Clear the query":a,l=r.cancelButtonText,u=void 0===l?"Cancel":l,s=r.cancelButtonAriaLabel,f=void 0===s?"Cancel":s,m=r.searchInputLabel,p=void 0===m?"Search":m,v=n.getFormProps({inputElement:n.inputRef.current}).onReset;return yt.useEffect((function(){n.autoFocus&&n.inputRef.current&&n.inputRef.current.focus()}),[n.autoFocus,n.inputRef]),yt.useEffect((function(){n.isFromSelection&&n.inputRef.current&&n.inputRef.current.select()}),[n.isFromSelection,n.inputRef]),yt.createElement(yt.Fragment,null,yt.createElement("form",{className:"DocSearch-Form",onSubmit:function(e){e.preventDefault()},onReset:v},yt.createElement("label",mr({className:"DocSearch-MagnifierLabel"},n.getLabelProps()),yt.createElement(sr.W,null),yt.createElement("span",{className:"DocSearch-VisuallyHiddenForAccessibility"},p)),yt.createElement("div",{className:"DocSearch-LoadingIndicator"},yt.createElement(ur,null)),yt.createElement("input",mr({className:"DocSearch-Input",ref:n.inputRef},n.getInputProps({inputElement:n.inputRef.current,autoFocus:n.autoFocus,maxLength:ht}))),yt.createElement("button",{type:"reset",title:i,className:"DocSearch-Reset","aria-label":c,hidden:!n.state.query},yt.createElement(er,null))),yt.createElement("button",{className:"DocSearch-Cancel",type:"reset","aria-label":f,onClick:n.onClose},u))}var dr=["_highlightResult","_snippetResult"];function yr(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function hr(e){return!1===function(){var e="__TEST_KEY__";try{return localStorage.setItem(e,""),localStorage.removeItem(e),!0}catch(t){return!1}}()?{setItem:function(){},getItem:function(){return[]}}:{setItem:function(t){return window.localStorage.setItem(e,JSON.stringify(t))},getItem:function(){var t=window.localStorage.getItem(e);return t?JSON.parse(t):[]}}}function br(e){var t=e.key,r=e.limit,n=void 0===r?5:r,o=hr(t),i=o.getItem().slice(0,n);return{add:function(e){var t=e,r=(t._highlightResult,t._snippetResult,yr(t,dr)),a=i.findIndex((function(e){return e.objectID===r.objectID}));a>-1&&i.splice(a,1),i.unshift(r),i=i.slice(0,n),o.setItem(i)},remove:function(e){i=i.filter((function(t){return t.objectID!==e.objectID})),o.setItem(i)},getAll:function(){return i}}}function gr(e){const t=`algoliasearch-client-js-${e.key}`;let r;const n=()=>(void 0===r&&(r=e.localStorage||window.localStorage),r),o=()=>JSON.parse(n().getItem(t)||"{}"),i=e=>{n().setItem(t,JSON.stringify(e))};return{get:(t,r,n={miss:()=>Promise.resolve()})=>Promise.resolve().then((()=>{(()=>{const t=e.timeToLive?1e3*e.timeToLive:null,r=o(),n=Object.fromEntries(Object.entries(r).filter((([,e])=>void 0!==e.timestamp)));if(i(n),!t)return;const a=Object.fromEntries(Object.entries(n).filter((([,e])=>{const r=(new Date).getTime();return!(e.timestamp+t<r)})));i(a)})();const r=JSON.stringify(t);return o()[r]})).then((e=>Promise.all([e?e.value:r(),void 0!==e]))).then((([e,t])=>Promise.all([e,t||n.miss(e)]))).then((([e])=>e)),set:(e,r)=>Promise.resolve().then((()=>{const i=o();return i[JSON.stringify(e)]={timestamp:(new Date).getTime(),value:r},n().setItem(t,JSON.stringify(i)),r})),delete:e=>Promise.resolve().then((()=>{const r=o();delete r[JSON.stringify(e)],n().setItem(t,JSON.stringify(r))})),clear:()=>Promise.resolve().then((()=>{n().removeItem(t)}))}}function Or(e){const t=[...e.caches],r=t.shift();return void 0===r?{get:(e,t,r={miss:()=>Promise.resolve()})=>t().then((e=>Promise.all([e,r.miss(e)]))).then((([e])=>e)),set:(e,t)=>Promise.resolve(t),delete:e=>Promise.resolve(),clear:()=>Promise.resolve()}:{get:(e,n,o={miss:()=>Promise.resolve()})=>r.get(e,n,o).catch((()=>Or({caches:t}).get(e,n,o))),set:(e,n)=>r.set(e,n).catch((()=>Or({caches:t}).set(e,n))),delete:e=>r.delete(e).catch((()=>Or({caches:t}).delete(e))),clear:()=>r.clear().catch((()=>Or({caches:t}).clear()))}}function Sr(e={serializable:!0}){let t={};return{get(r,n,o={miss:()=>Promise.resolve()}){const i=JSON.stringify(r);if(i in t)return Promise.resolve(e.serializable?JSON.parse(t[i]):t[i]);const a=n(),c=o&&o.miss||(()=>Promise.resolve());return a.then((e=>c(e))).then((()=>a))},set:(r,n)=>(t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)),delete:e=>(delete t[JSON.stringify(e)],Promise.resolve()),clear:()=>(t={},Promise.resolve())}}function jr(e){let t=e.length-1;for(;t>0;t--){const r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function wr(e,t){return t?(Object.keys(t).forEach((r=>{e[r]=t[r](e)})),e):e}function Er(e,...t){let r=0;return e.replace(/%s/g,(()=>encodeURIComponent(t[r++])))}const Pr="4.23.3",Ir={WithinQueryParameters:0,WithinHeaders:1};function Dr(e,t){const r=e||{},n=r.data||{};return Object.keys(r).forEach((e=>{-1===["timeout","headers","queryParameters","data","cacheable"].indexOf(e)&&(n[e]=r[e])})),{data:Object.entries(n).length>0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}const Ar={Read:1,Write:2,Any:3},kr={Up:1,Down:2,Timeouted:3},xr=12e4;function Cr(e,t=kr.Up){return{...e,status:t,lastUpdate:Date.now()}}function _r(e){return"string"==typeof e?{protocol:"https",url:e,accept:Ar.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||Ar.Any}}const Nr={Delete:"DELETE",Get:"GET",Post:"POST",Put:"PUT"};function Tr(e,t){return Promise.all(t.map((t=>e.get(t,(()=>Promise.resolve(Cr(t))))))).then((e=>{const r=e.filter((e=>function(e){return e.status===kr.Up||Date.now()-e.lastUpdate>xr}(e))),n=e.filter((e=>function(e){return e.status===kr.Timeouted&&Date.now()-e.lastUpdate<=xr}(e))),o=[...r,...n];return{getTimeout:(e,t)=>(0===n.length&&0===e?1:n.length+3+e)*t,statelessHosts:o.length>0?o.map((e=>_r(e))):t}}))}const qr=(e,t)=>(e=>{const t=e.status;return e.isTimedOut||(({isTimedOut:e,status:t})=>!e&&!~~t)(e)||2!=~~(t/100)&&4!=~~(t/100)})(e)?t.onRetry(e):(({status:e})=>2==~~(e/100))(e)?t.onSuccess(e):t.onFail(e);function Rr(e,t,r,n){const o=[],i=function(e,t){if(e.method===Nr.Get||void 0===e.data&&void 0===t.data)return;const r=Array.isArray(e.data)?e.data:{...e.data,...t.data};return JSON.stringify(r)}(r,n),a=function(e,t){const r={...e.headers,...t.headers},n={};return Object.keys(r).forEach((e=>{const t=r[e];n[e.toLowerCase()]=t})),n}(e,n),c=r.method,l=r.method!==Nr.Get?{}:{...r.data,...n.data},u={"x-algolia-agent":e.userAgent.value,...e.queryParameters,...l,...n.queryParameters};let s=0;const f=(t,l)=>{const m=t.pop();if(void 0===m)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:Fr(o)};const p={data:i,headers:a,method:c,url:Mr(m,r.path,u),connectTimeout:l(s,e.timeouts.connect),responseTimeout:l(s,n.timeout)},v=e=>{const r={request:p,response:e,host:m,triesLeft:t.length};return o.push(r),r},d={onSuccess:e=>function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e),onRetry(r){const n=v(r);return r.isTimedOut&&s++,Promise.all([e.logger.info("Retryable failure",Ur(n)),e.hostsCache.set(m,Cr(m,r.isTimedOut?kr.Timeouted:kr.Down))]).then((()=>f(t,l)))},onFail(e){throw v(e),function({content:e,status:t},r){let n=e;try{n=JSON.parse(e).message}catch(o){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(n,t,r)}(e,Fr(o))}};return e.requester.send(p).then((e=>qr(e,d)))};return Tr(e.hostsCache,t).then((e=>f([...e.statelessHosts].reverse(),e.getTimeout)))}function Lr(e){const t={value:`Algolia for JavaScript (${e})`,add(e){const r=`; ${e.segment}${void 0!==e.version?` (${e.version})`:""}`;return-1===t.value.indexOf(r)&&(t.value=`${t.value}${r}`),t}};return t}function Mr(e,t,r){const n=Hr(r);let o=`${e.protocol}://${e.url}/${"/"===t.charAt(0)?t.substr(1):t}`;return n.length&&(o+=`?${n}`),o}function Hr(e){return Object.keys(e).map((t=>{return Er("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function Fr(e){return e.map((e=>Ur(e)))}function Ur(e){const t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return{...e,request:{...e.request,headers:{...e.request.headers,...t}}}}const Br=e=>{const t=e.appId,r=function(e,t,r){const n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:()=>e===Ir.WithinHeaders?n:{},queryParameters:()=>e===Ir.WithinQueryParameters?n:{}}}(void 0!==e.authMode?e.authMode:Ir.WithinHeaders,t,e.apiKey),n=function(e){const{hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,hosts:l,queryParameters:u,headers:s}=e,f={hostsCache:t,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:a,userAgent:c,headers:s,queryParameters:u,hosts:l.map((e=>_r(e))),read(e,t){const r=Dr(t,f.timeouts.read),n=()=>Rr(f,f.hosts.filter((e=>!!(e.accept&Ar.Read))),e,r);if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();const o={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(o,(()=>f.requestsCache.get(o,(()=>f.requestsCache.set(o,n()).then((e=>Promise.all([f.requestsCache.delete(o),e])),(e=>Promise.all([f.requestsCache.delete(o),Promise.reject(e)]))).then((([e,t])=>t))))),{miss:e=>f.responsesCache.set(o,e)})},write:(e,t)=>Rr(f,f.hosts.filter((e=>!!(e.accept&Ar.Write))),e,Dr(t,f.timeouts.write))};return f}({hosts:[{url:`${t}-dsn.algolia.net`,accept:Ar.Read},{url:`${t}.algolia.net`,accept:Ar.Write}].concat(jr([{url:`${t}-1.algolianet.com`},{url:`${t}-2.algolianet.com`},{url:`${t}-3.algolianet.com`}])),...e,headers:{...r.headers(),"content-type":"application/x-www-form-urlencoded",...e.headers},queryParameters:{...r.queryParameters(),...e.queryParameters}}),o={transporter:n,appId:t,addAlgoliaAgent(e,t){n.userAgent.add({segment:e,version:t})},clearCache:()=>Promise.all([n.requestsCache.clear(),n.responsesCache.clear()]).then((()=>{}))};return wr(o,e.methods)},Vr=e=>(t,r)=>t.method===Nr.Get?e.transporter.read(t,r):e.transporter.write(t,r),Kr=e=>(t,r={})=>wr({transporter:e.transporter,appId:e.appId,indexName:t},r.methods),$r=e=>(t,r)=>{const n=t.map((e=>({...e,params:Hr(e.params||{})})));return e.transporter.read({method:Nr.Post,path:"1/indexes/*/queries",data:{requests:n},cacheable:!0},r)},Jr=e=>(t,r)=>Promise.all(t.map((t=>{const{facetName:n,facetQuery:o,...i}=t.params;return Kr(e)(t.indexName,{methods:{searchForFacetValues:Qr}}).searchForFacetValues(n,o,{...r,...i})}))),zr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n),Wr=e=>(t,r)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r),Qr=e=>(t,r,n)=>e.transporter.read({method:Nr.Post,path:Er("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n),Zr={Debug:1,Info:2,Error:3};const Gr=e=>(t,r)=>{const n=t.map((e=>({...e,threshold:e.threshold||0})));return e.transporter.read({method:Nr.Post,path:"1/indexes/*/recommendations",data:{requests:n},cacheable:!0},r)};function Xr(e,t,r){const n={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:e=>new Promise((t=>{const r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((t=>r.setRequestHeader(t,e.headers[t])));const n=(e,n)=>setTimeout((()=>{r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e),o=n(e.connectTimeout,"Connection timeout");let i;r.onreadystatechange=()=>{r.readyState>r.OPENED&&void 0===i&&(clearTimeout(o),i=n(e.responseTimeout,"Socket timeout"))},r.onerror=()=>{0===r.status&&(clearTimeout(o),clearTimeout(i),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=()=>{clearTimeout(o),clearTimeout(i),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))},logger:(o=Zr.Error,{debug:(e,t)=>(Zr.Debug>=o&&console.debug(e,t),Promise.resolve()),info:(e,t)=>(Zr.Info>=o&&console.info(e,t),Promise.resolve()),error:(e,t)=>(console.error(e,t),Promise.resolve())}),responsesCache:Sr(),requestsCache:Sr({serializable:!1}),hostsCache:Or({caches:[gr({key:`${Pr}-${e}`}),Sr()]}),userAgent:Lr(Pr).add({segment:"Browser",version:"lite"}),authMode:Ir.WithinQueryParameters};var o;return Br({...n,...r,methods:{search:$r,searchForFacetValues:Jr,multipleQueries:$r,multipleSearchForFacetValues:Jr,customRequest:Vr,initIndex:e=>t=>Kr(e)(t,{methods:{search:Wr,searchForFacetValues:Qr,findAnswers:zr}}),getRecommendations:Gr}})}Xr.version=Pr;const Yr=Xr;var en="3.6.0";function tn(){}function rn(e){return e}function nn(e){return 1===e.button||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey}function on(e,t,r){return e.reduce((function(e,n){var o=t(n);return e.hasOwnProperty(o)||(e[o]=[]),e[o].length<(r||5)&&e[o].push(n),e}),{})}var an=["footer","searchBox"];function cn(){return cn=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e},cn.apply(this,arguments)}function ln(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function un(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?ln(Object(r),!0).forEach((function(t){sn(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ln(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function sn(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function fn(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==r)return;var n,o,i=[],a=!0,c=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(l){c=!0,o=l}finally{try{a||null==r.return||r.return()}finally{if(c)throw o}}return i}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return mn(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);"Object"===r&&e.constructor&&(r=e.constructor.name);if("Map"===r||"Set"===r)return Array.from(e);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return mn(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function mn(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function pn(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function vn(e){var t=e.appId,r=e.apiKey,n=e.indexName,o=e.placeholder,i=void 0===o?"Search docs":o,a=e.searchParameters,c=e.maxResultsPerGroup,l=e.onClose,u=void 0===l?tn:l,s=e.transformItems,f=void 0===s?rn:s,m=e.hitComponent,p=void 0===m?St:m,v=e.resultsFooterComponent,d=void 0===v?function(){return null}:v,y=e.navigator,h=e.initialScrollY,b=void 0===h?0:h,g=e.transformSearchClient,O=void 0===g?rn:g,S=e.disableUserPersonalization,j=void 0!==S&&S,w=e.initialQuery,E=void 0===w?"":w,P=e.translations,I=void 0===P?{}:P,D=e.getMissingResultsUrl,A=e.insights,k=void 0!==A&&A,x=I.footer,C=I.searchBox,_=pn(I,an),N=fn(yt.useState({query:"",collections:[],completion:null,context:{},isOpen:!1,activeItemId:null,status:"idle"}),2),T=N[0],q=N[1],R=yt.useRef(null),L=yt.useRef(null),M=yt.useRef(null),H=yt.useRef(null),F=yt.useRef(null),U=yt.useRef(10),B=yt.useRef("undefined"!=typeof window?window.getSelection().toString().slice(0,ht):"").current,V=yt.useRef(E||B).current,K=function(e,t,r){return yt.useMemo((function(){var n=Yr(e,t);return n.addAlgoliaAgent("docsearch",en),!1===/docsearch.js \(.*\)/.test(n.transporter.userAgent.value)&&n.addAlgoliaAgent("docsearch-react",en),r(n)}),[e,t,r])}(t,r,O),$=yt.useRef(br({key:"__DOCSEARCH_FAVORITE_SEARCHES__".concat(n),limit:10})).current,J=yt.useRef(br({key:"__DOCSEARCH_RECENT_SEARCHES__".concat(n),limit:0===$.getAll().length?7:4})).current,z=yt.useCallback((function(e){if(!j){var t="content"===e.type?e.__docsearch_parent:e;t&&-1===$.getAll().findIndex((function(e){return e.objectID===t.objectID}))&&J.add(t)}}),[$,J,j]),W=yt.useCallback((function(e){if(T.context.algoliaInsightsPlugin&&e.__autocomplete_id){var t=e,r={eventName:"Item Selected",index:t.__autocomplete_indexName,items:[t],positions:[e.__autocomplete_id],queryID:t.__autocomplete_queryID};T.context.algoliaInsightsPlugin.insights.clickedObjectIDsAfterSearch(r)}}),[T.context.algoliaInsightsPlugin]),Q=yt.useMemo((function(){return dt({id:"docsearch",defaultActiveItemId:0,placeholder:i,openOnFocus:!0,initialState:{query:V,context:{searchSuggestions:[]}},insights:k,navigator:y,onStateChange:function(e){q(e.state)},getSources:function(e){var o=e.query,i=e.state,l=e.setContext,s=e.setStatus;if(!o)return j?[]:[{sourceId:"recentSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),nn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return J.getAll()}},{sourceId:"favoriteSearches",onSelect:function(e){var t=e.item,r=e.event;z(t),nn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return $.getAll()}}];var m=Boolean(k);return K.search([{query:o,indexName:n,params:un({attributesToRetrieve:["hierarchy.lvl0","hierarchy.lvl1","hierarchy.lvl2","hierarchy.lvl3","hierarchy.lvl4","hierarchy.lvl5","hierarchy.lvl6","content","type","url"],attributesToSnippet:["hierarchy.lvl1:".concat(U.current),"hierarchy.lvl2:".concat(U.current),"hierarchy.lvl3:".concat(U.current),"hierarchy.lvl4:".concat(U.current),"hierarchy.lvl5:".concat(U.current),"hierarchy.lvl6:".concat(U.current),"content:".concat(U.current)],snippetEllipsisText:"\u2026",highlightPreTag:"<mark>",highlightPostTag:"</mark>",hitsPerPage:20,clickAnalytics:m},a)}]).catch((function(e){throw"RetryError"===e.name&&s("error"),e})).then((function(e){var o=e.results[0],a=o.hits,s=o.nbHits,p=on(a,(function(e){return Qt(e)}),c);i.context.searchSuggestions.length<Object.keys(p).length&&l({searchSuggestions:Object.keys(p)}),l({nbHits:s});var v={};return m&&(v={__autocomplete_indexName:n,__autocomplete_queryID:o.queryID,__autocomplete_algoliaCredentials:{appId:t,apiKey:r}}),Object.values(p).map((function(e,t){return{sourceId:"hits".concat(t),onSelect:function(e){var t=e.item,r=e.event;z(t),nn(r)||u()},getItemUrl:function(e){return e.item.url},getItems:function(){return Object.values(on(e,(function(e){return e.hierarchy.lvl1}),c)).map(f).map((function(e){return e.map((function(t){var r=null,n=e.find((function(e){return"lvl1"===e.type&&e.hierarchy.lvl1===t.hierarchy.lvl1}));return"lvl1"!==t.type&&n&&(r=n),un(un({},t),{},{__docsearch_parent:r},v)}))})).flat()}}}))}))}})}),[n,a,c,K,u,J,$,z,V,i,y,f,j,k,t,r]),Z=Q.getEnvironmentProps,G=Q.getRootProps,X=Q.refresh;return function(e){var t=e.getEnvironmentProps,r=e.panelElement,n=e.formElement,o=e.inputElement;yt.useEffect((function(){if(r&&n&&o){var e=t({panelElement:r,formElement:n,inputElement:o}),i=e.onTouchStart,a=e.onTouchMove;return window.addEventListener("touchstart",i),window.addEventListener("touchmove",a),function(){window.removeEventListener("touchstart",i),window.removeEventListener("touchmove",a)}}}),[t,r,n,o])}({getEnvironmentProps:Z,panelElement:H.current,formElement:M.current,inputElement:F.current}),function(e){var t=e.container;yt.useEffect((function(){if(t){var e=t.querySelectorAll("a[href]:not([disabled]), button:not([disabled]), input:not([disabled])"),r=e[0],n=e[e.length-1];return t.addEventListener("keydown",o),function(){t.removeEventListener("keydown",o)}}function o(e){"Tab"===e.key&&(e.shiftKey?document.activeElement===r&&(e.preventDefault(),n.focus()):document.activeElement===n&&(e.preventDefault(),r.focus()))}}),[t])}({container:R.current}),yt.useEffect((function(){return document.body.classList.add("DocSearch--active"),function(){var e,t;document.body.classList.remove("DocSearch--active"),null===(e=(t=window).scrollTo)||void 0===e||e.call(t,0,b)}}),[]),yt.useEffect((function(){window.matchMedia("(max-width: 768px)").matches&&(U.current=5)}),[]),yt.useEffect((function(){H.current&&(H.current.scrollTop=0)}),[T.query]),yt.useEffect((function(){V.length>0&&(X(),F.current&&F.current.focus())}),[V,X]),yt.useEffect((function(){function e(){if(L.current){var e=.01*window.innerHeight;L.current.style.setProperty("--docsearch-vh","".concat(e,"px"))}}return e(),window.addEventListener("resize",e),function(){window.removeEventListener("resize",e)}}),[]),yt.createElement("div",cn({ref:R},G({"aria-expanded":!0}),{className:["DocSearch","DocSearch-Container","stalled"===T.status&&"DocSearch-Container--Stalled","error"===T.status&&"DocSearch-Container--Errored"].filter(Boolean).join(" "),role:"button",tabIndex:0,onMouseDown:function(e){e.target===e.currentTarget&&u()}}),yt.createElement("div",{className:"DocSearch-Modal",ref:L},yt.createElement("header",{className:"DocSearch-SearchBar",ref:M},yt.createElement(vr,cn({},Q,{state:T,autoFocus:0===V.length,inputRef:F,isFromSelection:Boolean(V)&&V===B,translations:C,onClose:u}))),yt.createElement("div",{className:"DocSearch-Dropdown",ref:H},yt.createElement(lr,cn({},Q,{indexName:n,state:T,hitComponent:p,resultsFooterComponent:d,disableUserPersonalization:j,recentSearches:J,favoriteSearches:$,inputRef:F,translations:_,getMissingResultsUrl:D,onItemClick:function(e,t){W(e),z(e),nn(t)||u()}}))),yt.createElement("footer",{className:"DocSearch-Footer"},yt.createElement(Ot,{translations:x}))))}}}]); \ No newline at end of file diff --git a/assets/js/59b1a96c.30ee1534.js b/assets/js/59b1a96c.30ee1534.js deleted file mode 100644 index c052d6060..000000000 --- a/assets/js/59b1a96c.30ee1534.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[67],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>y});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){n(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function l(e,t){if(null==e)return{};var a,r,n=function(e,t){if(null==e)return{};var a,r,n={},i=Object.keys(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)a=i[r],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),p=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},m=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},c=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),u=p(a),c=n,y=u["".concat(s,".").concat(c)]||u[c]||d[c]||i;return a?r.createElement(y,o(o({ref:t},m),{},{components:a})):r.createElement(y,o({ref:t},m))}));function y(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=c;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:n,o[1]=l;for(var p=2;p<i;p++)o[p]=a[p];return r.createElement.apply(null,o)}return r.createElement.apply(null,a)}c.displayName="MDXCreateElement"},2075:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=a(7462),n=(a(7294),a(3905));const i={sidebar_position:0,sidebar_label:"\ud83d\udd25 Prologue",slug:"/",hide_table_of_contents:!0,description:"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.",keywords:["c++ orm","prologue","tinyorm"]},o="Prologue",l={unversionedId:"README",id:"README",title:"Prologue",description:"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.",source:"@site/docs/README.mdx",sourceDirName:".",slug:"/",permalink:"/",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/README.mdx",tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"\ud83d\udd25 Prologue",slug:"/",hide_table_of_contents:!0,description:"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.",keywords:["c++ orm","prologue","tinyorm"]},sidebar:"tinyormSidebar",next:{title:"\ud83d\udd27 Dependencies",permalink:"/dependencies"}},s={},p=[{value:"Documentation Sitemap",id:"documentation-sitemap",level:5},{value:"Current versions",id:"current-versions",level:5}],m={toc:p},u="wrapper";function d(e){let{components:t,...a}=e;return(0,n.kt)(u,(0,r.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"prologue"},"Prologue"),(0,n.kt)("p",null,"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the ",(0,n.kt)("inlineCode",{parentName:"p"},"QtCore")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"QtSql")," libraries."),(0,n.kt)("p",null,"The code is written in the modern C++20 way and is ",(0,n.kt)("strong",{parentName:"p"},"heavily")," tested with ",(0,n.kt)("strong",{parentName:"p"},"3366")," unit and functional tests. Almost all the query builder methods are unit tested. The TinyORM's query builder code and the code which is responsible for obtaining relationships, is tested by functional tests against all supported databases. The code coverage is good enough to guarantee API and behavior compatibility."),(0,n.kt)("admonition",{type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"For a quick look at what's inside, check out the ",(0,n.kt)("a",{parentName:"p",href:"/features-summary"},"Features Summary"),".")),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"If you don't want to use full ",(0,n.kt)("a",{parentName:"p",href:"/tinyorm/getting-started"},(0,n.kt)("inlineCode",{parentName:"a"},"ORM")),", then you can use only the ",(0,n.kt)("a",{parentName:"p",href:"/database/query-builder"},(0,n.kt)("inlineCode",{parentName:"a"},"Query Builder")),", which is outstanding. \ud83d\udd25 This way you can avoid writing raw SQL queries and your code will run on all ",(0,n.kt)("a",{parentName:"p",href:"/database/getting-started#introduction"},"supported databases"),".")),(0,n.kt)("h5",{id:"documentation-sitemap"},"Documentation Sitemap"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/dependencies"},"Dependencies")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/supported-compilers"},"Supported Compilers")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/database/getting-started"},"Database"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/database/getting-started"},"Getting Started")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/database/query-builder"},"Query Builder")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/database/migrations"},"Migrations")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/database/seeding"},"Seeding")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinyorm/getting-started"},"TinyORM"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinyorm/getting-started"},"Getting Started")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinyorm/relationships"},"Relationships")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinyorm/collections"},"Collections")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinyorm/casts"},"Casts")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinyorm/serialization"},"Serialization")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinydrivers/getting-started"},"TinyDrivers"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/tinydrivers/getting-started"},"Getting Started")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/building/tinyorm"},"Building"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/building/tinyorm"},"TinyORM")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/building/hello-world"},"Hello world")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/building/migrations"},"Migrations")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/features-summary"},"Features Summary")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/sponsors"},"Sponsors"))),(0,n.kt)("h5",{id:"current-versions"},"Current versions"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"TinyORM")," v0.37.3"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"tom")," v0.9.1"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"TinyDrivers")," v0.1.1"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"TinyMySql")," v0.1.1")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/59b1a96c.35b999b1.js b/assets/js/59b1a96c.35b999b1.js new file mode 100644 index 000000000..37a828e7d --- /dev/null +++ b/assets/js/59b1a96c.35b999b1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[485],{3398:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>c,frontMatter:()=>s,metadata:()=>d,toc:()=>o});var t=i(4848),r=i(8453);const s={sidebar_position:0,sidebar_label:"\ud83d\udd25 Prologue",slug:"/",hide_table_of_contents:!0,description:"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.",keywords:["c++ orm","prologue","tinyorm"]},a="Prologue",d={id:"README",title:"Prologue",description:"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.",source:"@site/docs/README.mdx",sourceDirName:".",slug:"/",permalink:"/",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"\ud83d\udd25 Prologue",slug:"/",hide_table_of_contents:!0,description:"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.",keywords:["c++ orm","prologue","tinyorm"]},sidebar:"tinyormSidebar",next:{title:"\ud83d\udd27 Dependencies",permalink:"/dependencies"}},l={},o=[{value:"Documentation Sitemap",id:"documentation-sitemap",level:5},{value:"Current versions",id:"current-versions",level:5}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h5:"h5",li:"li",p:"p",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"prologue",children:"Prologue"}),"\n",(0,t.jsxs)(n.p,{children:["TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the ",(0,t.jsx)(n.code,{children:"QtCore"})," and ",(0,t.jsx)(n.code,{children:"QtSql"})," libraries."]}),"\n",(0,t.jsxs)(n.p,{children:["The code is written in the modern C++20 way and is ",(0,t.jsx)(n.strong,{children:"heavily"})," tested with ",(0,t.jsx)(n.strong,{children:"3366"})," unit and functional tests. Almost all the query builder methods are unit tested. The TinyORM's query builder code and the code which is responsible for obtaining relationships, is tested by functional tests against all supported databases. The code coverage is good enough to guarantee API and behavior compatibility."]}),"\n",(0,t.jsx)(n.admonition,{type:"tip",children:(0,t.jsxs)(n.p,{children:["For a quick look at what's inside, check out the ",(0,t.jsx)(n.a,{href:"/features-summary",children:"Features Summary"}),"."]})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["If you don't want to use full ",(0,t.jsx)(n.a,{href:"/tinyorm/getting-started",children:(0,t.jsx)(n.code,{children:"ORM"})}),", then you can use only the ",(0,t.jsx)(n.a,{href:"/database/query-builder",children:(0,t.jsx)(n.code,{children:"Query Builder"})}),", which is outstanding. \ud83d\udd25 This way you can avoid writing raw SQL queries and your code will run on all ",(0,t.jsx)(n.a,{href:"/database/getting-started#introduction",children:"supported databases"}),"."]})}),"\n",(0,t.jsx)(n.h5,{id:"documentation-sitemap",children:"Documentation Sitemap"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/dependencies",children:"Dependencies"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/supported-compilers",children:"Supported Compilers"})}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"/database/getting-started",children:"Database"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/database/getting-started",children:"Getting Started"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/database/query-builder",children:"Query Builder"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/database/migrations",children:"Migrations"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/database/seeding",children:"Seeding"})}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"/tinyorm/getting-started",children:"TinyORM"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/tinyorm/getting-started",children:"Getting Started"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/tinyorm/relationships",children:"Relationships"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/tinyorm/collections",children:"Collections"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/tinyorm/casts",children:"Casts"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/tinyorm/serialization",children:"Serialization"})}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"/tinydrivers/getting-started",children:"TinyDrivers"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/tinydrivers/getting-started",children:"Getting Started"})}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"/building/tinyorm",children:"Building"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/building/tinyorm",children:"TinyORM"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/building/hello-world",children:"Hello world"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/building/migrations",children:"Migrations"})}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/features-summary",children:"Features Summary"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.a,{href:"/sponsors",children:"Sponsors"})}),"\n"]}),"\n",(0,t.jsx)(n.h5,{id:"current-versions",children:"Current versions"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"TinyORM"})," v0.37.3"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"tom"})," v0.9.1"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"TinyDrivers"})," v0.1.1"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.strong,{children:"TinyMySql"})," v0.1.1"]}),"\n"]})]})}function c(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}},8453:(e,n,i)=>{i.d(n,{R:()=>a,x:()=>d});var t=i(6540);const r={},s=t.createContext(r);function a(e){const n=t.useContext(s);return t.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(r):e.components||r:a(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/5b254f70.287f094d.js b/assets/js/5b254f70.287f094d.js deleted file mode 100644 index d4894921f..000000000 --- a/assets/js/5b254f70.287f094d.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[116],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>c});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function r(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},l=Object.keys(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a<l.length;a++)n=l[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,m=r(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,c=p["".concat(s,".").concat(h)]||p[h]||u[h]||l;return n?a.createElement(c,o(o({ref:t},m),{},{components:n})):a.createElement(c,o({ref:t},m))}));function c(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,o=new Array(l);o[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[p]="string"==typeof e?e:i,o[1]=r;for(var d=2;d<l;d++)o[d]=n[d];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},7923:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>l,metadata:()=>r,toc:()=>d});var a=n(7462),i=(n(7294),n(3905));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"]},o="TinyORM: Getting Started",r={unversionedId:"tinyorm/getting-started",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,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/tinyorm/getting-started.mdx",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"}},s={},d=[{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}],m={toc:d},p="wrapper";function u(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,a.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"tinyorm-getting-started"},"TinyORM: Getting Started"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#generating-model-classes"},"Generating Model Classes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#tinyorm-model-conventions"},"TinyORM Model Conventions"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#table-names"},"Table Names")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#primary-keys"},"Primary Keys")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#timestamps"},"Timestamps")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#database-connections"},"Database Connections")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#default-attribute-values"},"Default Attribute Values")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#retrieving-models"},"Retrieving Models"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#containers"},"Containers")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#chunking-results"},"Chunking Results")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#advanced-subqueries"},"Advanced Subqueries")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#retrieving-single-models-and-aggregates"},"Retrieving Single Models / Aggregates"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#retrieving-or-creating-models"},"Retrieving Or Creating Models")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#retrieving-aggregates"},"Retrieving Aggregates")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#inserting-and-updating-models"},"Inserting & Updating Models"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#inserts"},"Inserts")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#updates"},"Updates")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#mass-assignment"},"Mass Assignment")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#upserts"},"Upserts")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#deleting-models"},"Deleting Models"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#soft-deleting"},"Soft Deleting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#querying-soft-deleted-models"},"Querying Soft Deleted Models")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#truncate-table"},"Truncate Table")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#replicating-models"},"Replicating Models")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#comparing-models"},"Comparing Models"))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,'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.'),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"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.kt)("a",{parentName:"p",href:"/database/getting-started#configuration"},"database configuration documentation"),".")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"If you want to see a model in which are used all possible TinyORM features you can look at the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/tests/models/models/torrent.hpp"},(0,i.kt)("inlineCode",{parentName:"a"},"torrent.hpp"))," in the TinyORM's tests, this ",(0,i.kt)("inlineCode",{parentName:"p"},"Models::Torrent")," class serves also as a showcase, so all possible features are defined in it.")),(0,i.kt)("h2",{id:"generating-model-classes"},"Generating Model Classes"),(0,i.kt)("p",null,"To get started, let's create the simplest TinyORM model. Models typically live in the ",(0,i.kt)("inlineCode",{parentName:"p"},"database\\models")," directory and extend the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Model")," class. You may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"make:model")," command to generate a new model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:model User\n")),(0,i.kt)("p",null,"If you would like to generate a database ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations"},"migration")," or ",(0,i.kt)("a",{parentName:"p",href:"/database/seeding"},"seeder")," when you generate the model, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"--migration"),"/",(0,i.kt)("inlineCode",{parentName:"p"},"-m")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"--seeder"),"/",(0,i.kt)("inlineCode",{parentName:"p"},"-s")," options:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:model User --migration --seeder\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"--force")," option forces overwriting of existing files:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:model User --migration --seeder --force\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"make:model")," help command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:model --help\n")),(0,i.kt)("p",null,"Few examples:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-powershell"},"# 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")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Writing a ",(0,i.kt)("inlineCode",{parentName:"p"},"make:model")," commands is superb with the ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations#tab-completion"},"tab completion"),".")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"--path")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"--realpath")," options work the same as for the ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations#generating-migrations"},(0,i.kt)("inlineCode",{parentName:"a"},"make:migration"))," command.")),(0,i.kt)("h2",{id:"tinyorm-model-conventions"},"TinyORM Model Conventions"),(0,i.kt)("p",null,"Let's examine a basic model class and discuss some of TinyORM's key conventions:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#pragma once\n#ifndef FLIGHT_HPP\n#define FLIGHT_HPP\n\n#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\n{\n friend Model;\n\n using Model::Model;\n};\n\n#endif // FLIGHT_HPP\n")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," source tree contains the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/tests/models/models/torrent.hpp#L43"},(0,i.kt)("inlineCode",{parentName:"a"},"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.")),(0,i.kt)("h3",{id:"table-names"},"Table Names"),(0,i.kt)("p",null,"After glancing at the example above, you may have noticed that we did not tell TinyORM which database table corresponds to our ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"Flight")," model stores records in the ",(0,i.kt)("inlineCode",{parentName:"p"},"flights")," table, while an ",(0,i.kt)("inlineCode",{parentName:"p"},"AirTrafficController")," model would store records in an ",(0,i.kt)("inlineCode",{parentName:"p"},"air_traffic_controllers")," table."),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"u_table")," data member on the model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The table associated with the model. */\n QString u_table {"flights"};\n};\n')),(0,i.kt)("h3",{id:"primary-keys"},"Primary Keys"),(0,i.kt)("p",null,"TinyORM will also assume that each model's corresponding database table has a primary key column named ",(0,i.kt)("inlineCode",{parentName:"p"},"id"),". If necessary, you may define a private ",(0,i.kt)("inlineCode",{parentName:"p"},"u_primaryKey")," data member on your model to specify a different column that serves as your model's primary key:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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')),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"u_incrementing")," data member on your model that is set to ",(0,i.kt)("inlineCode",{parentName:"p"},"false"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Non-numeric primary keys are not currently implemented, ",(0,i.kt)("inlineCode",{parentName:"p"},"u_incrementing")," code logic is fully implemented, but it is only one part to make it fully work.")),(0,i.kt)("h4",{id:"composite-primary-keys"},'"Composite" Primary Keys'),(0,i.kt)("p",null,'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.'),(0,i.kt)("h3",{id:"timestamps"},"Timestamps"),(0,i.kt)("p",null,"By default, TinyORM expects ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"u_timestamps")," data member on your model with a value of ",(0,i.kt)("inlineCode",{parentName:"p"},"false"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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")),(0,i.kt)("a",{id:"timestamps-u_dates"}),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dates")," static data member controls the casting of timestamp attributes. The ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," columns are automatically added to the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dates")," string list when the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_timestamps")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),". Also, the ",(0,i.kt)("a",{parentName:"p",href:"#soft-deleting"},(0,i.kt)("inlineCode",{parentName:"a"},"Soft Deleting"))," feature adds the ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," column to the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dates"),"."),(0,i.kt)("p",null,"You may add additional columns to the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dates")," list. After that, these columns will be automatically formatted using the format in the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dateFormat")," data member during the ",(0,i.kt)("inlineCode",{parentName:"p"},"setAttribute")," method call:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'class Flight final : public Model<Flight>\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')),(0,i.kt)("p",null,"If you need to customize the format of your model's timestamps, set the private ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"QDateTime")," documentation:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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')),(0,i.kt)("p",null,"If you need to customize the format of your model's time columns, set the private ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"QTime")," documentation. The default value for ",(0,i.kt)("inlineCode",{parentName:"p"},"u_timeFormat")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"HH:mm:ss"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'/*! The storage format of the model\'s time columns. */\nQString u_timeFormat {"HH:mm:ss.zzz"};\n')),(0,i.kt)("p",null,"The default value for datetime or timestamp columns is ",(0,i.kt)("inlineCode",{parentName:"p"},"yyyy-MM-dd HH:mm:ss")," and for time columns is ",(0,i.kt)("inlineCode",{parentName:"p"},"HH:mm:ss"),"."),(0,i.kt)("h5",{id:"unix-timestamps"},"Unix timestamps"),(0,i.kt)("p",null,"You can set the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dateFormat")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"U")," if you want to store dates in the database as unix timestamps:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"QString u_dateFormat {QLatin1Char('U')};\n")),(0,i.kt)("p",null,"In this case ",(0,i.kt)("strong",{parentName:"p"},"all")," date attributes set in the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dates")," will be handled as unix timestamps, so also the ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamp attributes."),(0,i.kt)("p",null,"To create unix timestamp columns using the ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations"},"tom migrations")," you should use ",(0,i.kt)("inlineCode",{parentName:"p"},"integer")," types:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("flights", [](Blueprint &table)\n{\n table.bigInteger("created_at").nullable();\n table.bigInteger("updated_at").nullable();\n});\n')),(0,i.kt)("h5",{id:"custom-timestamp-column-names"},"Custom timestamp column names"),(0,i.kt)("p",null,"If you need to customize the names of the columns used to store the timestamps, you may define ",(0,i.kt)("inlineCode",{parentName:"p"},"CREATED_AT")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"UPDATED_AT")," private static getter methods on your model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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')),(0,i.kt)("h4",{id:"touching-timestamps"},"Touching timestamps"),(0,i.kt)("p",null,"You can explicitly touch timestamps using the ",(0,i.kt)("inlineCode",{parentName:"p"},"touch")," method defined on the Model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flight = Flight::find(1);\n\nflight->touch();\nflight->touch("added_on"); // Custom column name\n')),(0,i.kt)("p",null,"You can also touch multiple rows at once using the ",(0,i.kt)("inlineCode",{parentName:"p"},"touch")," method defined on the TinyBuilder:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto [affected, query] = Flight::whereEq("status", "new")->touch();\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"touch")," method may also be called when building a ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/relationships"},"relationship")," query:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'flight->history()->touch();\nflight->history()->whereEq("status", "new").touch();\n')),(0,i.kt)("h3",{id:"database-connections"},"Database Connections"),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"u_connection")," private data member on the model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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')),(0,i.kt)("p",null,"In special cases, when you want to query the database through a different connection, you can use ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::on")," method, which takes the connection name as the first argument:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto user = User::on("sqlite")->find(1);\n')),(0,i.kt)("h2",{id:"default-attribute-values"},"Default Attribute Values"),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"u_attributes")," data member on your model, it has to be ",(0,i.kt)("strong",{parentName:"p"},"static")," and can be ",(0,i.kt)("strong",{parentName:"p"},"const"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <QDateTime>\n\n#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The model\'s default values for attributes. */\n inline static const QVector<AttributeItem> u_attributes {\n {"delayed", false},\n {"progress", 0},\n {"added_on", QDateTime::currentDateTimeUtc()},\n };\n};\n')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Use the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::instance")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::instanceHeap")," related methods to instantiate a model that contains a ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," in Default Attribute Values, or if attributes you want to pass to the model's constructor contain a ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance ",(0,i.kt)("small",null,"(problem is described below)"),".")),(0,i.kt)("h5",{id:"qdatetime-and-connection-name-problem"},"QDateTime and connection name problem"),(0,i.kt)("p",null,"If your Default Attribute Values or attributes that you can pass to the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model")," constructor contain the ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance, then ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," throws an exception. You have to use the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::instance")," related methods to create such a Model."),(0,i.kt)("p",null,"Virtually everything important is covered in the thrown exception, but let me summarize it. The problem is that the ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance is converted to a string based on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::u_dateFormat"),", or if not defined, the date format from ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Query::Grammars::Grammar")," will be used. This ",(0,i.kt)("inlineCode",{parentName:"p"},"QueryGrammar")," is obtained from ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::DatabaseConnection")," and because of that TinyORM needs to know the ",(0,i.kt)("strong",{parentName:"p"},"connection name")," and that's the crux of this problem. You can define your connection name using the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::u_connection")," in your derived model class, but this derived model ",(0,i.kt)("strong",{parentName:"p"},"is not yet initialized"),", so the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::u_connection")," is also not initialized."),(0,i.kt)("p",null,"So if the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::u_connection")," is not yet initialized, ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," can't obtain the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::DatabaseConnection")," -> ",(0,i.kt)("inlineCode",{parentName:"p"},"QueryGrammar")," -> ",(0,i.kt)("inlineCode",{parentName:"p"},"dateFormat"),"."),(0,i.kt)("h2",{id:"retrieving-models"},"Retrieving Models"),(0,i.kt)("p",null,"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.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builder")," allowing you to fluently query the database table associated with the model. The model's ",(0,i.kt)("inlineCode",{parentName:"p"},"all")," method will retrieve all of the records from the model's associated database table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include "models/flight.hpp"\n\nfor (const auto &flight : Flight::all())\n qDebug() << flight["name"].toString();\n')),(0,i.kt)("h4",{id:"building-queries"},"Building Queries"),(0,i.kt)("p",null,"The TinyORM ",(0,i.kt)("inlineCode",{parentName:"p"},"all")," method will return all of the results in the model's table. However, since each TinyORM model serves as a ",(0,i.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builder"),", you may add additional constraints to queries and then invoke the ",(0,i.kt)("inlineCode",{parentName:"p"},"get")," method to retrieve the results:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flights = Flight::whereEq("active", 1)\n ->orderBy("name")\n .take(10)\n .get();\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Since TinyORM models are query builders, you should review all of the methods provided by TinyORM's ",(0,i.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builder"),". You may use any of these methods when writing your TinyORM queries.")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"All the static methods defined on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Model<Derived, AllRelations...>")," class, which start building queries like ",(0,i.kt)("inlineCode",{parentName:"p"},"where"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"latest"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"oldest"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"with"),", ... return ",(0,i.kt)("inlineCode",{parentName:"p"},"std::unique_ptr<TinyBuilder<Model>>"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyBuilder = Orm::Tiny::Builder")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"Model")," template argument is queried model class.")),(0,i.kt)("h4",{id:"refreshing-models"},"Refreshing Models"),(0,i.kt)("p",null,'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.kt)("inlineCode",{parentName:"p"},"fresh")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"refresh")," methods. The ",(0,i.kt)("inlineCode",{parentName:"p"},"fresh")," method will re-retrieve the model from the database. The existing model instance will not be affected:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flight = Flight::whereEq("number", "FR 900")->first();\n\nauto freshFlight = flight->fresh();\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flight = Flight::whereEq("number", "FR 900")->first();\n\nflight->setAttribute("number", "FR 456");\n\nflight->refresh();\n\nflight->getAttribute("number"); // "FR 900"\n')),(0,i.kt)("h3",{id:"containers"},"Containers"),(0,i.kt)("p",null,"As we have seen, TinyORM methods like ",(0,i.kt)("inlineCode",{parentName:"p"},"all")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"get")," retrieve multiple records from the database. Since these methods return a ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<Model>"),", you can iterate it like any other container with the ",(0,i.kt)("a",{parentName:"p",href:"https://en.cppreference.com/w/cpp/language/range-for"},"Range-based for loop"),", ",(0,i.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/containers.html#stl-style-iterators"},"STL-Style Iterators"),", ",(0,i.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/containers.html#java-style-iterators"},"Java-Style Iterators")," or ",(0,i.kt)("a",{parentName:"p",href:"https://www.walletfox.com/course/quickref_range_v3.php"},"Ranges"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include "models/flight.hpp"\n\nfor (const auto &flight : Flight::all())\n qDebug() << flight["name"].toString();\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"An ",(0,i.kt)("inlineCode",{parentName:"p"},"all")," method is defined on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Model<Derived, AllRelations...>")," class and ",(0,i.kt)("inlineCode",{parentName:"p"},"get")," method is defined on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Builder"),", may be also referred as ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyBuilder"),", and on the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Query::Builder")," alias ",(0,i.kt)("inlineCode",{parentName:"p"},"QueryBuilder"),".")),(0,i.kt)("h3",{id:"chunking-results"},"Chunking Results"),(0,i.kt)("p",null,"Your application may run out of memory if you attempt to load tens of thousands of TinyORM records via the ",(0,i.kt)("inlineCode",{parentName:"p"},"all")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"get")," methods. Instead of using these methods, the ",(0,i.kt)("inlineCode",{parentName:"p"},"chunk")," method may be used to process large numbers of models more efficiently."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"chunk")," method will provide significantly reduced memory usage when working with a large number of models:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"Flight::chunk(200, [](QVector<Flight> &&flights, const int /*unused*/)\n{\n for (auto &&flight : flights) {\n //\n }\n\n return true;\n});\n")),(0,i.kt)("p",null,"The first argument passed to the ",(0,i.kt)("inlineCode",{parentName:"p"},"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.'),(0,i.kt)("p",null,"If you are filtering the results of the ",(0,i.kt)("inlineCode",{parentName:"p"},"chunk")," method based on a column that you will also be updating while iterating over the results, you should use the ",(0,i.kt)("inlineCode",{parentName:"p"},"chunkById")," method. Using the ",(0,i.kt)("inlineCode",{parentName:"p"},"chunk")," method in these scenarios could lead to unexpected and inconsistent results. Internally, the ",(0,i.kt)("inlineCode",{parentName:"p"},"chunkById")," method will always retrieve models with an ",(0,i.kt)("inlineCode",{parentName:"p"},"id")," column greater than the last model in the previous chunk:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Flight::whereEq("departed", true)\n ->chunkById(200, [](QVector<Flight> &&flights, const int /*unused*/)\n {\n for (auto &&flight : flights)\n flight.update({{"departed", false}});\n\n return true;\n });\n')),(0,i.kt)("h3",{id:"advanced-subqueries"},"Advanced Subqueries"),(0,i.kt)("h4",{id:"subquery-selects"},"Subquery Selects"),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"destinations")," and a table of ",(0,i.kt)("inlineCode",{parentName:"p"},"flights")," to destinations. The ",(0,i.kt)("inlineCode",{parentName:"p"},"flights")," table contains an ",(0,i.kt)("inlineCode",{parentName:"p"},"arrived_at")," column which indicates when the flight arrived at the destination."),(0,i.kt)("p",null,"Using the subquery functionality available to the query builder's ",(0,i.kt)("inlineCode",{parentName:"p"},"select")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"addSelect")," methods, we can select all of the ",(0,i.kt)("inlineCode",{parentName:"p"},"destinations")," and the name of the flight that most recently arrived at that destination using a single query:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#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')),(0,i.kt)("h4",{id:"subquery-ordering"},"Subquery Ordering"),(0,i.kt)("p",null,"In addition, the query builder's ",(0,i.kt)("inlineCode",{parentName:"p"},"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:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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')),(0,i.kt)("h2",{id:"retrieving-single-models-and-aggregates"},"Retrieving Single Models / Aggregates"),(0,i.kt)("p",null,"In addition to retrieving all of the records matching a given query, you may also retrieve single records using the ",(0,i.kt)("inlineCode",{parentName:"p"},"find"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"first"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"firstWhere"),", or ",(0,i.kt)("inlineCode",{parentName:"p"},"firstWhereEq")," methods. Instead of returning a vector of models, these methods return a single model instance:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#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')),(0,i.kt)("p",null,"Sometimes you may wish to perform some other action if no results are found. The ",(0,i.kt)("inlineCode",{parentName:"p"},"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:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"auto flight = Flight::findOr(1, [] {\n // ...\n});\n\nauto flight = Flight::findOr<int>(1, [] {\n // ...\n return 10;\n});\n\nauto flight = Flight::findOr<std::optional<Flight>>(1, [] {\n // ...\n return Flight::find(10);\n});\n")),(0,i.kt)("p",null,"To obtain only a subset of the model's attributes you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"Model::only")," method, it returns the ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<AttributeItem>"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#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')),(0,i.kt)("h4",{id:"not-found-exceptions"},"Not Found Exceptions"),(0,i.kt)("p",null,"Sometimes you may wish to throw an exception if a model is not found. The ",(0,i.kt)("inlineCode",{parentName:"p"},"findOrFail")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"firstOrFail")," methods will retrieve the first result of the query; however, if no result is found, an ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::ModelNotFoundError")," will be thrown:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flight = Flight::findOrFail(1);\n\nauto flight = Flight::where("legs", ">", 3)->firstOrFail();\n')),(0,i.kt)("h3",{id:"retrieving-or-creating-models"},"Retrieving Or Creating Models"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WhereItem>")," argument with the optional second ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<Orm::AttributeItem>")," argument:"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"firstOrNew")," method, like ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"firstOrNew")," has not yet been persisted to the database. You will need to manually call the ",(0,i.kt)("inlineCode",{parentName:"p"},"save")," method to persist it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#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')),(0,i.kt)("h3",{id:"retrieving-aggregates"},"Retrieving Aggregates"),(0,i.kt)("p",null,"When interacting with TinyORM models, you may also use the ",(0,i.kt)("inlineCode",{parentName:"p"},"count"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"sum"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"max"),", and other ",(0,i.kt)("a",{parentName:"p",href:"/database/query-builder#aggregates"},"aggregate methods")," provided by the ",(0,i.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builder"),". As you might expect, these methods return a scalar value instead of a TinyORM model instance:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto count = Flight::whereEq("active", 1)->count();\n\nauto max = Flight::whereEq("active", 1)->max("price");\n')),(0,i.kt)("h2",{id:"inserting-and-updating-models"},"Inserting & Updating Models"),(0,i.kt)("h3",{id:"inserts"},"Inserts"),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"save")," method on the model instance:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include "models/flight.hpp"\n\n// Store a new flight in the database\nFlight flight;\nflight.setAttribute("name", "Slovakia to Czech");\nflight.save();\n')),(0,i.kt)("p",null,"In this example, we assign the ",(0,i.kt)("inlineCode",{parentName:"p"},"name")," attribute of the ",(0,i.kt)("inlineCode",{parentName:"p"},"Flight")," model instance. When we call the ",(0,i.kt)("inlineCode",{parentName:"p"},"save")," method, a record will be inserted into the database. The model's ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamps will automatically be set when the ",(0,i.kt)("inlineCode",{parentName:"p"},"save")," method is called, so there is no need to set them manually."),(0,i.kt)("p",null,"Alternatively, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"create")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include "models/flight.hpp"\n\nauto flight = Flight::create({\n {"name", "London to Paris"},\n});\n')),(0,i.kt)("p",null,"However, before using the ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method, you will need to specify either a ",(0,i.kt)("inlineCode",{parentName:"p"},"u_fillable")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("a",{parentName:"p",href:"#mass-assignment"},"mass assignment documentation"),"."),(0,i.kt)("h3",{id:"updates"},"Updates"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"save")," method. Again, the ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamp will automatically be updated, so there is no need to manually set its value:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include "models/flight.hpp"\n\nauto flight = Flight::find(1);\n\nflight->setAttribute("name", "Paris to London");\n\nflight->save();\n')),(0,i.kt)("h4",{id:"mass-updates"},"Mass Updates"),(0,i.kt)("p",null,"Updates can also be performed against models that match a given query. In this example, all flights that are ",(0,i.kt)("inlineCode",{parentName:"p"},"active")," and have a ",(0,i.kt)("inlineCode",{parentName:"p"},"destination")," of ",(0,i.kt)("inlineCode",{parentName:"p"},"San Diego")," will be marked as delayed:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Flight::whereEq("active", 1)\n ->whereEq("destination", "San Diego")\n .update({{"delayed", 1}});\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"update")," method expects the ",(0,i.kt)("inlineCode",{parentName:"p"},"QVector<Orm::UpdateItem>")," of column and value pairs representing the columns that should be updated."),(0,i.kt)("h4",{id:"examining-attribute-changes"},"Examining Attribute Changes"),(0,i.kt)("p",null,"TinyORM provides the ",(0,i.kt)("inlineCode",{parentName:"p"},"isDirty"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"isClean"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"wasChanged")," methods to examine the internal state of your model and determine how its attributes have changed from when the model was originally retrieved."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"isDirty")," method to determine if a particular attribute is dirty. The ",(0,i.kt)("inlineCode",{parentName:"p"},"isClean")," will determine if an attribute has remained unchanged since the model was retrieved. This method also accepts an optional attribute argument:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#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')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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')),(0,i.kt)("h3",{id:"mass-assignment"},"Mass Assignment"),(0,i.kt)("p",null,"You may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"create"),' method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the method:'),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include "models/flight.hpp"\n\nauto flight = Flight::create({\n {"name", "London to Paris"},\n});\n')),(0,i.kt)("p",null,"However, before using the ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method, you will need to specify either a ",(0,i.kt)("inlineCode",{parentName:"p"},"u_fillable")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"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."),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"is_admin")," parameter through an HTTP request, which is then passed to your model's ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method, allowing the user to escalate themselves to an administrator."),(0,i.kt)("p",null,"So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_fillable")," static data member on the model. For example, let's make the ",(0,i.kt)("inlineCode",{parentName:"p"},"name")," attribute of our ",(0,i.kt)("inlineCode",{parentName:"p"},"Flight")," model mass assignable:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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')),(0,i.kt)("p",null,"Once you have specified which attributes are mass assignable, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method to insert a new record in the database. The ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method returns the newly created model instance:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flight = Flight::create({{"name", "London to Paris"}});\n')),(0,i.kt)("p",null,"If you already have a model instance, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"fill")," method to populate it with the vector of attributes:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'flight.fill({{"name", "Amsterdam to Frankfurt"}});\n')),(0,i.kt)("h4",{id:"allowing-mass-assignment"},"Allowing Mass Assignment"),(0,i.kt)("p",null,"If you would like to make all of your attributes mass assignable, you may define your model's ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"fill"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"create"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"update")," methods:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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")),(0,i.kt)("h3",{id:"upserts"},"Upserts"),(0,i.kt)("p",null,"Occasionally, you may need to update an existing model or create a new model if no matching model exists."),(0,i.kt)("p",null,"In the example below, if a flight exists with a ",(0,i.kt)("inlineCode",{parentName:"p"},"departure")," location of ",(0,i.kt)("inlineCode",{parentName:"p"},"Oakland")," and a ",(0,i.kt)("inlineCode",{parentName:"p"},"destination")," location of ",(0,i.kt)("inlineCode",{parentName:"p"},"San Diego"),", its ",(0,i.kt)("inlineCode",{parentName:"p"},"price")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"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:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flight = Flight::updateOrCreate(\n {{"departure", "Oakland"}, {"destination", "San Diego"}},\n {{"price", 99}, {"discounted", 1}}\n);\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"firstOrCreate")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updateOrCreate")," methods persist the model, so there's no need to manually call the ",(0,i.kt)("inlineCode",{parentName:"p"},"save")," method.")),(0,i.kt)("p",null,'If you would like to perform multiple "upserts" in a single query, then you should use the ',(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"upsert")," method will automatically set the ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamps if timestamps are enabled on the model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"All databases except SQL Server require the columns in the second argument of the ",(0,i.kt)("inlineCode",{parentName:"p"},"upsert"),' method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the ',(0,i.kt)("inlineCode",{parentName:"p"},"upsert"),' method and always uses the "primary" and "unique" indexes of the table to detect existing records.')),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"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.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/refman/8.3/en/insert-on-duplicate.html"},"documentation"),". The MySQL server version is auto-detected and can be overridden in the ",(0,i.kt)("a",{parentName:"p",href:"/database/getting-started#configuration"},"configuration"),".")),(0,i.kt)("h2",{id:"deleting-models"},"Deleting Models"),(0,i.kt)("p",null,"To delete a model, you may call the ",(0,i.kt)("inlineCode",{parentName:"p"},"remove"),", or an alias ",(0,i.kt)("inlineCode",{parentName:"p"},"deleteRow")," method on the model instance:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include "models/flight.hpp"\n\nauto flight = Flight::find(1);\n\nflight->remove();\n')),(0,i.kt)("h4",{id:"deleting-an-existing-model-by-its-primary-key"},"Deleting An Existing Model By Its Primary Key"),(0,i.kt)("p",null,"In the example above, we are retrieving the model from the database before calling the ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"destroy")," method. In addition to accepting the single primary key, the ",(0,i.kt)("inlineCode",{parentName:"p"},"destroy")," method can accept multiple primary keys:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"Flight::destroy(1);\n\nFlight::destroy({1, 2, 3});\n")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"destroy")," method loads models from the database and calls the ",(0,i.kt)("inlineCode",{parentName:"p"},"remove")," method on each model individually, the reason for this is future compatibility with events.")),(0,i.kt)("h4",{id:"deleting-models-using-queries"},"Deleting Models Using Queries"),(0,i.kt)("p",null,"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:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto deletedRows = Flight::whereEq("active", 0)->remove();\n')),(0,i.kt)("h3",{id:"soft-deleting"},"Soft Deleting"),(0,i.kt)("p",null,'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.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::SoftDeletes")," base class to the model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n#include <orm/tiny/softdeletes.hpp>\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::SoftDeletes;\n\nclass Flight final : public Model<Flight>,\n public SoftDeletes<Flight>\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The table associated with the model. */\n QString u_table {"flights"};\n};\n')),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"SoftDeletes")," base class will automatically cast the ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," attribute to the ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance for you (it adds the ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," column to the model's ",(0,i.kt)("a",{parentName:"p",href:"#timestamps-u_dates"},(0,i.kt)("inlineCode",{parentName:"a"},"u_dates"))," list).")),(0,i.kt)("p",null,"You should also add the ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," column to your database table. The TinyORM ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations"},"schema builder")," contains a helper method to create this column:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Schema::table("flights", [](Blueprint &table)\n{\n table.softDeletes();\n});\n\nSchema::table("flights", [](Blueprint &table)\n{\n table.dropSoftDeletes();\n});\n')),(0,i.kt)("p",null,"Now, when you call the ",(0,i.kt)("inlineCode",{parentName:"p"},"remove")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"deleteModel")," method on the model, the ",(0,i.kt)("inlineCode",{parentName:"p"},"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."),(0,i.kt)("p",null,"To determine if a given model instance has been soft deleted, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"trashed")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"if (flight->trashed()) {\n //\n}\n")),(0,i.kt)("h4",{id:"restoring-soft-deleted-models"},"Restoring Soft Deleted Models"),(0,i.kt)("p",null,'Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model, you may call the ',(0,i.kt)("inlineCode",{parentName:"p"},"restore")," method on a model instance. The ",(0,i.kt)("inlineCode",{parentName:"p"},"restore")," method will set the model's ",(0,i.kt)("inlineCode",{parentName:"p"},"deleted_at")," column to ",(0,i.kt)("inlineCode",{parentName:"p"},"null"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"flight->restore();\n")),(0,i.kt)("p",null,"You may also use the ",(0,i.kt)("inlineCode",{parentName:"p"},"restore")," method in a query to restore multiple models:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'Flight::withTrashed()\n ->whereEq("airline_id", 1)\n .restore();\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"restore")," method may also be used when building ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/relationships"},"relationship")," queries:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"flight->history()->restore();\n")),(0,i.kt)("h4",{id:"permanently-deleting-models"},"Permanently Deleting Models"),(0,i.kt)("p",null,"Sometimes you may need to truly remove a model from your database. You may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"forceDelete")," method (or it's alias ",(0,i.kt)("inlineCode",{parentName:"p"},"forceRemove"),") to permanently remove a soft deleted model from the database table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"flight->forceDelete();\n")),(0,i.kt)("p",null,"You may also use the ",(0,i.kt)("inlineCode",{parentName:"p"},"forceDelete")," method when building TinyORM relationship queries:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"flight->history()->forceDelete();\n")),(0,i.kt)("h3",{id:"querying-soft-deleted-models"},"Querying Soft Deleted Models"),(0,i.kt)("h4",{id:"including-soft-deleted-models"},"Including Soft Deleted Models"),(0,i.kt)("p",null,"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.kt)("inlineCode",{parentName:"p"},"withTrashed")," method on the query:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flights = Flight::withTrashed()\n ->whereEq("account_id", 1)\n .get();\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"withTrashed")," method may also be called when building a ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/relationships"},"relationship")," query:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"flight->history()->withTrashed().get();\n")),(0,i.kt)("h4",{id:"retrieving-only-soft-deleted-models"},"Retrieving Only Soft Deleted Models"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"onlyTrashed")," method will retrieve ",(0,i.kt)("strong",{parentName:"p"},"only")," soft deleted models:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flights = Flight::onlyTrashed()\n ->whereEq("airline_id", 1)\n .get();\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"onlyTrashed")," method may also be called when building a ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/relationships"},"relationship")," query:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"flight->history()->onlyTrashed().get();\n")),(0,i.kt)("h4",{id:"excluding-soft-deleted-models"},"Excluding Soft Deleted Models"),(0,i.kt)("p",null,"As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be ",(0,i.kt)("strong",{parentName:"p"},"excluded")," in a query's results by calling the ",(0,i.kt)("inlineCode",{parentName:"p"},"withoutTrashed")," method on the query:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto flights = Flight::withoutTrashed()\n ->whereEq("account_id", 1)\n .get();\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"withoutTrashed")," method may also be called when building a ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/relationships"},"relationship")," query:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"flight->history()->withoutTrashed().get();\n")),(0,i.kt)("h3",{id:"truncate-table"},"Truncate Table"),(0,i.kt)("p",null,"You may call the ",(0,i.kt)("inlineCode",{parentName:"p"},"truncate")," method to delete all of the model's associated database records. The ",(0,i.kt)("inlineCode",{parentName:"p"},"truncate")," operation will also reset any auto-incrementing IDs on the model's associated table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"Flight::truncate();\n")),(0,i.kt)("h2",{id:"replicating-models"},"Replicating Models"),(0,i.kt)("p",null,"You may create an unsaved copy of an existing model instance using the ",(0,i.kt)("inlineCode",{parentName:"p"},"replicate")," method. This method is particularly useful when you have model instances that share many of the same attributes:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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')),(0,i.kt)("p",null,"To exclude one or more attributes from being replicated to the new model, you may pass an unordered_set to the ",(0,i.kt)("inlineCode",{parentName:"p"},"replicate")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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')),(0,i.kt)("h2",{id:"comparing-models"},"Comparing Models"),(0,i.kt)("p",null,'Sometimes you may need to determine if two models are the "same" or not. The ',(0,i.kt)("inlineCode",{parentName:"p"},"is")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"isNot")," methods may be used to quickly verify two models have the same primary key, table, and database connection or not:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"if (post->is(anotherPost)) {\n //\n}\n\nif (post->isNot(anotherPost)) {\n //\n}\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"is")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"isNot")," methods are also available when using the ",(0,i.kt)("inlineCode",{parentName:"p"},"belongsTo")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"hasOne")," ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/relationships"},"relationships"),". This method is particularly helpful when you would like to compare a related model without issuing a query to retrieve that model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"if (post->author()->is(user)) {\n //\n}\n")),(0,i.kt)("h5",{id:"equality-comparison"},"Equality comparison"),(0,i.kt)("p",null,"The base ",(0,i.kt)("inlineCode",{parentName:"p"},"Model")," class also defines the ",(0,i.kt)("inlineCode",{parentName:"p"},"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.kt)("inlineCode",{parentName:"p"},"model1 == model2")," expression guarantees that these two models are exactly the same."),(0,i.kt)("p",null,"It would be appropriate to mention that this comparison also includes relations, which means it will also compare ",(0,i.kt)("strong",{parentName:"p"},"all")," models (including their data members) these relations contain."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5b254f70.84226d5d.js b/assets/js/5b254f70.84226d5d.js new file mode 100644 index 000000000..7535556a6 --- /dev/null +++ b/assets/js/5b254f70.84226d5d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[82],{5105:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>r,contentTitle:()=>l,default:()=>h,frontMatter:()=>a,metadata:()=>d,toc:()=>o});var i=t(4848),s=t(8453);const a={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"]},l="TinyORM: Getting Started",d={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"}},r={},o=[{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 c(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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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",{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<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <QDateTime>\n\n#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\n{\n friend Model;\n using Model::Model;\n\nprivate:\n /*! The model\'s default values for attributes. */\n inline static const QVector<AttributeItem> 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 <QDebug>\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<Derived, AllRelations...>"})," 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<TinyBuilder<Model>>"}),", ",(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<Model>"}),", 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 <QDebug>\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<Derived, AllRelations...>"})," 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<Flight> &&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<Flight> &&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<int>(1, [] {\n // ...\n return 10;\n});\n\nauto flight = Flight::findOr<std::optional<Flight>>(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<AttributeItem>"}),":"]}),"\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<Orm::WhereItem>"})," argument with the optional second ",(0,i.jsx)(n.code,{children:"QVector<Orm::AttributeItem>"})," 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<Orm::UpdateItem>"})," 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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass Flight final : public Model<Flight>\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.3/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 <orm/tiny/model.hpp>\n#include <orm/tiny/softdeletes.hpp>\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::SoftDeletes;\n\nclass Flight final : public Model<Flight>,\n public SoftDeletes<Flight>\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 h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(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/5e95c892.7024aad0.js b/assets/js/5e95c892.7024aad0.js new file mode 100644 index 000000000..2f6bf0d45 --- /dev/null +++ b/assets/js/5e95c892.7024aad0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[647],{7121:(e,r,s)=>{s.r(r),s.d(r,{default:()=>i});s(6540);var n=s(4164),t=s(9024),u=s(7559),a=s(2831),c=s(9201),o=s(4848);function i(e){return(0,o.jsx)(t.e3,{className:(0,n.A)(u.G.wrapper.docsPages),children:(0,o.jsx)(c.A,{children:(0,a.v)(e.route.routes)})})}}}]); \ No newline at end of file diff --git a/assets/js/62a1276f.732e44fe.js b/assets/js/62a1276f.732e44fe.js deleted file mode 100644 index 0569911e4..000000000 --- a/assets/js/62a1276f.732e44fe.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[57],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>y});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?r(Object(a),!0).forEach((function(t){i(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):r(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,i=function(e,t){if(null==e)return{};var a,n,i={},r=Object.keys(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n<r.length;n++)a=r[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),p=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},m=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),d=p(a),c=i,y=d["".concat(l,".").concat(c)]||d[c]||u[c]||r;return a?n.createElement(y,o(o({ref:t},m),{},{components:a})):n.createElement(y,o({ref:t},m))}));function y(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=c;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var p=2;p<r;p++)o[p]=a[p];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}c.displayName="MDXCreateElement"},9823:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>p});var n=a(7462),i=(a(7294),a(3905));const r={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"]},o="TinyORM: Casting",s={unversionedId:"tinyorm/casts",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,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/tinyorm/casts.mdx",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"}},l={},p=[{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}],m={toc:p},d="wrapper";function u(e){let{components:t,...a}=e;return(0,i.kt)(d,(0,n.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"tinyorm-casting"},"TinyORM: Casting"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#accessors"},"Accessors"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#defining-an-accessor"},"Defining An Accessor")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#attribute-casting"},"Attribute Casting"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#date-casting"},"Date Casting")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#query-time-casting"},"Query Time Casting"))))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,"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,i.kt)("inlineCode",{parentName:"p"},"datetime")," string that is stored in your database to the ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance when it is accessed via your TinyORM model. Or, you may want to convert a ",(0,i.kt)("inlineCode",{parentName:"p"},"tinyint")," number that is stored in the database to the ",(0,i.kt)("inlineCode",{parentName:"p"},"bool")," when you access it on the TinyORM model."),(0,i.kt)("h2",{id:"accessors"},"Accessors"),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Accessors are currently only used during the serialization by the ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/serialization#appending-values-to-json"},"Appending Values")," feature. They are not used during the ",(0,i.kt)("inlineCode",{parentName:"p"},"getAttribute")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"getAttributeValue")," methods calls.")),(0,i.kt)("h3",{id:"defining-an-accessor"},"Defining An Accessor"),(0,i.kt)("p",null,"An accessor transforms a TinyORM attribute value when it is accessed (currently during serialization only by the ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/serialization#appending-values-to-json"},"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.'),(0,i.kt)("p",null,"In this example, we'll define an accessor for the ",(0,i.kt)("inlineCode",{parentName:"p"},"first_name")," attribute. The accessor will automatically be called by TinyORM during serialization if the ",(0,i.kt)("inlineCode",{parentName:"p"},"first_name")," attribute is defined in the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_appends")," data member set. All attribute accessor methods must return the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Casts::Attribute"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User>\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<QString>("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<QString, MutatorFunction> u_mutators {\n {"first_name", &User::firstName},\n };\n};\n')),(0,i.kt)("p",null,"All accessor methods return an ",(0,i.kt)("inlineCode",{parentName:"p"},"Attribute")," instance which defines how the attribute will be accessed. To do so, we supply the ",(0,i.kt)("inlineCode",{parentName:"p"},"get")," argument to the ",(0,i.kt)("inlineCode",{parentName:"p"},"Attribute")," class constructor or ",(0,i.kt)("inlineCode",{parentName:"p"},"Attribute::make")," factory method."),(0,i.kt)("p",null,"As you can see, the current model is captured by-reference using the ",(0,i.kt)("inlineCode",{parentName:"p"},"[this]")," capture, allowing you to obtain a value by the ",(0,i.kt)("inlineCode",{parentName:"p"},"getAttribute")," method inside the lambda expression, manipulate it and return a new value."),(0,i.kt)("p",null,"You can also use the second overload that allows you to pass the ",(0,i.kt)("inlineCode",{parentName:"p"},"ModelAttributes")," unordered map to the lambda expression:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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<QString>("first_name");\n\n if (!firstName.isEmpty())\n firstName[0] = firstName.at(0).toUpper();\n\n return firstName;\n });\n }\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/include/orm/tiny/types/modelattributes.hpp"},(0,i.kt)("inlineCode",{parentName:"a"},"ModelAttributes"))," container extends the ",(0,i.kt)("inlineCode",{parentName:"p"},"std::unordered_map<QString, QVariant>")," and adds the ",(0,i.kt)("inlineCode",{parentName:"p"},"at<T>")," method that allows you to cast the underlying QVariant value."),(0,i.kt)("p",null,"Special note should be given to the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_mutators")," static data member map, which maps accessors' attribute names to its methods. This data member is ",(0,i.kt)("strong",{parentName:"p"},"required")," because C++ does not currently support reflection."),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"If you would like these computed values to be added to the vector, map, or JSON representations of your model, ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/serialization#appending-values-to-json"},"you will need to append them"),".")),(0,i.kt)("admonition",{type:"danger"},(0,i.kt)("p",{parentName:"admonition"},"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.")),(0,i.kt)("h4",{id:"building-value-from-multiple-attributes"},"Building Value From Multiple Attributes"),(0,i.kt)("p",null,"Sometimes your accessor may need to transform multiple model attributes into a single value. You can use both methods described above to accomplish this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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<QString>("first_name"),\n getAttribute<QString>("last_name"));\n });\n }\n')),(0,i.kt)("p",null,"Or you can use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ModelAttributes")," overload:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'/*! 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<QString>("first_name"),\n attributes.at<QString>("last_name"));\n });\n}\n')),(0,i.kt)("h4",{id:"accessor-caching"},"Accessor Caching"),(0,i.kt)("p",null,"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,i.kt)("inlineCode",{parentName:"p"},"shouldCache")," method when defining your accessor:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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<QString>("first_name"),\n getAttribute<QString>("last_name"));\n }).shouldCache();\n }\n')),(0,i.kt)("h2",{id:"attribute-casting"},"Attribute Casting"),(0,i.kt)("p",null,"Attribute casting provides functionality that allows converting model attributes to the appropriate ",(0,i.kt)("inlineCode",{parentName:"p"},"QVariant")," ",(0,i.kt)("strong",{parentName:"p"},"metatype")," when it is accessed via your TinyORM model. The core of this functionality is a model's ",(0,i.kt)("inlineCode",{parentName:"p"},"u_casts")," static data member that provides a convenient method of converting attributes' ",(0,i.kt)("inlineCode",{parentName:"p"},"QVariant")," ",(0,i.kt)("strong",{parentName:"p"},"internal types")," to the defined cast types."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"u_casts")," static data member should be the ",(0,i.kt)("inlineCode",{parentName:"p"},"std::unordered_map<QString, Orm::CastItem>")," 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:"),(0,i.kt)("div",{id:"casts-types-list"},(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::QString")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Boolean")," / ",(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Bool")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Integer")," / ",(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Int")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::UInteger")," / ",(0,i.kt)("inlineCode",{parentName:"li"},"CastType::UInt")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::LongLong")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::ULongLong")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Short")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::UShort")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::QDate")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::QDateTime")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Timestamp")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Real")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Float")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::Double")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("code",null,"CastType::Decimal:<precision>")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"CastType::QByteArray")))),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"The primary key name defined by the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_primaryKey")," model's data member is automatically cast to the ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::ULongLong")," for all database drivers if the ",(0,i.kt)("inlineCode",{parentName:"p"},"u_incrementing")," is set to true (its default value).")),(0,i.kt)("p",null,"To demonstrate attribute casting, let's cast the ",(0,i.kt)("inlineCode",{parentName:"p"},"is_admin")," attribute, which is stored in our database as an integer (",(0,i.kt)("inlineCode",{parentName:"p"},"0")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"1"),") to a ",(0,i.kt)("inlineCode",{parentName:"p"},"QVariant(bool)")," value:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#pragma once\n\n#include <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User>\n{\n friend Model;\n using Model::Model;\n\n /*! The attributes that should be cast. */\n inline static std::unordered_map<QString, CastItem> u_casts {\n {"is_admin", CastType::Boolean},\n };\n};\n')),(0,i.kt)("p",null,"After defining the cast, the ",(0,i.kt)("inlineCode",{parentName:"p"},"is_admin")," attribute will always be cast to a ",(0,i.kt)("inlineCode",{parentName:"p"},"QVariant(bool)")," when you access it, even if the underlying value is stored in the database as an integer:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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<bool>()) {\n //\n}\n')),(0,i.kt)("p",null,"If you need to add a new, ",(0,i.kt)("strong",{parentName:"p"},"temporary")," cast at runtime, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"mergeCasts")," method. These cast definitions will be added to any of the casts already defined on the model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'user->mergeCasts({\n {"is_paid", CastType::Boolean},\n {"income", {CastType::Decimal, 2}},\n});\n')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"You should never define a cast (or an attribute) that has the same name as a relationship.")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Attributes that are ",(0,i.kt)("inlineCode",{parentName:"p"},"null")," ",(0,i.kt)("strong",{parentName:"p"},"will also be")," cast so that the ",(0,i.kt)("inlineCode",{parentName:"p"},"QVariant"),"'s internal type will have the correct type.")),(0,i.kt)("h3",{id:"date-casting"},"Date Casting"),(0,i.kt)("p",null,"By default, TinyORM will cast the ",(0,i.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"updated_at")," columns to instances of ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime"),". You may cast additional date attributes by defining additional date casts within your model's ",(0,i.kt)("inlineCode",{parentName:"p"},"u_casts")," static data member unordered map. Typically, dates should be cast using the ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::QDateTime"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::QDate"),", or ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::Timestamp")," cast types."),(0,i.kt)("p",null,"When a database column is of the date type, you may set the corresponding model attribute value to a UNIX timestamp, date string (",(0,i.kt)("inlineCode",{parentName:"p"},"Y-m-d"),"), date-time string, ",(0,i.kt)("inlineCode",{parentName:"p"},"QDate"),", or ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance. The date's value will be correctly converted and stored in your database.",(0,i.kt)("br",null),"\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,i.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance."),(0,i.kt)("p",null,"When defining the ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::QDate")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::QDateTime")," cast, you may also specify the date's format. In this case you must use the ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDate")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDateTime")," cast types. This format will be used when the ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/serialization"},"model is serialized to a vector, map, or JSON"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'/*! The attributes that should be cast. */\ninline static std::unordered_map<QString, CastItem> u_casts {\n {"created_at", {CastType::CustomQDateTime, "yyyy-MM-dd"}},\n};\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDate")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDateTime")," cast types behave exactly like the ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::QDate")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::QDateTime")," cast types with the additional ",(0,i.kt)("strong",{parentName:"p"},"date's format")," functionality during ",(0,i.kt)("u",null,(0,i.kt)("strong",{parentName:"p"},"serialization")),".")),(0,i.kt)("p",null,"You may customize the ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/serialization#customizing-the-default-date-format"},"default serialization format")," for all of your model's dates or datetimes by defining a ",(0,i.kt)("inlineCode",{parentName:"p"},"serializeDate")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"serializeDateTime")," methods on your model. These methods do not affect how your dates are formatted for storage in the database:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'/*! 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')),(0,i.kt)("p",null,"To specify the format that should be used when actually storing a model's dates within your database, you should define a ",(0,i.kt)("inlineCode",{parentName:"p"},"u_dateFormat")," data member on your model:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"/*! The storage format of the model's date columns. */\ninline static QString u_dateFormat {QLatin1Char('U')};\n")),(0,i.kt)("p",null,"This format can be any format that the QDateTime's ",(0,i.kt)("inlineCode",{parentName:"p"},"fromString")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"toString")," methods accept or the special ",(0,i.kt)("inlineCode",{parentName:"p"},"U")," format that represents the UNIX timestamp (this ",(0,i.kt)("inlineCode",{parentName:"p"},"U")," format is TinyORM-specific and isn't supported by ",(0,i.kt)("inlineCode",{parentName:"p"},"QDateTime"),")."),(0,i.kt)("p",null,"Define a ",(0,i.kt)("inlineCode",{parentName:"p"},"u_timeFormat")," data member on your model to specify the format that should be used when storing a model's times within your database:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'/*! The storage format of the model\'s time columns. */\ninline static QString u_timeFormat {"HH:mm:ss.zzz"};\n')),(0,i.kt)("h4",{id:"date-casting-serialization-and-timezones"},"Date Casting, Serialization & Timezones"),(0,i.kt)("p",null,"By default, the ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDate")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDateTime")," casts will serialize dates to a UTC ISO-8601 date string (",(0,i.kt)("inlineCode",{parentName:"p"},"yyyy-MM-ddTHH:mm:ss.zzzZ"),"), regardless of the timezone specified in your database connection's ",(0,i.kt)("inlineCode",{parentName:"p"},"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,i.kt)("inlineCode",{parentName:"p"},"qt_timezone")," configuration option from its default ",(0,i.kt)("inlineCode",{parentName:"p"},"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."),(0,i.kt)("p",null,"If a custom format is applied to the ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDate")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"CastType::CustomQDateTime")," cast types, such as ",(0,i.kt)("inlineCode",{parentName:"p"},'{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,i.kt)("inlineCode",{parentName:"p"},"qt_timezone")," configuration option."),(0,i.kt)("h3",{id:"query-time-casting"},"Query Time Casting"),(0,i.kt)("p",null,"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:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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,i.kt)("inlineCode",{parentName:"p"},"CastType::QDateTime")," cast to this attribute when executing the query. Thankfully, we may accomplish this using the ",(0,i.kt)("inlineCode",{parentName:"p"},"withCasts")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"withCast")," methods:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'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')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/62a1276f.87749e65.js b/assets/js/62a1276f.87749e65.js new file mode 100644 index 000000000..1d88ca9c9 --- /dev/null +++ b/assets/js/62a1276f.87749e65.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[304],{6257:(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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User>\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<QString>("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<QString, MutatorFunction> 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<QString>("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<QString, QVariant>"})," and adds the ",(0,s.jsx)(t.code,{children:"at<T>"})," 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<QString>("first_name"),\n getAttribute<QString>("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<QString>("first_name"),\n attributes.at<QString>("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<QString>("first_name"),\n getAttribute<QString>("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<QString, Orm::CastItem>"})," 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:<precision>"}),"\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 <orm/tiny/model.hpp>\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User>\n{\n friend Model;\n using Model::Model;\n\n /*! The attributes that should be cast. */\n inline static std::unordered_map<QString, CastItem> 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<bool>()) {\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<QString, CastItem> 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/6629c45f.43d6f39e.js b/assets/js/6629c45f.43d6f39e.js new file mode 100644 index 000000000..5c706d682 --- /dev/null +++ b/assets/js/6629c45f.43d6f39e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[820],{72:e=>{e.exports=JSON.parse('{"version":{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tinyormSidebar":[{"type":"link","label":"\ud83d\udd25 Prologue","href":"/","docId":"README","unlisted":false},{"type":"link","label":"\ud83d\udd27 Dependencies","href":"/dependencies","docId":"dependencies","unlisted":false},{"type":"link","label":"\ud83d\ude80 Supported Compilers","href":"/supported-compilers","docId":"supported-compilers","unlisted":false},{"type":"category","label":"\u2728 Database","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/database/getting-started","docId":"database/getting-started","unlisted":false},{"type":"link","label":"Query Builder","href":"/database/query-builder","docId":"database/query-builder","unlisted":false},{"type":"link","label":"Migrations","href":"/database/migrations","docId":"database/migrations","unlisted":false},{"type":"link","label":"Seeding","href":"/database/seeding","docId":"database/seeding","unlisted":false}]},{"type":"category","label":"\ud83c\udf89 TinyORM","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/tinyorm/getting-started","docId":"tinyorm/getting-started","unlisted":false},{"type":"link","label":"Relationships","href":"/tinyorm/relationships","docId":"tinyorm/relationships","unlisted":false},{"type":"link","label":"Collections","href":"/tinyorm/collections","docId":"tinyorm/collections","unlisted":false},{"type":"link","label":"Casts","href":"/tinyorm/casts","docId":"tinyorm/casts","unlisted":false},{"type":"link","label":"Serialization","href":"/tinyorm/serialization","docId":"tinyorm/serialization","unlisted":false}]},{"type":"category","label":"\ud83e\uddec TinyDrivers","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/tinydrivers/getting-started","docId":"tinydrivers/getting-started","unlisted":false}]},{"type":"category","label":"\ud83d\udea7 Building","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"TinyORM","href":"/building/tinyorm","docId":"building/tinyorm","unlisted":false},{"type":"link","label":"Hello world","href":"/building/hello-world","docId":"building/hello-world","unlisted":false},{"type":"link","label":"Migrations","href":"/building/migrations","docId":"building/migrations","unlisted":false}]},{"type":"link","label":"\ud83d\udcc4 Features Summary","href":"/features-summary","docId":"features-summary","unlisted":false},{"type":"link","label":"\u2764\ufe0f Sponsors","href":"/sponsors","docId":"sponsors","unlisted":false}]},"docs":{"building/hello-world":{"id":"building/hello-world","title":"Building: Hello world","description":"Hello world example created in the terminal and QtCreator IDE.","sidebar":"tinyormSidebar"},"building/migrations":{"id":"building/migrations","title":"Building: Migrations","description":"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.","sidebar":"tinyormSidebar"},"building/tinyorm":{"id":"building/tinyorm","title":"Building: TinyORM","description":"How to compile the TinyORM C++ library on Windows and Linux.","sidebar":"tinyormSidebar"},"database/getting-started":{"id":"database/getting-started","title":"Database: Getting Started","description":"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.","sidebar":"tinyormSidebar"},"database/migrations":{"id":"database/migrations","title":"Database: Migrations","description":"Migrations are like version control for your database, allowing your team to define and share the application\'s database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM\'s supported database systems.","sidebar":"tinyormSidebar"},"database/query-builder":{"id":"database/query-builder","title":"Database: Query Builder","description":"TinyORM\'s database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.","sidebar":"tinyormSidebar"},"database/seeding":{"id":"database/seeding","title":"Database: Seeding","description":"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.","sidebar":"tinyormSidebar"},"dependencies":{"id":"dependencies","title":"Dependencies","description":"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.","sidebar":"tinyormSidebar"},"features-summary":{"id":"features-summary","title":"Features Summary","description":"List that fastly summarizes all TinyORM features.","sidebar":"tinyormSidebar"},"README":{"id":"README","title":"Prologue","description":"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.","sidebar":"tinyormSidebar"},"sponsors":{"id":"sponsors","title":"Sponsors","description":"How to sponsor and support the TinyORM project.","sidebar":"tinyormSidebar"},"supported-compilers":{"id":"supported-compilers","title":"Supported Compilers","description":"Platform requirements, supported compilers and build systems for TinyORM C++ library.","sidebar":"tinyormSidebar"},"tinydrivers/getting-started":{"id":"tinydrivers/getting-started","title":"TinyDrivers: Getting Started","description":"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.","sidebar":"tinyormSidebar"},"tinyorm/casts":{"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.","sidebar":"tinyormSidebar"},"tinyorm/collections":{"id":"tinyorm/collections","title":"TinyORM: Collections","description":"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.","sidebar":"tinyormSidebar"},"tinyorm/getting-started":{"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.","sidebar":"tinyormSidebar"},"tinyorm/relationships":{"id":"tinyorm/relationships","title":"TinyORM: Relationships","description":"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.","sidebar":"tinyormSidebar"},"tinyorm/serialization":{"id":"tinyorm/serialization","title":"TinyORM: Serialization","description":"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.","sidebar":"tinyormSidebar"}}}}')}}]); \ No newline at end of file diff --git a/assets/js/7333c691.02799d7f.js b/assets/js/7333c691.02799d7f.js new file mode 100644 index 000000000..e8f7b0380 --- /dev/null +++ b/assets/js/7333c691.02799d7f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[638],{3156:(e,n,o)=>{o.r(n),o.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>c,frontMatter:()=>i,metadata:()=>r,toc:()=>d});var s=o(4848),t=o(8453);const i={sidebar_position:1,sidebar_label:"Relationships",description:"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.",keywords:["c++ orm","relationships","relations","tinyorm"]},a="TinyORM: Relationships",r={id:"tinyorm/relationships",title:"TinyORM: Relationships",description:"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.",source:"@site/docs/tinyorm/relationships.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/relationships",permalink:"/tinyorm/relationships",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,sidebar_label:"Relationships",description:"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.",keywords:["c++ orm","relationships","relations","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Getting Started",permalink:"/tinyorm/getting-started"},next:{title:"Collections",permalink:"/tinyorm/collections"}},l={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Defining Relationships",id:"defining-relationships",level:2},{value:"Common Rules",id:"common-rules",level:3},{value:"One To One",id:"one-to-one",level:3},{value:"Defining The Inverse Of The Relationship",id:"defining-the-inverse-of-the-relationship",level:4},{value:"One To Many",id:"one-to-many",level:3},{value:"One To Many (Inverse) / Belongs To",id:"one-to-many-inverse",level:3},{value:"Default Models",id:"default-models",level:4},{value:"Many To Many Relationships",id:"many-to-many",level:2},{value:"Table Structure",id:"table-structure",level:4},{value:"Model Structure",id:"model-structure",level:4},{value:"Defining The Inverse Of The Relationship",id:"defining-the-inverse-of-the-relationship-1",level:4},{value:"Retrieving Intermediate Table Columns",id:"retrieving-intermediate-table-columns",level:3},{value:"Customizing The <code>pivot</code> Relation Name",id:"customizing-the-pivot-relation-name",level:4},{value:"Defining Custom Intermediate Table Models",id:"defining-custom-intermediate-table-models",level:3},{value:"Custom Pivot Models And Incrementing IDs",id:"custom-pivot-models-and-incrementing-ids",level:4},{value:"Closer Look At Defining Custom Intermediate Table Models",id:"closer-look-at-defining-custom-intermediate-table-models",level:4},{value:"User Data Members on Custom Intermediate Table Models",id:"user-data-members-on-custom-intermediate-table-models",level:5},{value:"Querying Relations",id:"querying-relations",level:2},{value:"Chaining <code>orWhere</code> Clauses After Relationships",id:"chaining-orwhere-clauses-after-relationships",level:4},{value:"Relationship Methods",id:"relationship-methods",level:3},{value:"Querying Relationship Existence",id:"querying-relationship-existence",level:3},{value:"Related template parameter",id:"related-template-parameter",level:4},{value:"Querying Relationship Absence",id:"querying-relationship-absence",level:3},{value:"Eager Loading",id:"eager-loading",level:2},{value:"Eager Loading Multiple Relationships",id:"eager-loading-multiple-relationships",level:4},{value:"Nested Eager Loading",id:"nested-eager-loading",level:4},{value:"Eager Loading Specific Columns",id:"eager-loading-specific-columns",level:4},{value:"Eager Loading By Default",id:"eager-loading-by-default",level:4},{value:"Constraining Eager Loads",id:"constraining-eager-loads",level:3},{value:"Lazy Eager Loading",id:"lazy-eager-loading",level:3},{value:"Inserting & Updating Related Models",id:"inserting-and-updating-related-models",level:2},{value:"The <code>save</code> Method",id:"the-save-method",level:3},{value:"Recursively Saving Models & Relationships",id:"recursively-saving-models--relationships",level:4},{value:"The <code>create</code> Method",id:"the-create-method",level:3},{value:"Belongs To Relationships",id:"updating-belongs-to-relationships",level:3},{value:"Many To Many Relationships",id:"updating-many-to-many-relationships",level:3},{value:"Attaching / Detaching",id:"attaching--detaching",level:4},{value:"Syncing Associations",id:"syncing-associations",level:4},{value:"Updating A Record On The Intermediate Table",id:"updating-a-record-on-the-intermediate-table",level:4},{value:"Touching Parent Timestamps",id:"touching-parent-timestamps",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",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:"tinyorm-relationships",children:"TinyORM: Relationships"}),"\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:"#defining-relationships",children:"Defining Relationships"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#common-rules",children:"Common Rules"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#one-to-one",children:"One To One"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#one-to-many",children:"One To Many"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#one-to-many-inverse",children:"One To Many (Inverse) / Belongs To"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#many-to-many",children:"Many To Many Relationships"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#retrieving-intermediate-table-columns",children:"Retrieving Intermediate Table Columns"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#defining-custom-intermediate-table-models",children:"Defining Custom Intermediate Table Models"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#querying-relations",children:"Querying Relations"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#relationship-methods",children:"Relationship Methods"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#querying-relationship-existence",children:"Querying Relationship Existence"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#querying-relationship-absence",children:"Querying Relationship Absence"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#eager-loading",children:"Eager Loading"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#constraining-eager-loads",children:"Constraining Eager Loads"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#lazy-eager-loading",children:"Lazy Eager Loading"})}),"\n"]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#inserting-and-updating-related-models",children:"Inserting & Updating Related Models"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsxs)(n.a,{href:"#the-save-method",children:["The ",(0,s.jsx)(n.code,{children:"save"})," Method"]})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsxs)(n.a,{href:"#the-create-method",children:["The ",(0,s.jsx)(n.code,{children:"create"})," Method"]})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#updating-belongs-to-relationships",children:"Belongs To Relationships"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#updating-many-to-many-relationships",children:"Many To Many Relationships"})}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#touching-parent-timestamps",children:"Touching Parent Timestamps"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,s.jsx)(n.p,{children:"Database tables are often related to one another. For example, a blog post may have many comments or an order could be related to the user who placed it. TinyORM makes managing and working with these relationships easy, and supports basic relationships:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#one-to-one",children:"One To One"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#one-to-many",children:"One To Many"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#many-to-many",children:"Many To Many"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"defining-relationships",children:"Defining Relationships"}),"\n",(0,s.jsxs)(n.p,{children:["TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful ",(0,s.jsx)(n.a,{href:"/database/query-builder",children:"query builders"}),", defining relationships as methods provides powerful method chaining and querying capabilities. For example, we may chain additional query constraints on this ",(0,s.jsx)(n.code,{children:"posts"})," relationship:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'user->posts()->whereEq("active", 1).get();\n'})}),"\n",(0,s.jsx)(n.p,{children:"But, before diving too deep into using relationships, let's learn how to define each type of relationship supported by TinyORM."}),"\n",(0,s.jsx)(n.h3,{id:"common-rules",children:"Common Rules"}),"\n",(0,s.jsx)(n.p,{children:'Before you start defining relationship methods, you have to declare a model class, let\'s examine following model class with a "one" type relation:'}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/phone.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User, Phone>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the phone associated with the user. */\n std::unique_ptr<HasOne<User, Phone>>\n phone()\n {\n return hasOne<Phone>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"phone", &User::phone); }},\n };\n};\n\n#endif // USER_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["First, you have to extend the ",(0,s.jsx)(n.code,{children:"Model<Derived, AllRelations...>"}),", it is a common class for all models, the first template parameter is the type-id of the defined model itself, this pattern is called a ",(0,s.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern",children:"Curiously recurring template pattern"})," pattern."]}),"\n",(0,s.jsx)(n.p,{children:"However, the second parameter is more interesting, here you have to provide a type-id of all related models. The TinyORM needs these types to store relationships in the hash."}),"\n",(0,s.jsxs)(n.p,{children:["Next, you have to define the ",(0,s.jsx)(n.code,{children:"u_relations"})," hash, which maps relation names to relationship methods. \ud83d\udd25\ud83d\ude80\ud83d\ude4c"]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You may omit the ",(0,s.jsx)(n.code,{children:"friend Model"})," declaration and define all the private data and function members as public."]})}),"\n",(0,s.jsx)(n.h3,{id:"one-to-one",children:"One To One"}),"\n",(0,s.jsxs)(n.p,{children:["A one-to-one relationship is a very basic type of database relationship. For example, a ",(0,s.jsx)(n.code,{children:"User"})," model might be associated with one ",(0,s.jsx)(n.code,{children:"Phone"})," model. To define this relationship, we will place a ",(0,s.jsx)(n.code,{children:"phone"})," method on the ",(0,s.jsx)(n.code,{children:"User"})," model. The ",(0,s.jsx)(n.code,{children:"phone"})," method should call the ",(0,s.jsx)(n.code,{children:"hasOne"})," method and return its result. The ",(0,s.jsx)(n.code,{children:"hasOne<Related>"})," method is available to your model via the model's ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Model<Derived, AllRelations...>"})," base class:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/phone.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User, Phone>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the phone associated with the user. */\n std::unique_ptr<HasOne<User, Phone>>\n phone()\n {\n return hasOne<Phone>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"phone", [](auto &v) { v(&User::phone); }},\n };\n};\n\n#endif // USER_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"Related"})," template argument provided to the ",(0,s.jsx)(n.code,{children:"hasOne<Related>"})," method is the type-id of the related model class. Once the relationship is defined, we may retrieve the related record using Model's ",(0,s.jsx)(n.code,{children:"getRelationValue<Related, Tag>"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto phone = User::find(1)->getRelationValue<Phone, Orm::One>("phone");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["TinyORM determines the foreign key of the relationship based on the parent model name. In this case, the ",(0,s.jsx)(n.code,{children:"Phone"})," model is automatically assumed to have a ",(0,s.jsx)(n.code,{children:"user_id"})," foreign key. If you wish to override this convention, you may pass a first argument to the ",(0,s.jsx)(n.code,{children:"hasOne"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'return hasOne<Phone>("foreign_key");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Additionally, TinyORM assumes that the foreign key should have a value matching the primary key column of the parent. In other words, TinyORM will look for the value of the user's ",(0,s.jsx)(n.code,{children:"id"})," column in the ",(0,s.jsx)(n.code,{children:"user_id"})," column of the ",(0,s.jsx)(n.code,{children:"Phone"})," record. If you would like the relationship to use a primary key value other than ",(0,s.jsx)(n.code,{children:"id"})," or your model's ",(0,s.jsx)(n.code,{children:"u_primaryKey"})," data member, you may pass a second argument to the ",(0,s.jsx)(n.code,{children:"hasOne"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'return hasOne<Phone>("foreign_key", "local_key");\n'})}),"\n",(0,s.jsx)(n.h4,{id:"defining-the-inverse-of-the-relationship",children:"Defining The Inverse Of The Relationship"}),"\n",(0,s.jsxs)(n.p,{children:["So, we can access the ",(0,s.jsx)(n.code,{children:"Phone"})," model from our ",(0,s.jsx)(n.code,{children:"User"})," model. Next, let's define a relationship on the ",(0,s.jsx)(n.code,{children:"Phone"})," model that will let us access the user that owns the phone. We can define the inverse of a ",(0,s.jsx)(n.code,{children:"hasOne"})," relationship using the ",(0,s.jsx)(n.code,{children:"belongsTo<Related>"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef PHONE_HPP\n#define PHONE_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/user.hpp"\n\nusing Orm::Tiny::Model;\n\nclass Phone final : public Model<Phone, User>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the user that owns the phone. */\n std::unique_ptr<BelongsTo<Phone, User>>\n user()\n {\n return belongsTo<User>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"user", [](auto &v) { v(&Phone::user); }},\n };\n};\n\n#endif // PHONE_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["When invoking the ",(0,s.jsx)(n.code,{children:"user"})," method, TinyORM will attempt to find a ",(0,s.jsx)(n.code,{children:"User"})," model that has an ",(0,s.jsx)(n.code,{children:"id"})," which matches the ",(0,s.jsx)(n.code,{children:"user_id"})," column on the ",(0,s.jsx)(n.code,{children:"Phone"})," model."]}),"\n",(0,s.jsxs)(n.p,{children:["TinyORM determines the foreign key name by examining the type-name of the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter and suffixing the type-name with ",(0,s.jsx)(n.code,{children:"_id"}),". So, in this case, TinyORM assumes that the ",(0,s.jsx)(n.code,{children:"Phone"})," model has a ",(0,s.jsx)(n.code,{children:"user_id"})," column."]}),"\n",(0,s.jsxs)(n.p,{children:["However, if the foreign key on the ",(0,s.jsx)(n.code,{children:"Phone"})," model is not ",(0,s.jsx)(n.code,{children:"user_id"}),", you may pass a custom key name as the first argument to the ",(0,s.jsx)(n.code,{children:"belongsTo"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'/*! Get the user that owns the phone. */\nstd::unique_ptr<BelongsTo<Phone, User>>\nuser()\n{\n return belongsTo<User>("foreign_key");\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If the parent model does not use ",(0,s.jsx)(n.code,{children:"id"})," as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the ",(0,s.jsx)(n.code,{children:"belongsTo"})," method specifying the parent table's custom key:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'/*! Get the user that owns the phone. */\nstd::unique_ptr<BelongsTo<Phone, User>>\nuser()\n{\n return belongsTo<User>("foreign_key", "owner_key");\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The third ",(0,s.jsx)(n.code,{children:"belongsTo"}),' parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snake_case" this relation name and suffix it with a ',(0,s.jsx)(n.code,{children:"_"})," followed by the name of the parent model's primary key column to generate foreign key, the ",(0,s.jsx)(n.code,{children:"__func__"})," predefined identifier is ideal for this. The relation name is also used in BelongsTo's ",(0,s.jsx)(n.code,{children:"associate"})," and ",(0,s.jsx)(n.code,{children:"disassociate"})," methods:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"/*! Get the user that owns the phone. */\nstd::unique_ptr<BelongsTo<Phone, User>>\nsomeUser()\n{\n return belongsTo<User>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_user_id\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The relation name will be guessed from the type-id of the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be ",(0,s.jsx)(n.code,{children:"user"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"one-to-many",children:"One To Many"}),"\n",(0,s.jsxs)(n.p,{children:["A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models. For example, a blog post may have an infinite number of comments. Like all other TinyORM relationships, one-to-many relationships are defined by defining a ",(0,s.jsx)(n.code,{children:"hasMany<Related>"})," method on your TinyORM model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef POST_HPP\n#define POST_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/comment.hpp"\n\nusing Orm::Tiny::Model;\n\nclass Post final : public Model<Post, Comment>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the comments for the blog post. */\n std::unique_ptr<HasMany<Post, Comment>>\n comments()\n {\n return hasMany<Comment>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"comments", [](auto &v) { v(&Post::comments); }},\n };\n};\n\n#endif // POST_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Remember, TinyORM will automatically determine the proper foreign key column for the ",(0,s.jsx)(n.code,{children:"Comment"}),' model. By convention, TinyORM will take the "snake_case" name of the parent model and suffix it with ',(0,s.jsx)(n.code,{children:"_id"}),". So, in this example, TinyORM will assume the foreign key column on the ",(0,s.jsx)(n.code,{children:"Comment"})," model is ",(0,s.jsx)(n.code,{children:"post_id"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Once the relationship method has been defined, we can access the ",(0,s.jsx)(n.code,{children:"QVector<Related *>"})," of related comments by Model's ",(0,s.jsx)(n.code,{children:"getRelationValue<Related, Container = QVector>"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/post.hpp"\n\nauto comments = Post::find(1)->getRelationValue<Comment>("comments");\n\nfor (auto *comment : comments) {\n //\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Since all relationships also serve as ",(0,s.jsx)(n.a,{href:"/database/query-builder",children:"query builders"}),", you may add further constraints to the relationship query by calling the ",(0,s.jsx)(n.code,{children:"comments"})," method and continuing to chain conditions onto the query, all the ",(0,s.jsx)(n.code,{children:"TinyBuilder"})," methods which are related to building queries are proxied:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto comment = Post::find(1)->comments()\n ->whereEq("title", "foo")\n .first();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Like the ",(0,s.jsx)(n.code,{children:"hasOne"})," method, you may also override the foreign and local keys by passing additional arguments to the ",(0,s.jsx)(n.code,{children:"hasMany"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'return hasMany<Comment>("foreign_key");\n\nreturn hasMany<Comment>("foreign_key", "local_key");\n'})}),"\n",(0,s.jsx)(n.h3,{id:"one-to-many-inverse",children:"One To Many (Inverse) / Belongs To"}),"\n",(0,s.jsxs)(n.p,{children:["Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a ",(0,s.jsx)(n.code,{children:"hasMany"})," relationship, define a relationship method on the child model which calls the ",(0,s.jsx)(n.code,{children:"belongsTo"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef COMMENT_HPP\n#define COMMENT_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/post.hpp"\n\nusing Orm::Tiny::Model;\n\nclass Comment final : public Model<Comment, Post>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the post that owns the comment. */\n std::unique_ptr<BelongsTo<Comment, Post>>\n post()\n {\n return belongsTo<Post>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"post", [](auto &v) { v(&Comment::post); }},\n };\n};\n\n#endif // COMMENT_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Once the relationship has been defined, we can retrieve a comment's parent post by Model's ",(0,s.jsx)(n.code,{children:"getRelationValue<Related, Tag>"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/comment.hpp"\n\nauto comment = Comment::find(1);\n\nreturn comment->getRelationValue<Post, Orm::One>("post")->getAttribute<QString>("title");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["In the example above, TinyORM will attempt to find a ",(0,s.jsx)(n.code,{children:"Post"})," model that has an ",(0,s.jsx)(n.code,{children:"id"})," which matches the ",(0,s.jsx)(n.code,{children:"post_id"})," column on the ",(0,s.jsx)(n.code,{children:"Comment"})," model."]}),"\n",(0,s.jsxs)(n.p,{children:["TinyORM determines the foreign key name by examining the type-name of the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter and suffixing the type-name with a ",(0,s.jsx)(n.code,{children:"_"})," followed by the name of the parent model's primary key column. So, in this case, TinyORM assumes that the ",(0,s.jsx)(n.code,{children:"Post"})," model's foreign key on the ",(0,s.jsx)(n.code,{children:"comments"})," table is ",(0,s.jsx)(n.code,{children:"post_id"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["However, if the foreign key for your relationship does not follow these conventions, you may pass a custom foreign key name as the first argument to the ",(0,s.jsx)(n.code,{children:"belongsTo"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'/*! Get the post that owns the comment. */\nstd::unique_ptr<BelongsTo<Comment, Post>>\npost()\n{\n return belongsTo<Post>("foreign_key");\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If your parent model does not use ",(0,s.jsx)(n.code,{children:"id"})," as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the ",(0,s.jsx)(n.code,{children:"belongsTo"})," method specifying your parent table's custom key:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'/*! Get the post that owns the comment. */\nstd::unique_ptr<BelongsTo<Comment, Post>>\npost()\n{\n return belongsTo<Post>("foreign_key", "owner_key");\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The third ",(0,s.jsx)(n.code,{children:"belongsTo"}),' parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snake_case" this relation name and suffix it with a ',(0,s.jsx)(n.code,{children:"_"})," followed by the name of the parent model's primary key column to generate foreign key, the ",(0,s.jsx)(n.code,{children:"__func__"})," predefined identifier is ideal for this. The relation name is also used in BelongsTo's ",(0,s.jsx)(n.code,{children:"associate"})," and ",(0,s.jsx)(n.code,{children:"disassociate"})," methods:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"/*! Get the post that owns the comment. */\nstd::unique_ptr<BelongsTo<Comment, Post>>\nsomePost()\n{\n return belongsTo<Post>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_post_id\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The relation name will be guessed from the type-id of the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be ",(0,s.jsx)(n.code,{children:"user"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"default-models",children:"Default Models"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"belongsTo"}),", and ",(0,s.jsx)(n.code,{children:"hasOne"})," relationships allow you to define a default model that will be returned if the given relationship is ",(0,s.jsx)(n.code,{children:"null"}),". This pattern is often referred to as the ",(0,s.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Null_Object_pattern",children:"Null Object pattern"})," and can help remove conditional checks in your code. In the following example, the ",(0,s.jsx)(n.code,{children:"user"})," relation will return an empty ",(0,s.jsx)(n.code,{children:"User"})," model if no user is attached to the ",(0,s.jsx)(n.code,{children:"Post"})," model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"/*! Get the author of the post. */\nstd::unique_ptr<BelongsTo<Post, User>>\nuser()\n{\n // Ownership of a unique_ptr()\n auto relation = belongsTo<User>();\n\n relation->withDefault();\n\n return relation;\n}\n"})}),"\n",(0,s.jsxs)(n.p,{children:["To populate the default model with attributes, you may pass the vector of attributes to the ",(0,s.jsx)(n.code,{children:"withDefault"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'/*! Get the author of the post. */\nstd::unique_ptr<BelongsTo<Post, User>>\nuser()\n{\n // Ownership of a unique_ptr()\n auto relation = belongsTo<User>();\n\n relation->withDefault({{"name", "Guest Author"},\n {"is_active", false}});\n\n return relation;\n}\n'})}),"\n",(0,s.jsx)(n.h2,{id:"many-to-many",children:"Many To Many Relationships"}),"\n",(0,s.jsxs)(n.p,{children:["Many-to-many relations are slightly more complicated than ",(0,s.jsx)(n.code,{children:"hasOne"})," and ",(0,s.jsx)(n.code,{children:"hasMany"}),' relationships. An example of a many-to-many relationship is a user that has many roles and those roles are also shared by other users in the application. For example, a user may be assigned the role of "Author" and "Editor"; however, those roles may also be assigned to other users as well. So, a user has many roles and a role has many users.']}),"\n",(0,s.jsx)(n.h4,{id:"table-structure",children:"Table Structure"}),"\n",(0,s.jsxs)(n.p,{children:["To define this relationship, three database tables are needed: ",(0,s.jsx)(n.code,{children:"users"}),", ",(0,s.jsx)(n.code,{children:"roles"}),", and ",(0,s.jsx)(n.code,{children:"role_user"}),". The ",(0,s.jsx)(n.code,{children:"role_user"})," table is derived from the alphabetical order of the related model names and contains ",(0,s.jsx)(n.code,{children:"user_id"})," and ",(0,s.jsx)(n.code,{children:"role_id"})," columns. This table is used as an intermediate table linking the users and roles."]}),"\n",(0,s.jsxs)(n.p,{children:["Remember, since a role can belong to many users, we cannot simply place a ",(0,s.jsx)(n.code,{children:"user_id"})," column on the ",(0,s.jsx)(n.code,{children:"roles"})," table. This would mean that a role could only belong to a single user. In order to provide support for roles being assigned to multiple users, the ",(0,s.jsx)(n.code,{children:"role_user"})," table is needed. We can summarize the relationship's table structure like so:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-text",children:"users\n id - integer\n name - string\n\nroles\n id - integer\n name - string\n\nrole_user\n user_id - integer\n role_id - integer\n"})}),"\n",(0,s.jsx)(n.h4,{id:"model-structure",children:"Model Structure"}),"\n",(0,s.jsxs)(n.p,{children:["Many-to-many relationships are defined by writing a method that returns the result of the ",(0,s.jsx)(n.code,{children:"belongsToMany"})," method. The ",(0,s.jsx)(n.code,{children:"belongsToMany"})," method is provided by the ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Model<Derived, AllRelations...>"})," base class that is used by all of your application's TinyORM models. For example, let's define a ",(0,s.jsx)(n.code,{children:"roles"})," method on our ",(0,s.jsx)(n.code,{children:"User"})," model. The first argument passed to this method is the name of the related model class:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/relations/pivot.hpp>\n\n#include "models/role.hpp"\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::Relations::Pivot;\n\nclass User final : public Model<User, Role, Pivot>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The roles that belong to the user. */\n std::unique_ptr<BelongsToMany<User, Role>>\n roles()\n {\n return belongsToMany<Role>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"roles", [](auto &v) { v(&User::roles); }},\n };\n};\n\n#endif // USER_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Once the relationship is defined, you may access the user's roles as the ",(0,s.jsx)(n.code,{children:"QVector<Related *>"})," by Model's ",(0,s.jsx)(n.code,{children:"getRelationValue<Related, Container = QVector>"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include "models/user.hpp"\n\nauto user = User::find(1);\n\nfor (auto *role : user->getRelationValue<Role>("roles"))\n qDebug() << role->getAttribute<quint64>("id");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the ",(0,s.jsx)(n.code,{children:"roles"})," method and continuing to chain conditions onto the query:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto roles = User::find(1)->roles()->orderBy("name").get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["To determine the table name of the relationship's intermediate table, TinyORM will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a first argument to the ",(0,s.jsx)(n.code,{children:"belongsToMany"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'return belongsToMany<Role>("role_user");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["In addition to customizing the name of the intermediate table, you may also customize the column names of the keys on the table by passing additional arguments to the ",(0,s.jsx)(n.code,{children:"belongsToMany"})," method. The second argument is the foreign key name of the model on which you are defining the relationship, while the third argument is the foreign key name of the model that you are joining to:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'return belongsToMany<Role>("role_user", "user_id", "role_id");\n'})}),"\n",(0,s.jsx)(n.p,{children:"The fourth and fifth arguments are primary key names on models in the many-to-many relation and the sixth argument is the relation name."}),"\n",(0,s.jsxs)(n.p,{children:["The relation name is used during ",(0,s.jsx)(n.a,{href:"#touching-parent-timestamps",children:"Touching Parent Timestamps"})," and will be guessed from the type-id of the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter, TinyORM takes this name, changes the first character to lower case, and appends ",(0,s.jsx)(n.code,{children:"s"})," character. So in the example above, the relation name will be ",(0,s.jsx)(n.code,{children:"roles"}),"."]}),"\n",(0,s.jsx)(n.h4,{id:"defining-the-inverse-of-the-relationship-1",children:"Defining The Inverse Of The Relationship"}),"\n",(0,s.jsxs)(n.p,{children:['To define the "inverse" of a many-to-many relationship, you should define a method on the related model which also returns the result of the ',(0,s.jsx)(n.code,{children:"belongsToMany"})," method. To complete our user / role example, let's define the ",(0,s.jsx)(n.code,{children:"users"})," method on the ",(0,s.jsx)(n.code,{children:"Role"})," model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef ROLE_HPP\n#define ROLE_HPP\n\n#include <orm/tiny/relations/pivot.hpp>\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::Relations::Pivot;\n\nclass User; // Forward declaration to avoid cyclic dependency\n\nclass Role final : public Model<Role, User, Pivot>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The users that belong to the role. */\n std::unique_ptr<BelongsToMany<Role, User>>\n users()\n {\n return belongsToMany<User>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"users", [](auto &v) { v(&Role::users); }},\n };\n};\n\n#endif // ROLE_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["As you can see, the relationship is defined exactly the same as its ",(0,s.jsx)(n.code,{children:"User"})," model counterpart with the exception of referencing the ",(0,s.jsx)(n.code,{children:"User"})," model. Since we're reusing the ",(0,s.jsx)(n.code,{children:"belongsToMany"}),' method, all of the usual table and key customization options are available when defining the "inverse" of many-to-many relationships.']}),"\n",(0,s.jsx)(n.h3,{id:"retrieving-intermediate-table-columns",children:"Retrieving Intermediate Table Columns"}),"\n",(0,s.jsxs)(n.p,{children:["As you have already learned, working with many-to-many relations requires the presence of an intermediate table. TinyORM provides some very helpful ways of interacting with this table. For example, let's assume our ",(0,s.jsx)(n.code,{children:"User"})," model has many ",(0,s.jsx)(n.code,{children:"Role"})," models that it is related to. After accessing this relationship, we may access the intermediate table using the ",(0,s.jsx)(n.code,{children:"pivot"})," attribute on the models:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include "models/user.hpp"\n\nusing Orm::Tiny::Relations::Pivot;\n\nauto user = User::find(1);\n\nfor (auto *role : user->getRelationValue<Role>("roles"))\n qDebug() << role->getRelation<Pivot, Orm::One>("pivot")\n ->getAttribute("created_at");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Notice that each ",(0,s.jsx)(n.code,{children:"Role"})," model we retrieve has automatically assigned a ",(0,s.jsx)(n.code,{children:"pivot"})," relationship. This relation contains a model representing the intermediate table and it is an instance of the ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Relations::Pivot"})," model class."]}),"\n",(0,s.jsxs)(n.p,{children:["By default, only the model keys will be present on the ",(0,s.jsx)(n.code,{children:"pivot"})," model. If your intermediate table contains extra attributes, you must specify them when defining the relationship:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'// Ownership of a unique_ptr()\nauto relation = belongsToMany<Role>();\n\nrelation->withPivot({"active", "created_by"});\n\nreturn relation;\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If you would like your intermediate table to have ",(0,s.jsx)(n.code,{children:"created_at"})," and ",(0,s.jsx)(n.code,{children:"updated_at"})," timestamps that are automatically maintained by TinyORM, call the ",(0,s.jsx)(n.code,{children:"withTimestamps"})," method when defining the relationship:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"// Ownership of a unique_ptr()\nauto relation = belongsToMany<Role>();\n\nrelation->withTimestamps();\n\nreturn relation;\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["Intermediate tables that utilize TinyORM's automatically maintained timestamps are required to have both ",(0,s.jsx)(n.code,{children:"created_at"})," and ",(0,s.jsx)(n.code,{children:"updated_at"})," timestamp columns."]})}),"\n",(0,s.jsxs)(n.h4,{id:"customizing-the-pivot-relation-name",children:["Customizing The ",(0,s.jsx)(n.code,{children:"pivot"})," Relation Name"]}),"\n",(0,s.jsxs)(n.p,{children:["As noted previously, attributes from the intermediate table may be accessed on models via the ",(0,s.jsx)(n.code,{children:"pivot"})," relation name. However, you are free to customize the name of this relation to better reflect its purpose within your application."]}),"\n",(0,s.jsxs)(n.p,{children:["For example, if your application contains users that may subscribe to podcasts, you likely have a many-to-many relationship between users and podcasts. If this is the case, you may wish to rename your intermediate table relation name to ",(0,s.jsx)(n.code,{children:"subscription"})," instead of ",(0,s.jsx)(n.code,{children:"pivot"}),". This can be done using the ",(0,s.jsx)(n.code,{children:"as"})," method when defining the relationship:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'// Ownership of a unique_ptr()\nauto relation = belongsToMany<Podcast>();\n\nrelation->as("subscription")\n .withTimestamps();\n\nreturn relation;\n'})}),"\n",(0,s.jsx)(n.p,{children:"Once the custom intermediate table relation name has been specified, you may access the intermediate table data using the customized name:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include "models/user.hpp"\n\nusing Orm::Tiny::Relations::Pivot;\n\nauto users = User::with("podcasts")->get();\n\nfor (auto &user : users)\n for (auto *podcast : user.getRelation<Podcast>("podcasts"))\n qDebug() << podcast->getRelation<Pivot, Orm::One>("subscription")\n ->getAttribute("created_at");\n'})}),"\n",(0,s.jsx)(n.h3,{id:"defining-custom-intermediate-table-models",children:"Defining Custom Intermediate Table Models"}),"\n",(0,s.jsxs)(n.p,{children:["If you would like to define a custom model to represent the intermediate table of your many-to-many relationship, you may pass the custom pivot type as a second template argument to the ",(0,s.jsx)(n.code,{children:"belongsToMany<Related, PivotType = Pivot>"})," method when defining the relationship. Custom pivot models give you the opportunity to define additional methods on the pivot model."]}),"\n",(0,s.jsxs)(n.p,{children:["Custom many-to-many pivot models should extend the ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Relations::BasePivot<PivotModel>"})," class. For example, we may define a ",(0,s.jsx)(n.code,{children:"User"})," model which uses a custom ",(0,s.jsx)(n.code,{children:"RoleUser"})," pivot model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/relations/pivot.hpp>\n\n#include "models/role.hpp"\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::Relations::Pivot;\n\nclass User final : public Model<User, Role, Pivot>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The roles that belong to the user. */\n std::unique_ptr<BelongsToMany<User, Role, RoleUser>>\n roles()\n {\n return belongsToMany<Role, RoleUser>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"roles", [](auto &v) { v(&User::roles); }},\n };\n};\n\n#endif // USER_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["When defining the ",(0,s.jsx)(n.code,{children:"RoleUser"})," model, you should extend the ",(0,s.jsx)(n.code,{children:"Orm::Tiny::Relations::BasePivot<PivotModel>"})," class:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"#pragma once\n#ifndef ROLEUSER_HPP\n#define ROLEUSER_HPP\n\n#include <orm/tiny/relations/basepivot.hpp>\n\nusing Orm::Tiny::Relations::BasePivot;\n\nclass RoleUser final : public BasePivot<RoleUser>\n{\n friend Model;\n friend BasePivot;\n\n using BasePivot::BasePivot;\n};\n\n#endif // ROLEUSER_HPP\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You have to pass a custom pivot type to the ",(0,s.jsx)(n.code,{children:"AllRelations"})," template parameter pack on ",(0,s.jsx)(n.code,{children:"Model<Derived, AllRelations...>"})," so that the ",(0,s.jsx)(n.code,{children:"Model"})," knows how to generate a ",(0,s.jsx)(n.code,{children:"std::variant"}),", which holds all the relations and also you have to add a new mapping from the relation name to the custom pivot model type-id, this is described in more detail in the ",(0,s.jsx)(n.a,{href:"#common-rules",children:"Common Rules"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#pragma once\n#ifndef ROLE_HPP\n#define ROLE_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/roleuser.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User; // Forward declaration to avoid cyclic dependency\n\nclass Role final : public Model<Role, User, RoleUser>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The users that belong to the role. */\n std::unique_ptr<BelongsToMany<Role, User>>\n users()\n {\n return belongsToMany<User>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"users", [](auto &v) { v(&Role::users); }},\n };\n};\n\n#endif // ROLE_HPP\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Once the custom pivot model ",(0,s.jsx)(n.code,{children:"RoleUser"})," has been defined, ",(0,s.jsx)(n.code,{children:"getRelation"})," or ",(0,s.jsx)(n.code,{children:"getRelationValue"})," method returns proper pivot type:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include "models/user.hpp"\n\nauto users = User::with("roles")->get();\n\nfor (auto &user : users)\n for (auto *role : user.getRelation<Role>("roles"))\n qDebug() << role->getRelation<RoleUser, Orm::One>("pivot")\n ->getAttribute("created_at");\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["Custom Pivot models may not use the ",(0,s.jsx)(n.code,{children:"SoftDeletes"})," base class. If you need to soft delete pivot records consider converting your pivot model to an actual TinyORM model."]})}),"\n",(0,s.jsx)(n.h4,{id:"custom-pivot-models-and-incrementing-ids",children:"Custom Pivot Models And Incrementing IDs"}),"\n",(0,s.jsxs)(n.p,{children:["If you have defined a many-to-many relationship that uses a custom pivot model, and that pivot model has an auto-incrementing primary key, you should ensure your custom pivot model class defines an ",(0,s.jsx)(n.code,{children:"u_incrementing"})," data member that is set to ",(0,s.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"/*! Indicates if the IDs are auto-incrementing. */\nbool u_incrementing = true;\n"})}),"\n",(0,s.jsx)(n.h4,{id:"closer-look-at-defining-custom-intermediate-table-models",children:"Closer Look At Defining Custom Intermediate Table Models"}),"\n",(0,s.jsx)(n.p,{children:"I can tell that defining a custom intermediate table models is the most confusing part of the TinyORM framework, let's look closer at it."}),"\n",(0,s.jsxs)(n.p,{children:["If you are defining a custom ",(0,s.jsx)(n.code,{children:"RoleUser"})," intermediate table for the ",(0,s.jsx)(n.code,{children:"Role"})," model like in the example above then you have to pass the ",(0,s.jsx)(n.code,{children:"RoleUser"})," pivot type as the second template argument to the ",(0,s.jsx)(n.code,{children:"User::roles()"})," ",(0,s.jsx)(n.code,{children:"belongsToMany"})," relationship method and you have to pass the ",(0,s.jsx)(n.code,{children:"RoleUser"})," pivot type to the ",(0,s.jsx)(n.code,{children:"AllRelations"})," template parameter pack ",(0,s.jsxs)(n.strong,{children:["on the ",(0,s.jsx)(n.code,{children:"Role"})," model!"]})]}),"\n",(0,s.jsxs)(n.p,{children:["Do you see the confusing part? In short, if defining the ",(0,s.jsx)(n.code,{children:"User::roles()"})," relation with the custom ",(0,s.jsx)(n.code,{children:"UserRole"})," pivot model then add the ",(0,s.jsx)(n.code,{children:"UserRole"})," type to the ",(0,s.jsx)(n.code,{children:"AllRelations"})," template parameter pack on the ",(0,s.jsx)(n.code,{children:"Role"})," model."]}),"\n",(0,s.jsxs)(n.p,{children:["The same is true for the basic ",(0,s.jsx)(n.code,{children:"Pivot"})," model, if you are using a basic pivot model and not a custom pivot model you still need to add the ",(0,s.jsx)(n.code,{children:"Pivot"})," type to the ",(0,s.jsx)(n.code,{children:"AllRelations"})," template parameter pack on the ",(0,s.jsx)(n.code,{children:"Model"})," class!"]}),"\n",(0,s.jsxs)(n.p,{children:["The reason for all of this is that the ",(0,s.jsx)(n.code,{children:"Model"})," knows how to generate and work with the ",(0,s.jsx)(n.code,{children:"std::variant"})," that holds the pivot model in the ",(0,s.jsx)(n.code,{children:"Model::m_relations"})," data member map, then you can get the pivot model using the ",(0,s.jsx)(n.code,{children:"Model::getRelationValue"})," or ",(0,s.jsx)(n.code,{children:"Model::getRelation"})," methods."]}),"\n",(0,s.jsx)(n.h5,{id:"user-data-members-on-custom-intermediate-table-models",children:"User Data Members on Custom Intermediate Table Models"}),"\n",(0,s.jsxs)(n.p,{children:["This is another nonstandard part of the custom pivot models. The ",(0,s.jsx)(n.code,{children:"u_connection"})," and ",(0,s.jsx)(n.code,{children:"u_timestamps"})," user data members and the ",(0,s.jsx)(n.code,{children:"CREATED_AT()"})," and ",(0,s.jsx)(n.code,{children:"UPDATED_AT()"})," static getter methods are ignored when obtaining pivot records from the database during the lazy or eager loading."]}),"\n",(0,s.jsx)(n.p,{children:"Let's describe how these data members are resolved:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"u_connection"})," - inferred from the parent model"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"u_timestamps"})," - true if obtained pivot attributes contain both the ",(0,s.jsx)(n.code,{children:"CREATED_AT"})," and ",(0,s.jsx)(n.code,{children:"UPDATED_AT"})," attributes"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"CREATED_AT"}),", ",(0,s.jsx)(n.code,{children:"UPDATED_AT"})," - inferred from the parent model, can be overridden using the ",(0,s.jsx)(n.code,{children:"withTimestamps()"})," method"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["All these data members are taken into account normally when you call the ",(0,s.jsx)(n.code,{children:"create"}),", ",(0,s.jsx)(n.code,{children:"save"}),", ",(0,s.jsx)(n.code,{children:"update"}),", ... on the Custom Pivot models!"]}),"\n",(0,s.jsx)(n.h2,{id:"querying-relations",children:"Querying Relations"}),"\n",(0,s.jsxs)(n.p,{children:["Since all TinyORM relationships are defined via methods, you may call those methods to obtain an instance of the relationship without actually executing a query to load the related models. In addition, all types of TinyORM relationships also serve as ",(0,s.jsx)(n.a,{href:"/database/query-builder",children:"query builders"}),", allowing you to continue to chain constraints onto the relationship query before finally executing the SQL query against your database."]}),"\n",(0,s.jsxs)(n.p,{children:["For example, imagine a blog application in which a ",(0,s.jsx)(n.code,{children:"User"})," model has many associated ",(0,s.jsx)(n.code,{children:"Post"})," models:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/post.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User, Post>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get all of the posts for the user. */\n std::unique_ptr<HasMany<User, Post>>\n posts()\n {\n return hasMany<Post>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"posts", [](auto &v) { v(&User::posts); }},\n };\n};\n'})}),"\n",(0,s.jsxs)(n.p,{children:["You may query the ",(0,s.jsx)(n.code,{children:"posts"})," relationship and add additional constraints to the relationship like so:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nauto user = User::find(1);\n\nuser->posts()->whereEq("active", 1).get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["You are able to use any of the TinyORM ",(0,s.jsx)(n.a,{href:"/database/query-builder",children:"query builder's"})," methods on the relationship, so be sure to explore the query builder documentation to learn about all of the methods that are available to you."]}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["All the ",(0,s.jsx)(n.code,{children:"TinyBuilder"})," methods which are related to building queries are proxied on the ",(0,s.jsx)(n.code,{children:"Relation"})," base class."]})}),"\n",(0,s.jsxs)(n.h4,{id:"chaining-orwhere-clauses-after-relationships",children:["Chaining ",(0,s.jsx)(n.code,{children:"orWhere"})," Clauses After Relationships"]}),"\n",(0,s.jsxs)(n.p,{children:["As demonstrated in the example above, you are free to add additional constraints to relationships when querying them. However, be careful when chaining ",(0,s.jsx)(n.code,{children:"orWhere"})," clauses onto a relationship, as the ",(0,s.jsx)(n.code,{children:"orWhere"})," clauses will be logically grouped at the same level as the relationship constraint:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'user->posts()\n ->whereEq("active", 1)\n .orWhere("votes", ">=", 100)\n .get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The example above will generate the following SQL. As you can see, the ",(0,s.jsx)(n.code,{children:"or"})," clause instructs the query to return ",(0,s.jsx)(n.em,{children:"any"})," user with greater than 100 votes. The query is no longer constrained to a specific user:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sql",children:"select *\nfrom posts\nwhere user_id = ? and active = 1 or votes >= 100\n"})}),"\n",(0,s.jsxs)(n.p,{children:["In most situations, you should use ",(0,s.jsx)(n.a,{href:"/database/query-builder#logical-grouping",children:"logical groups"})," to group the conditional checks between parentheses:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'user->posts()\n ->where([](auto &query)\n {\n query.whereEq("active", 1)\n .orWhere("votes", ">=", 100);\n })\n .get();\n'})}),"\n",(0,s.jsx)(n.p,{children:"The example above will produce the following SQL. Note that the logical grouping has properly grouped the constraints and the query remains constrained to a specific user:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sql",children:"select *\nfrom posts\nwhere user_id = ? and (active = 1 or votes >= 100)\n"})}),"\n",(0,s.jsx)(n.h3,{id:"relationship-methods",children:"Relationship Methods"}),"\n",(0,s.jsxs)(n.p,{children:["If you do not need to add additional constraints to the TinyORM relationship query, you may access the relationship directly. For example, continuing to use our ",(0,s.jsx)(n.code,{children:"User"})," and ",(0,s.jsx)(n.code,{children:"Post"})," example models, we may access all of a user's posts like so:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nauto user = User::find(1);\n\nfor (auto *post : user->getRelationValue<Post>("posts")) {\n //\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"getRelationValue<Related>"}),' method performs "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use ',(0,s.jsx)(n.a,{href:"#eager-loading",children:"eager loading"})," to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations."]}),"\n",(0,s.jsxs)(n.p,{children:["To access eager loaded relationship use Model's ",(0,s.jsx)(n.code,{children:"getRelation<Related>"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto user = User::find(1);\n\nfor (auto *post : user->getRelation<Post>("posts")) {\n //\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:["As described above TinyORM offers two methods to access relationships; ",(0,s.jsx)(n.code,{children:"getRelation"})," and ",(0,s.jsx)(n.code,{children:"getRelationValue"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"getRelation"}),' method is for "eager loaded" relations, when the relationship is not loaded, it throws the exception ',(0,s.jsx)(n.code,{children:"RelationNotLoadedError"}),". The ",(0,s.jsx)(n.code,{children:"getRelationValue"}),' is for "lazy loading", when the relationship is not loaded, it will load it.']}),"\n",(0,s.jsxs)(n.p,{children:["Both methods have two overloads, the ",(0,s.jsx)(n.code,{children:"getRelation<Related, Container = QVector>"})," overload is for obtaining many type relationships:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto posts = User::find(1)->getRelation<Post>("posts");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"getRelation<Related, Tag>"}),' overload is for obtaining "one" type relationships:']}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto user = Post::find(1)->getRelation<User, Orm::One>("user");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The same is true for the ",(0,s.jsx)(n.code,{children:"getRelationValue"})," method."]}),"\n",(0,s.jsx)(n.h3,{id:"querying-relationship-existence",children:"Querying Relationship Existence"}),"\n",(0,s.jsxs)(n.p,{children:["When retrieving model records, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the ",(0,s.jsx)(n.code,{children:"has"})," and ",(0,s.jsx)(n.code,{children:"orHas"})," methods:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/post.hpp"\n\n// Retrieve all posts that have at least one comment...\nauto posts = Post::has("comments")->get();\n'})}),"\n",(0,s.jsx)(n.p,{children:"You may also specify an operator and count value to further customize the query:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'// Retrieve all posts that have three or more comments...\nauto posts = Post::has("comments", ">=", 3)->get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Nested ",(0,s.jsx)(n.code,{children:"has"}),' statements may be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment that has at least one image:']}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'// Retrieve posts that have at least one comment with images...\nauto posts = Post::has<Image>("comments.images")->get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If you need even more power, you may use the ",(0,s.jsx)(n.code,{children:"whereHas"})," and ",(0,s.jsx)(n.code,{children:"orWhereHas"})," methods to define additional query constraints on your ",(0,s.jsx)(n.code,{children:"has"})," queries, such as inspecting the content of a comment:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'// Retrieve posts with at least one comment containing words like code%...\nauto posts = Post::whereHas("comments", [](auto &query)\n{\n query.where("content", LIKE, "code%");\n})->get();\n\n// Retrieve posts with at least ten comments containing words like code%...\nauto posts = Post::whereHas("comments", [](auto &query)\n{\n query.where("content", LIKE, "code%");\n}, ">=", 10)->get();\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsx)(n.p,{children:"TinyORM does not currently support querying for relationship existence across databases. The relationships must exist within the same database."})}),"\n",(0,s.jsx)(n.h4,{id:"related-template-parameter",children:"Related template parameter"}),"\n",(0,s.jsxs)(n.p,{children:["All the ",(0,s.jsx)(n.code,{children:"has"}),"-related methods are templated by the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter, it looks something like the following ",(0,s.jsx)(n.code,{children:"has<Related>(..., const std::function<void(CallbackType<Related> &)> &callback = nullptr)"}),", you can pass a query callback to this methods and on the base of the ",(0,s.jsx)(n.code,{children:"Related"})," template argument will be decided whether the ",(0,s.jsx)(n.code,{children:"Orm::QueryBuilder"})," or ",(0,s.jsx)(n.code,{children:"Orm::TinyBuilder<Related>"})," will be passed to the callback. As you can see this ",(0,s.jsx)(n.code,{children:"Related"})," parameter exists because the ",(0,s.jsx)(n.code,{children:"Orm::TinyBuilder<Related>"})," needs it."]}),"\n",(0,s.jsx)(n.p,{children:"The rule of thumbs are:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["if you don't pass the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter or you pass ",(0,s.jsx)(n.code,{children:"void"})," then the ",(0,s.jsx)(n.code,{children:"Orm::QueryBuilder &"})," will be passed to the callback"]}),"\n",(0,s.jsxs)(n.li,{children:["if you pass it, then the ",(0,s.jsx)(n.code,{children:"Orm::TinyBuilder<Related> &"})," will be passed to the callback"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"Related"})," has to be of the same type as a relation name passed to the ",(0,s.jsx)(n.code,{children:"has"}),"-related method (a real type of the relation eg. type of the ",(0,s.jsx)(n.code,{children:"posts"})," relation name is ",(0,s.jsx)(n.code,{children:"Post"}),")"]}),"\n",(0,s.jsxs)(n.li,{children:["you have to always pass the ",(0,s.jsx)(n.code,{children:"Related"})," template parameter for nested relations, you can not use nested relations with ",(0,s.jsx)(n.code,{children:"Related = void"})]}),"\n",(0,s.jsxs)(n.li,{children:['in nested relations, where you can pass more relation names using "dot" notation, ',(0,s.jsx)(n.code,{children:"Related"})," has to be of the same type as the ",(0,s.jsx)(n.strong,{children:"last"})," relation name passed to the ",(0,s.jsx)(n.code,{children:"has"}),"-related method like you can see in the nested example above or below"]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"querying-relationship-absence",children:"Querying Relationship Absence"}),"\n",(0,s.jsxs)(n.p,{children:["When retrieving model records, you may wish to limit your results based on the absence of a relationship. For example, imagine you want to retrieve all blog posts that ",(0,s.jsx)(n.strong,{children:"don't"})," have any comments. To do so, you may pass the name of the relationship to the ",(0,s.jsx)(n.code,{children:"doesntHave"})," and ",(0,s.jsx)(n.code,{children:"orDoesntHave"})," methods:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/post.hpp"\n\nauto posts = Post::doesntHave("comments")->get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If you need even more power, you may use the ",(0,s.jsx)(n.code,{children:"whereDoesntHave"})," and ",(0,s.jsx)(n.code,{children:"orWhereDoesntHave"})," methods to add additional query constraints to your ",(0,s.jsx)(n.code,{children:"doesntHave"})," queries, such as inspecting the content of a comment:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto posts = Post::whereDoesntHave("comments", [](auto &query)\n{\n query.where("content", LIKE, "code%");\n})->get();\n'})}),"\n",(0,s.jsx)(n.p,{children:'You may use "dot" notation to execute a query against a nested relationship. For example, the following query will retrieve all posts that have comments from authors that are not banned:'}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto posts = Post::whereDoesntHave<Author>("comments.author",\n [](auto &query)\n{\n query.where("banned", false);\n})->get();\n'})}),"\n",(0,s.jsx)(n.h2,{id:"eager-loading",children:"Eager Loading"}),"\n",(0,s.jsxs)(n.p,{children:["When accessing TinyORM relationships by Model's ",(0,s.jsx)(n.code,{children:"getRelationValue"}),' method, the related models are "lazy loaded". This means the relationship data is not actually loaded until you first access them. However, TinyORM can "eager load" relationships at the time you query the parent model. Eager loading alleviates the "N + 1" query problem. To illustrate the N + 1 query problem, consider a ',(0,s.jsx)(n.code,{children:"Book"}),' model that "belongs to" to an ',(0,s.jsx)(n.code,{children:"Author"})," model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using Orm::Tiny::Model;\n\nclass Book final : public Model<Book, Author>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the author that wrote the book. */\n std::unique_ptr<BelongsTo<Book, Author>>\n author()\n {\n return belongsTo<Author>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"author", [](auto &v) { v(&Book::author); }},\n };\n};\n'})}),"\n",(0,s.jsx)(n.p,{children:"Now, let's retrieve all books and their authors:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include "models/book.hpp"\n\nauto books = Book::all();\n\nfor (auto &book : books)\n qDebug() << book.getRelationValue<Author, Orm::One>("author")\n ->getAttribute<QString>("name");\n'})}),"\n",(0,s.jsx)(n.p,{children:"This loop will execute one query to retrieve all of the books within the database table, then another query for each book in order to retrieve the book's author. So, if we have 25 books, the code above would run 26 queries: one for the original book, and 25 additional queries to retrieve the author of each book."}),"\n",(0,s.jsxs)(n.p,{children:["Thankfully, we can use eager loading to reduce this operation to just two queries. When building a query, you may specify which relationships should be eager loaded using the ",(0,s.jsx)(n.code,{children:"with"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto books = Book::with("author")->get();\n\nfor (auto &book : books)\n qDebug() << book.getRelation<Author, Orm::One>("author")\n ->getAttribute<QString>("name");\n'})}),"\n",(0,s.jsx)(n.p,{children:"For this operation, only two queries will be executed - one query to retrieve all of the books and one query to retrieve all of the authors for all of the books:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-sql",children:"select * from books\n\nselect * from authors where id in (1, 2, 3, 4, 5, ...)\n"})}),"\n",(0,s.jsx)(n.h4,{id:"eager-loading-multiple-relationships",children:"Eager Loading Multiple Relationships"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes you may need to eager load several different relationships. To do so, just pass a ",(0,s.jsx)(n.code,{children:"QVector<Orm::WithItem>"})," of relationships to the ",(0,s.jsx)(n.code,{children:"with"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto books = Book::with({"author", "publisher"})->get();\n'})}),"\n",(0,s.jsx)(n.h4,{id:"nested-eager-loading",children:"Nested Eager Loading"}),"\n",(0,s.jsx)(n.p,{children:"To eager a relationship's relationships, you may use \"dot\" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto books = Book::with("author.contacts")->get();\n'})}),"\n",(0,s.jsx)(n.h4,{id:"eager-loading-specific-columns",children:"Eager Loading Specific Columns"}),"\n",(0,s.jsx)(n.p,{children:"You may not always need every column from the relationships you are retrieving. For this reason, TinyORM allows you to specify which columns of the relationship you would like to retrieve:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto books = Book::with("author:id,name,book_id")->get();\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"warning",children:(0,s.jsxs)(n.p,{children:["When using this feature, you should always include the ",(0,s.jsx)(n.code,{children:"id"})," column and any relevant foreign key columns in the list of columns you wish to retrieve, otherwise relations will not be loaded correctly."]})}),"\n",(0,s.jsx)(n.h4,{id:"eager-loading-by-default",children:"Eager Loading By Default"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes you might want to always load some relationships when retrieving a model. To accomplish this, you may define a ",(0,s.jsx)(n.code,{children:"u_with"})," data member on the model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using Orm::Tiny::Model;\n\nclass Book final : public Model<Book, Author>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the author that wrote the book. */\n std::unique_ptr<BelongsTo<Book, Author>>\n author()\n {\n return belongsTo<Author>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"author", [](auto &v) { v(&Book::author); }},\n };\n\n /*! The relationships that should always be loaded. */\n QVector<QString> u_with {\n "author",\n };\n};\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If you would like to remove an item from the ",(0,s.jsx)(n.code,{children:"u_with"})," data member for a single query, you may use the ",(0,s.jsx)(n.code,{children:"without"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto books = Book::without("author")->get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If you would like to override all items within the ",(0,s.jsx)(n.code,{children:"u_with"})," data member for a single query, you may use the ",(0,s.jsx)(n.code,{children:"withOnly"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto books = Book::withOnly("genre")->get();\n'})}),"\n",(0,s.jsx)(n.h3,{id:"constraining-eager-loads",children:"Constraining Eager Loads"}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes you may wish to eager load a relationship but also specify additional query conditions for the eager loading query. You can accomplish this by passing a ",(0,s.jsx)(n.code,{children:"QVector<Orm::WithItem>"})," of relationships to the ",(0,s.jsx)(n.code,{children:"with"})," method where the ",(0,s.jsx)(n.code,{children:"name"})," data member of ",(0,s.jsx)(n.code,{children:"Orm::WithItem"})," struct is a relationship name and the ",(0,s.jsx)(n.code,{children:"constraints"})," data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the ",(0,s.jsx)(n.code,{children:"constraints"})," lambda expression is an underlying ",(0,s.jsx)(n.code,{children:"Orm::QueryBuilder"})," for a related model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nauto users = User::with({{"posts", [](auto &query)\n{\n query.where("title", "like", "%code%");\n}}})->get();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["In this example, TinyORM will only eager load posts where the post's ",(0,s.jsx)(n.code,{children:"title"})," column contains the word ",(0,s.jsx)(n.code,{children:"code"}),". You may call other ",(0,s.jsx)(n.a,{href:"/database/query-builder",children:"query builder"})," methods to further customize the eager loading operation:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto users = User::with({{"posts", [](auto &query)\n{\n query.orderBy("created_at", "desc");\n}}})->get();\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"limit"})," and ",(0,s.jsx)(n.code,{children:"take"})," query builder methods may not be used when constraining eager loads."]})}),"\n",(0,s.jsx)(n.h3,{id:"lazy-eager-loading",children:"Lazy Eager Loading"}),"\n",(0,s.jsx)(n.p,{children:"Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/book.hpp"\n\nauto book = Book::find(1);\n\nif (someCondition)\n book->load("author");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["You may load more relationships at once, to do so, just pass a ",(0,s.jsx)(n.code,{children:"QVector<Orm::WithItem>"})," of relationships to the ",(0,s.jsx)(n.code,{children:"load"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'Book::find(1)->load({"author", "publisher"});\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["So far, this only works on models, not on containers returned from Model's ",(0,s.jsx)(n.code,{children:"get"})," or ",(0,s.jsx)(n.code,{children:"all"})," methods."]})}),"\n",(0,s.jsxs)(n.p,{children:["If you need to set additional query constraints on the eager loading query, you may pass a ",(0,s.jsx)(n.code,{children:"QVector<Orm::WithItem>"})," of relationships to the ",(0,s.jsx)(n.code,{children:"load"})," method where the ",(0,s.jsx)(n.code,{children:"name"})," data member of ",(0,s.jsx)(n.code,{children:"Orm::WithItem"})," struct is a relationship name and the ",(0,s.jsx)(n.code,{children:"constraints"})," data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the ",(0,s.jsx)(n.code,{children:"constraints"})," lambda expression is an underlying ",(0,s.jsx)(n.code,{children:"Orm::QueryBuilder"})," for a related model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'author->load({{"books", [](auto &query)\n{\n query.orderBy("published_date", "asc");\n}}});\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You can also use eager constraining in the Model's ",(0,s.jsx)(n.code,{children:"fresh"})," method."]})}),"\n",(0,s.jsx)(n.h2,{id:"inserting-and-updating-related-models",children:"Inserting & Updating Related Models"}),"\n",(0,s.jsxs)(n.h3,{id:"the-save-method",children:["The ",(0,s.jsx)(n.code,{children:"save"})," Method"]}),"\n",(0,s.jsxs)(n.p,{children:["TinyORM provides convenient methods for adding new models to relationships. For example, perhaps you need to add a new comment to a post. Instead of manually setting the ",(0,s.jsx)(n.code,{children:"post_id"})," attribute on the ",(0,s.jsx)(n.code,{children:"Comment"})," model you may insert the comment using the relationship's ",(0,s.jsx)(n.code,{children:"save"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/comment.hpp"\n#include "models/post.hpp"\n\nComment comment({{"message", "A new comment."}});\n\nauto post = Post::find(1);\n\npost->comments()->save(comment);\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Note that we did not access the ",(0,s.jsx)(n.code,{children:"comments"})," relationship with the ",(0,s.jsx)(n.code,{children:"getRelation"})," or ",(0,s.jsx)(n.code,{children:"getRelationValue"})," method. Instead, we called the ",(0,s.jsx)(n.code,{children:"comments"})," method to obtain an instance of the relationship. The ",(0,s.jsx)(n.code,{children:"save"})," method will automatically add the appropriate ",(0,s.jsx)(n.code,{children:"post_id"})," value to the new ",(0,s.jsx)(n.code,{children:"Comment"})," model."]}),"\n",(0,s.jsxs)(n.p,{children:["If you need to save multiple related models, you may use the ",(0,s.jsx)(n.code,{children:"saveMany"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto post = Post::find(1);\n\npost->comments()->saveMany({\n {{"message", "A new comment."}},\n {{"message", "Another new comment."}},\n});\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"save"})," and ",(0,s.jsx)(n.code,{children:"saveMany"})," methods will not add the new models to any in-memory relationships that are already loaded onto the parent model. If you plan on accessing the relationship after using the ",(0,s.jsx)(n.code,{children:"save"})," or ",(0,s.jsx)(n.code,{children:"saveMany"})," methods, you may wish to use the ",(0,s.jsx)(n.code,{children:"refresh"})," method to reload the model and its relationships:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'post->comments()->save(comment);\n\npost->refresh();\n\n// All comments, including the newly saved comment...\npost->getRelation<Comment>("comments");\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The many-to-many relationship also supports the ",(0,s.jsx)(n.code,{children:"save"})," and ",(0,s.jsx)(n.code,{children:"saveMany"})," methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto user = User::find(2);\n\nRole role {{"name", "admin"}};\n\nuser->roles()->save(role, {{"active", true}});\n\nRole role1 {{"name", "edit"}};\nRole role2 {{"name", "view"}};\n\nuser->roles()->saveMany({role1, role2}, {{{"active", true}},\n {{"active", false}}});\n\n// No pivot attributes for role1\nuser->roles()->saveMany({role1, role2}, {{}, {{"active", false}}});\n'})}),"\n",(0,s.jsx)(n.h4,{id:"recursively-saving-models--relationships",children:"Recursively Saving Models & Relationships"}),"\n",(0,s.jsxs)(n.p,{children:["If you would like to ",(0,s.jsx)(n.code,{children:"save"})," your model and all of its associated relationships, you may use the ",(0,s.jsx)(n.code,{children:"push"})," method. In this example, the ",(0,s.jsx)(n.code,{children:"Post"})," model will be saved as well as its comments and the comment's authors:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto post = Post::find(1);\n\npost->getRelationValue<Comment>("comments").at(0)->setAttribute("message", "Message");\n\npost->getRelationValue<Comment>("comments").first()\n ->getRelationValue<User, Orm::One>("author")->setAttribute("name", "Author Name");\n\npost->push();\n'})}),"\n",(0,s.jsxs)(n.h3,{id:"the-create-method",children:["The ",(0,s.jsx)(n.code,{children:"create"})," Method"]}),"\n",(0,s.jsxs)(n.p,{children:["In addition to the ",(0,s.jsx)(n.code,{children:"save"})," and ",(0,s.jsx)(n.code,{children:"saveMany"})," methods, you may also use the ",(0,s.jsx)(n.code,{children:"create"})," method, which accepts a vector of attributes, creates a model, and inserts it into the database. The difference between ",(0,s.jsx)(n.code,{children:"save"})," and ",(0,s.jsx)(n.code,{children:"create"})," is that ",(0,s.jsx)(n.code,{children:"save"})," accepts a full TinyORM model instance while ",(0,s.jsx)(n.code,{children:"create"})," accepts a ",(0,s.jsx)(n.code,{children:"QVector<Orm::AttributeItem>"}),". The newly created model will be returned by the ",(0,s.jsx)(n.code,{children:"create"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/post.hpp"\n\nauto post = Post::find(1);\n\nauto comment = post->comments()->create({\n {"message", "A new comment."},\n});\n'})}),"\n",(0,s.jsxs)(n.p,{children:["You may use the ",(0,s.jsx)(n.code,{children:"createMany"})," method to create multiple related models:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto post = Post::find(1);\n\nauto comments = post->comments()->createMany({\n {{"message", "A new comment."}, {"is_published", true}},\n {{"message", "Another new comment."}, {"is_published", false}},\n});\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The many-to-many relationship also supports the ",(0,s.jsx)(n.code,{children:"create"})," and ",(0,s.jsx)(n.code,{children:"createMany"})," methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto user = User::find(2);\n\nuser->roles()->create({{"name", "admin"}}, {{"active", true}});\n\nuser->roles()->createMany({\n {{"name", "edit"}},\n {{"name", "view"}},\n}, {\n {{"active", true}},\n {{"active", false}},\n});\n\n// No pivot attributes for the first role\nuser->roles()->createMany({\n {{"name", "edit"}},\n {{"name", "view"}},\n}, {\n {},\n {{"active", false}},\n});\n'})}),"\n",(0,s.jsxs)(n.p,{children:["You may also use the ",(0,s.jsx)(n.code,{children:"findOrNew"}),", ",(0,s.jsx)(n.code,{children:"firstOrNew"}),", ",(0,s.jsx)(n.code,{children:"firstOrCreate"}),", and ",(0,s.jsx)(n.code,{children:"updateOrCreate"})," methods to ",(0,s.jsx)(n.a,{href:"/tinyorm/getting-started#retrieving-or-creating-models",children:"create and update models on relationships"}),"."]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Before using the ",(0,s.jsx)(n.code,{children:"create"})," method, be sure to review the ",(0,s.jsx)(n.a,{href:"/tinyorm/getting-started#mass-assignment",children:"mass assignment"})," documentation."]})}),"\n",(0,s.jsx)(n.h3,{id:"updating-belongs-to-relationships",children:"Belongs To Relationships"}),"\n",(0,s.jsxs)(n.p,{children:["If you would like to assign a child model to a new parent model, you may use the ",(0,s.jsx)(n.code,{children:"associate"})," method. In this example, the ",(0,s.jsx)(n.code,{children:"User"})," model defines a ",(0,s.jsx)(n.code,{children:"belongsTo"})," relationship to the ",(0,s.jsx)(n.code,{children:"Account"})," model. The ",(0,s.jsx)(n.code,{children:"associate"})," method will set the foreign key on the child model:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nUser user {{"name", "Mike"}};\n\nauto account = Account::find(10);\n\nuser.account()->associate(*account);\n\nuser.save();\n'})}),"\n",(0,s.jsxs)(n.p,{children:["To remove a parent model from a child model, you may use the ",(0,s.jsx)(n.code,{children:"dissociate"})," method. This method will set the relationship's foreign key to ",(0,s.jsx)(n.code,{children:"null"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"user.account()->dissociate();\n\nuser.save();\n"})}),"\n",(0,s.jsx)(n.h3,{id:"updating-many-to-many-relationships",children:"Many To Many Relationships"}),"\n",(0,s.jsx)(n.h4,{id:"attaching--detaching",children:"Attaching / Detaching"}),"\n",(0,s.jsxs)(n.p,{children:["TinyORM also provides methods to make working with many-to-many relationships more convenient. For example, let's imagine a user can have many roles and a role can have many users. You may use the ",(0,s.jsx)(n.code,{children:"attach"})," method to attach a role to a user by inserting a record in the relationship's intermediate table:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nauto user = User::find(1);\n\nuser->roles()->attach(roleId);\n'})}),"\n",(0,s.jsx)(n.p,{children:"When attaching a relationship to a model, you may also pass a vector of additional data to be inserted into the intermediate table:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'const auto expires = true;\n\nuser->roles()->attach(roleId, {{"expires", expires}});\n'})}),"\n",(0,s.jsxs)(n.p,{children:["Sometimes it may be necessary to remove a role from a user. To remove a many-to-many relationship record, use the ",(0,s.jsx)(n.code,{children:"detach"})," method. The ",(0,s.jsx)(n.code,{children:"detach"})," method will delete the appropriate record out of the intermediate table; however, both models will remain in the database:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"// Detach a single role from the user...\nuser->roles()->detach(roleId);\n\n// Detach all roles from the user...\nuser->roles()->detachAll();\n"})}),"\n",(0,s.jsxs)(n.p,{children:["For convenience, ",(0,s.jsx)(n.code,{children:"attach"})," and ",(0,s.jsx)(n.code,{children:"detach"})," also accept vectors of IDs or Model instances as input:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto user = User::find(1);\n\nuser->roles()->detach({1, 2, 3});\n\nRole role1({{"name", "Role 1"}});\nrole1.save();\nRole role2({{"name", "Role 2"}});\nrole2.save();\n\nuser->roles()->attach({{role1}, {role2}});\n'})}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.code,{children:"attach"})," method also accepts ",(0,s.jsx)(n.code,{children:"std::map"})," as input, so you can pass different attributes for each model you are attaching:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'user->roles()->attach({\n {1, {{"expires", true}, {"is_active", false}}},\n {2, {{"expires", false}, {"is_active", true}}},\n});\n'})}),"\n",(0,s.jsx)(n.h4,{id:"syncing-associations",children:"Syncing Associations"}),"\n",(0,s.jsxs)(n.p,{children:["You may also use the ",(0,s.jsx)(n.code,{children:"sync"})," method to construct many-to-many associations. The ",(0,s.jsx)(n.code,{children:"sync"})," method accepts a vector of IDs to place on the intermediate table. Any IDs that are not in the given vector will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given vector will exist in the intermediate table:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"user->roles()->sync({1, 2, 3});\n"})}),"\n",(0,s.jsx)(n.p,{children:"You may also pass additional intermediate table values with the IDs:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'user->roles()->sync({\n {1, {{"expires", true}}},\n {2, {}},\n {3, {}},\n});\n'})}),"\n",(0,s.jsxs)(n.p,{children:["If you do not want to detach existing IDs that are missing from the given vector, you may use the ",(0,s.jsx)(n.code,{children:"syncWithoutDetaching"})," method:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:"user->roles()->syncWithoutDetaching({1, 2, 3});\n"})}),"\n",(0,s.jsx)(n.h4,{id:"updating-a-record-on-the-intermediate-table",children:"Updating A Record On The Intermediate Table"}),"\n",(0,s.jsxs)(n.p,{children:["If you need to update an existing row in your relationship's intermediate table, you may use the ",(0,s.jsx)(n.code,{children:"updateExistingPivot"})," method. This method accepts the intermediate record foreign key and the vector of attributes to update:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'auto user = User::find(1);\n\nuser->roles()->updateExistingPivot(roleId, {\n {"active", false},\n});\n'})}),"\n",(0,s.jsx)(n.h2,{id:"touching-parent-timestamps",children:"Touching Parent Timestamps"}),"\n",(0,s.jsxs)(n.p,{children:["When a model defines a ",(0,s.jsx)(n.code,{children:"belongsTo"})," relationship to another model, such as a ",(0,s.jsx)(n.code,{children:"Comment"})," which belongs to a ",(0,s.jsx)(n.code,{children:"Post"}),", it is sometimes helpful to update the parent's timestamp when the child model is updated."]}),"\n",(0,s.jsxs)(n.p,{children:["For example, when a ",(0,s.jsx)(n.code,{children:"Comment"}),' model is updated, you may want to automatically "touch" the ',(0,s.jsx)(n.code,{children:"updated_at"})," timestamp of the owning ",(0,s.jsx)(n.code,{children:"Post"})," so that it is set to the current date and time. To accomplish this, you may add a ",(0,s.jsx)(n.code,{children:"u_touches"})," data member to your child model containing the names of the relationships that should have their ",(0,s.jsx)(n.code,{children:"updated_at"})," timestamps updated when the child model is updated:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-cpp",children:'using Orm::Tiny::Model;\n\nclass Comment final : public Model<Comment, Post>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the post that owns the comment. */\n std::unique_ptr<BelongsTo<Comment, Post>>\n post()\n {\n return belongsTo<Post>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"post", [](auto &v) { v(&Comment::post); }},\n };\n\n /*! All of the relationships to be touched. */\n QStringList u_touches {"post"};\n};\n'})}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.p,{children:["Parent model timestamps will only be updated if the child model is updated using TinyORM's ",(0,s.jsx)(n.code,{children:"save"}),", ",(0,s.jsx)(n.code,{children:"push"}),", or ",(0,s.jsx)(n.code,{children:"remove"})," method."]})})]})}function c(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},8453:(e,n,o)=>{o.d(n,{R:()=>a,x:()=>r});var s=o(6540);const t={},i=s.createContext(t);function a(e){const n=s.useContext(i);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),s.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7333c691.d4a3b177.js b/assets/js/7333c691.d4a3b177.js deleted file mode 100644 index 757231215..000000000 --- a/assets/js/7333c691.d4a3b177.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[799],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>c});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,o=function(e,t){if(null==e)return{};var n,a,o={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),m=p(n),u=o,c=m["".concat(s,".").concat(u)]||m[u]||h[u]||i;return n?a.createElement(c,r(r({ref:t},d),{},{components:n})):a.createElement(c,r({ref:t},d))}));function c(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:o,r[1]=l;for(var p=2;p<i;p++)r[p]=n[p];return a.createElement.apply(null,r)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},7273:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>h,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={sidebar_position:1,sidebar_label:"Relationships",description:"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.",keywords:["c++ orm","relationships","relations","tinyorm"]},r="TinyORM: Relationships",l={unversionedId:"tinyorm/relationships",id:"tinyorm/relationships",title:"TinyORM: Relationships",description:"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.",source:"@site/docs/tinyorm/relationships.mdx",sourceDirName:"tinyorm",slug:"/tinyorm/relationships",permalink:"/tinyorm/relationships",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/tinyorm/relationships.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,sidebar_label:"Relationships",description:"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.",keywords:["c++ orm","relationships","relations","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Getting Started",permalink:"/tinyorm/getting-started"},next:{title:"Collections",permalink:"/tinyorm/collections"}},s={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Defining Relationships",id:"defining-relationships",level:2},{value:"Common Rules",id:"common-rules",level:3},{value:"One To One",id:"one-to-one",level:3},{value:"Defining The Inverse Of The Relationship",id:"defining-the-inverse-of-the-relationship",level:4},{value:"One To Many",id:"one-to-many",level:3},{value:"One To Many (Inverse) / Belongs To",id:"one-to-many-inverse",level:3},{value:"Default Models",id:"default-models",level:4},{value:"Many To Many Relationships",id:"many-to-many",level:2},{value:"Table Structure",id:"table-structure",level:4},{value:"Model Structure",id:"model-structure",level:4},{value:"Defining The Inverse Of The Relationship",id:"defining-the-inverse-of-the-relationship-1",level:4},{value:"Retrieving Intermediate Table Columns",id:"retrieving-intermediate-table-columns",level:3},{value:"Customizing The <code>pivot</code> Relation Name",id:"customizing-the-pivot-relation-name",level:4},{value:"Defining Custom Intermediate Table Models",id:"defining-custom-intermediate-table-models",level:3},{value:"Custom Pivot Models And Incrementing IDs",id:"custom-pivot-models-and-incrementing-ids",level:4},{value:"Closer Look At Defining Custom Intermediate Table Models",id:"closer-look-at-defining-custom-intermediate-table-models",level:4},{value:"User Data Members on Custom Intermediate Table Models",id:"user-data-members-on-custom-intermediate-table-models",level:5},{value:"Querying Relations",id:"querying-relations",level:2},{value:"Chaining <code>orWhere</code> Clauses After Relationships",id:"chaining-orwhere-clauses-after-relationships",level:4},{value:"Relationship Methods",id:"relationship-methods",level:3},{value:"Querying Relationship Existence",id:"querying-relationship-existence",level:3},{value:"Related template parameter",id:"related-template-parameter",level:4},{value:"Querying Relationship Absence",id:"querying-relationship-absence",level:3},{value:"Eager Loading",id:"eager-loading",level:2},{value:"Eager Loading Multiple Relationships",id:"eager-loading-multiple-relationships",level:4},{value:"Nested Eager Loading",id:"nested-eager-loading",level:4},{value:"Eager Loading Specific Columns",id:"eager-loading-specific-columns",level:4},{value:"Eager Loading By Default",id:"eager-loading-by-default",level:4},{value:"Constraining Eager Loads",id:"constraining-eager-loads",level:3},{value:"Lazy Eager Loading",id:"lazy-eager-loading",level:3},{value:"Inserting & Updating Related Models",id:"inserting-and-updating-related-models",level:2},{value:"The <code>save</code> Method",id:"the-save-method",level:3},{value:"Recursively Saving Models & Relationships",id:"recursively-saving-models--relationships",level:4},{value:"The <code>create</code> Method",id:"the-create-method",level:3},{value:"Belongs To Relationships",id:"updating-belongs-to-relationships",level:3},{value:"Many To Many Relationships",id:"updating-many-to-many-relationships",level:3},{value:"Attaching / Detaching",id:"attaching--detaching",level:4},{value:"Syncing Associations",id:"syncing-associations",level:4},{value:"Updating A Record On The Intermediate Table",id:"updating-a-record-on-the-intermediate-table",level:4},{value:"Touching Parent Timestamps",id:"touching-parent-timestamps",level:2}],d={toc:p},m="wrapper";function h(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"tinyorm-relationships"},"TinyORM: Relationships"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#defining-relationships"},"Defining Relationships"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#common-rules"},"Common Rules")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#one-to-one"},"One To One")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#one-to-many"},"One To Many")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#one-to-many-inverse"},"One To Many (Inverse) / Belongs To")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#many-to-many"},"Many To Many Relationships"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#retrieving-intermediate-table-columns"},"Retrieving Intermediate Table Columns")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#defining-custom-intermediate-table-models"},"Defining Custom Intermediate Table Models")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#querying-relations"},"Querying Relations"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#relationship-methods"},"Relationship Methods")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#querying-relationship-existence"},"Querying Relationship Existence")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#querying-relationship-absence"},"Querying Relationship Absence")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#eager-loading"},"Eager Loading"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#constraining-eager-loads"},"Constraining Eager Loads")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#lazy-eager-loading"},"Lazy Eager Loading")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#inserting-and-updating-related-models"},"Inserting & Updating Related Models"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#the-save-method"},"The ",(0,o.kt)("inlineCode",{parentName:"a"},"save")," Method")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#the-create-method"},"The ",(0,o.kt)("inlineCode",{parentName:"a"},"create")," Method")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#updating-belongs-to-relationships"},"Belongs To Relationships")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#updating-many-to-many-relationships"},"Many To Many Relationships")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#touching-parent-timestamps"},"Touching Parent Timestamps"))),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,"Database tables are often related to one another. For example, a blog post may have many comments or an order could be related to the user who placed it. TinyORM makes managing and working with these relationships easy, and supports basic relationships:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#one-to-one"},"One To One")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#one-to-many"},"One To Many")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#many-to-many"},"Many To Many"))),(0,o.kt)("h2",{id:"defining-relationships"},"Defining Relationships"),(0,o.kt)("p",null,"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful ",(0,o.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builders"),", defining relationships as methods provides powerful method chaining and querying capabilities. For example, we may chain additional query constraints on this ",(0,o.kt)("inlineCode",{parentName:"p"},"posts")," relationship:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'user->posts()->whereEq("active", 1).get();\n')),(0,o.kt)("p",null,"But, before diving too deep into using relationships, let's learn how to define each type of relationship supported by TinyORM."),(0,o.kt)("h3",{id:"common-rules"},"Common Rules"),(0,o.kt)("p",null,'Before you start defining relationship methods, you have to declare a model class, let\'s examine following model class with a "one" type relation:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/phone.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User, Phone>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the phone associated with the user. */\n std::unique_ptr<HasOne<User, Phone>>\n phone()\n {\n return hasOne<Phone>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"phone", &User::phone); }},\n };\n};\n\n#endif // USER_HPP\n')),(0,o.kt)("p",null,"First, you have to extend the ",(0,o.kt)("inlineCode",{parentName:"p"},"Model<Derived, AllRelations...>"),", it is a common class for all models, the first template parameter is the type-id of the defined model itself, this pattern is called a ",(0,o.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern"},"Curiously recurring template pattern")," pattern."),(0,o.kt)("p",null,"However, the second parameter is more interesting, here you have to provide a type-id of all related models. The TinyORM needs these types to store relationships in the hash."),(0,o.kt)("p",null,"Next, you have to define the ",(0,o.kt)("inlineCode",{parentName:"p"},"u_relations")," hash, which maps relation names to relationship methods. \ud83d\udd25\ud83d\ude80\ud83d\ude4c"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"You may omit the ",(0,o.kt)("inlineCode",{parentName:"p"},"friend Model")," declaration and define all the private data and function members as public.")),(0,o.kt)("h3",{id:"one-to-one"},"One To One"),(0,o.kt)("p",null,"A one-to-one relationship is a very basic type of database relationship. For example, a ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model might be associated with one ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," model. To define this relationship, we will place a ",(0,o.kt)("inlineCode",{parentName:"p"},"phone")," method on the ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model. The ",(0,o.kt)("inlineCode",{parentName:"p"},"phone")," method should call the ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne")," method and return its result. The ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne<Related>")," method is available to your model via the model's ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Model<Derived, AllRelations...>")," base class:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/phone.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User, Phone>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the phone associated with the user. */\n std::unique_ptr<HasOne<User, Phone>>\n phone()\n {\n return hasOne<Phone>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"phone", [](auto &v) { v(&User::phone); }},\n };\n};\n\n#endif // USER_HPP\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template argument provided to the ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne<Related>")," method is the type-id of the related model class. Once the relationship is defined, we may retrieve the related record using Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue<Related, Tag>")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto phone = User::find(1)->getRelationValue<Phone, Orm::One>("phone");\n')),(0,o.kt)("p",null,"TinyORM determines the foreign key of the relationship based on the parent model name. In this case, the ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," model is automatically assumed to have a ",(0,o.kt)("inlineCode",{parentName:"p"},"user_id")," foreign key. If you wish to override this convention, you may pass a first argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'return hasOne<Phone>("foreign_key");\n')),(0,o.kt)("p",null,"Additionally, TinyORM assumes that the foreign key should have a value matching the primary key column of the parent. In other words, TinyORM will look for the value of the user's ",(0,o.kt)("inlineCode",{parentName:"p"},"id")," column in the ",(0,o.kt)("inlineCode",{parentName:"p"},"user_id")," column of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," record. If you would like the relationship to use a primary key value other than ",(0,o.kt)("inlineCode",{parentName:"p"},"id")," or your model's ",(0,o.kt)("inlineCode",{parentName:"p"},"u_primaryKey")," data member, you may pass a second argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'return hasOne<Phone>("foreign_key", "local_key");\n')),(0,o.kt)("h4",{id:"defining-the-inverse-of-the-relationship"},"Defining The Inverse Of The Relationship"),(0,o.kt)("p",null,"So, we can access the ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," model from our ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model. Next, let's define a relationship on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," model that will let us access the user that owns the phone. We can define the inverse of a ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne")," relationship using the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo<Related>")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef PHONE_HPP\n#define PHONE_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/user.hpp"\n\nusing Orm::Tiny::Model;\n\nclass Phone final : public Model<Phone, User>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the user that owns the phone. */\n std::unique_ptr<BelongsTo<Phone, User>>\n user()\n {\n return belongsTo<User>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"user", [](auto &v) { v(&Phone::user); }},\n };\n};\n\n#endif // PHONE_HPP\n')),(0,o.kt)("p",null,"When invoking the ",(0,o.kt)("inlineCode",{parentName:"p"},"user")," method, TinyORM will attempt to find a ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model that has an ",(0,o.kt)("inlineCode",{parentName:"p"},"id")," which matches the ",(0,o.kt)("inlineCode",{parentName:"p"},"user_id")," column on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," model."),(0,o.kt)("p",null,"TinyORM determines the foreign key name by examining the type-name of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template parameter and suffixing the type-name with ",(0,o.kt)("inlineCode",{parentName:"p"},"_id"),". So, in this case, TinyORM assumes that the ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," model has a ",(0,o.kt)("inlineCode",{parentName:"p"},"user_id")," column."),(0,o.kt)("p",null," However, if the foreign key on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Phone")," model is not ",(0,o.kt)("inlineCode",{parentName:"p"},"user_id"),", you may pass a custom key name as the first argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'/*! Get the user that owns the phone. */\nstd::unique_ptr<BelongsTo<Phone, User>>\nuser()\n{\n return belongsTo<User>("foreign_key");\n}\n')),(0,o.kt)("p",null,"If the parent model does not use ",(0,o.kt)("inlineCode",{parentName:"p"},"id")," as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo")," method specifying the parent table's custom key:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'/*! Get the user that owns the phone. */\nstd::unique_ptr<BelongsTo<Phone, User>>\nuser()\n{\n return belongsTo<User>("foreign_key", "owner_key");\n}\n')),(0,o.kt)("p",null,"The third ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo"),' parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snake',(0,o.kt)("em",{parentName:"p"},'case" this relation name and suffix it with a `'),(0,o.kt)("inlineCode",{parentName:"p"},"followed by the name of the parent model's primary key column to generate foreign key, the"),(0,o.kt)("strong",{parentName:"p"},"func"),(0,o.kt)("inlineCode",{parentName:"p"},"predefined identifier is ideal for this. The relation name is also used in BelongsTo's"),"associate",(0,o.kt)("inlineCode",{parentName:"p"},"and"),"disassociate` methods:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"/*! Get the user that owns the phone. */\nstd::unique_ptr<BelongsTo<Phone, User>>\nsomeUser()\n{\n return belongsTo<User>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_user_id\n}\n")),(0,o.kt)("p",null,"The relation name will be guessed from the type-id of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be ",(0,o.kt)("inlineCode",{parentName:"p"},"user"),"."),(0,o.kt)("h3",{id:"one-to-many"},"One To Many"),(0,o.kt)("p",null,"A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models. For example, a blog post may have an infinite number of comments. Like all other TinyORM relationships, one-to-many relationships are defined by defining a ",(0,o.kt)("inlineCode",{parentName:"p"},"hasMany<Related>")," method on your TinyORM model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef POST_HPP\n#define POST_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/comment.hpp"\n\nusing Orm::Tiny::Model;\n\nclass Post final : public Model<Post, Comment>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the comments for the blog post. */\n std::unique_ptr<HasMany<Post, Comment>>\n comments()\n {\n return hasMany<Comment>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"comments", [](auto &v) { v(&Post::comments); }},\n };\n};\n\n#endif // POST_HPP\n')),(0,o.kt)("p",null,"Remember, TinyORM will automatically determine the proper foreign key column for the ",(0,o.kt)("inlineCode",{parentName:"p"},"Comment"),' model. By convention, TinyORM will take the "snake_case" name of the parent model and suffix it with ',(0,o.kt)("inlineCode",{parentName:"p"},"_id"),". So, in this example, TinyORM will assume the foreign key column on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Comment")," model is ",(0,o.kt)("inlineCode",{parentName:"p"},"post_id"),"."),(0,o.kt)("p",null,"Once the relationship method has been defined, we can access the ",(0,o.kt)("inlineCode",{parentName:"p"},"QVector<Related *>")," of related comments by Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue<Related, Container = QVector>")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/post.hpp"\n\nauto comments = Post::find(1)->getRelationValue<Comment>("comments");\n\nfor (auto *comment : comments) {\n //\n}\n')),(0,o.kt)("p",null,"Since all relationships also serve as ",(0,o.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builders"),", you may add further constraints to the relationship query by calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"comments")," method and continuing to chain conditions onto the query, all the ",(0,o.kt)("inlineCode",{parentName:"p"},"TinyBuilder")," methods which are related to building queries are proxied:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto comment = Post::find(1)->comments()\n ->whereEq("title", "foo")\n .first();\n')),(0,o.kt)("p",null,"Like the ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne")," method, you may also override the foreign and local keys by passing additional arguments to the ",(0,o.kt)("inlineCode",{parentName:"p"},"hasMany")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'return hasMany<Comment>("foreign_key");\n\nreturn hasMany<Comment>("foreign_key", "local_key");\n')),(0,o.kt)("h3",{id:"one-to-many-inverse"},"One To Many (Inverse) / Belongs To"),(0,o.kt)("p",null,"Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a ",(0,o.kt)("inlineCode",{parentName:"p"},"hasMany")," relationship, define a relationship method on the child model which calls the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef COMMENT_HPP\n#define COMMENT_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/post.hpp"\n\nusing Orm::Tiny::Model;\n\nclass Comment final : public Model<Comment, Post>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the post that owns the comment. */\n std::unique_ptr<BelongsTo<Comment, Post>>\n post()\n {\n return belongsTo<Post>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"post", [](auto &v) { v(&Comment::post); }},\n };\n};\n\n#endif // COMMENT_HPP\n')),(0,o.kt)("p",null,"Once the relationship has been defined, we can retrieve a comment's parent post by Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue<Related, Tag>")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/comment.hpp"\n\nauto comment = Comment::find(1);\n\nreturn comment->getRelationValue<Post, Orm::One>("post")->getAttribute<QString>("title");\n')),(0,o.kt)("p",null,"In the example above, TinyORM will attempt to find a ",(0,o.kt)("inlineCode",{parentName:"p"},"Post")," model that has an ",(0,o.kt)("inlineCode",{parentName:"p"},"id")," which matches the ",(0,o.kt)("inlineCode",{parentName:"p"},"post_id")," column on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Comment")," model."),(0,o.kt)("p",null,"TinyORM determines the foreign key name by examining the type-name of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template parameter and suffixing the type-name with a ",(0,o.kt)("inlineCode",{parentName:"p"},"_")," followed by the name of the parent model's primary key column. So, in this case, TinyORM assumes that the ",(0,o.kt)("inlineCode",{parentName:"p"},"Post")," model's foreign key on the ",(0,o.kt)("inlineCode",{parentName:"p"},"comments")," table is ",(0,o.kt)("inlineCode",{parentName:"p"},"post_id"),"."),(0,o.kt)("p",null,"However, if the foreign key for your relationship does not follow these conventions, you may pass a custom foreign key name as the first argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'/*! Get the post that owns the comment. */\nstd::unique_ptr<BelongsTo<Comment, Post>>\npost()\n{\n return belongsTo<Post>("foreign_key");\n}\n')),(0,o.kt)("p",null,"If your parent model does not use ",(0,o.kt)("inlineCode",{parentName:"p"},"id")," as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo")," method specifying your parent table's custom key:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'/*! Get the post that owns the comment. */\nstd::unique_ptr<BelongsTo<Comment, Post>>\npost()\n{\n return belongsTo<Post>("foreign_key", "owner_key");\n}\n')),(0,o.kt)("p",null,"The third ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo"),' parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snake',(0,o.kt)("em",{parentName:"p"},'case" this relation name and suffix it with a `'),(0,o.kt)("inlineCode",{parentName:"p"},"followed by the name of the parent model's primary key column to generate foreign key, the"),(0,o.kt)("strong",{parentName:"p"},"func"),(0,o.kt)("inlineCode",{parentName:"p"},"predefined identifier is ideal for this. The relation name is also used in BelongsTo's"),"associate",(0,o.kt)("inlineCode",{parentName:"p"},"and"),"disassociate` methods:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"/*! Get the post that owns the comment. */\nstd::unique_ptr<BelongsTo<Comment, Post>>\nsomePost()\n{\n return belongsTo<Post>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_post_id\n}\n")),(0,o.kt)("p",null,"The relation name will be guessed from the type-id of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be ",(0,o.kt)("inlineCode",{parentName:"p"},"user"),"."),(0,o.kt)("h4",{id:"default-models"},"Default Models"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo"),", and ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne")," relationships allow you to define a default model that will be returned if the given relationship is ",(0,o.kt)("inlineCode",{parentName:"p"},"null"),". This pattern is often referred to as the ",(0,o.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Null_Object_pattern"},"Null Object pattern")," and can help remove conditional checks in your code. In the following example, the ",(0,o.kt)("inlineCode",{parentName:"p"},"user")," relation will return an empty ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model if no user is attached to the ",(0,o.kt)("inlineCode",{parentName:"p"},"Post")," model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"/*! Get the author of the post. */\nstd::unique_ptr<BelongsTo<Post, User>>\nuser()\n{\n // Ownership of a unique_ptr()\n auto relation = belongsTo<User>();\n\n relation->withDefault();\n\n return relation;\n}\n")),(0,o.kt)("p",null,"To populate the default model with attributes, you may pass the vector of attributes to the ",(0,o.kt)("inlineCode",{parentName:"p"},"withDefault")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'/*! Get the author of the post. */\nstd::unique_ptr<BelongsTo<Post, User>>\nuser()\n{\n // Ownership of a unique_ptr()\n auto relation = belongsTo<User>();\n\n relation->withDefault({{"name", "Guest Author"},\n {"is_active", false}});\n\n return relation;\n}\n')),(0,o.kt)("h2",{id:"many-to-many"},"Many To Many Relationships"),(0,o.kt)("p",null,"Many-to-many relations are slightly more complicated than ",(0,o.kt)("inlineCode",{parentName:"p"},"hasOne")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"hasMany"),' relationships. An example of a many-to-many relationship is a user that has many roles and those roles are also shared by other users in the application. For example, a user may be assigned the role of "Author" and "Editor"; however, those roles may also be assigned to other users as well. So, a user has many roles and a role has many users.'),(0,o.kt)("h4",{id:"table-structure"},"Table Structure"),(0,o.kt)("p",null,"To define this relationship, three database tables are needed: ",(0,o.kt)("inlineCode",{parentName:"p"},"users"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"roles"),", and ",(0,o.kt)("inlineCode",{parentName:"p"},"role_user"),". The ",(0,o.kt)("inlineCode",{parentName:"p"},"role_user")," table is derived from the alphabetical order of the related model names and contains ",(0,o.kt)("inlineCode",{parentName:"p"},"user_id")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"role_id")," columns. This table is used as an intermediate table linking the users and roles."),(0,o.kt)("p",null,"Remember, since a role can belong to many users, we cannot simply place a ",(0,o.kt)("inlineCode",{parentName:"p"},"user_id")," column on the ",(0,o.kt)("inlineCode",{parentName:"p"},"roles")," table. This would mean that a role could only belong to a single user. In order to provide support for roles being assigned to multiple users, the ",(0,o.kt)("inlineCode",{parentName:"p"},"role_user")," table is needed. We can summarize the relationship's table structure like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"users\n id - integer\n name - string\n\nroles\n id - integer\n name - string\n\nrole_user\n user_id - integer\n role_id - integer\n")),(0,o.kt)("h4",{id:"model-structure"},"Model Structure"),(0,o.kt)("p",null,"Many-to-many relationships are defined by writing a method that returns the result of the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany")," method. The ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany")," method is provided by the ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Model<Derived, AllRelations...>")," base class that is used by all of your application's TinyORM models. For example, let's define a ",(0,o.kt)("inlineCode",{parentName:"p"},"roles")," method on our ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model. The first argument passed to this method is the name of the related model class:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/relations/pivot.hpp>\n\n#include "models/role.hpp"\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::Relations::Pivot;\n\nclass User final : public Model<User, Role, Pivot>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The roles that belong to the user. */\n std::unique_ptr<BelongsToMany<User, Role>>\n roles()\n {\n return belongsToMany<Role>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"roles", [](auto &v) { v(&User::roles); }},\n };\n};\n\n#endif // USER_HPP\n')),(0,o.kt)("p",null,"Once the relationship is defined, you may access the user's roles as the ",(0,o.kt)("inlineCode",{parentName:"p"},"QVector<Related *>")," by Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue<Related, Container = QVector>")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include "models/user.hpp"\n\nauto user = User::find(1);\n\nfor (auto *role : user->getRelationValue<Role>("roles"))\n qDebug() << role->getAttribute<quint64>("id");\n')),(0,o.kt)("p",null,"Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"roles")," method and continuing to chain conditions onto the query:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto roles = User::find(1)->roles()->orderBy("name").get();\n')),(0,o.kt)("p",null,"To determine the table name of the relationship's intermediate table, TinyORM will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a first argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'return belongsToMany<Role>("role_user");\n')),(0,o.kt)("p",null,"In addition to customizing the name of the intermediate table, you may also customize the column names of the keys on the table by passing additional arguments to the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany")," method. The second argument is the foreign key name of the model on which you are defining the relationship, while the third argument is the foreign key name of the model that you are joining to:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'return belongsToMany<Role>("role_user", "user_id", "role_id");\n')),(0,o.kt)("p",null,"The fourth and fifth arguments are primary key names on models in the many-to-many relation and the sixth argument is the relation name."),(0,o.kt)("p",null,"The relation name is used during ",(0,o.kt)("a",{parentName:"p",href:"#touching-parent-timestamps"},"Touching Parent Timestamps")," and will be guessed from the type-id of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template parameter, TinyORM takes this name, changes the first character to lower case, and appends ",(0,o.kt)("inlineCode",{parentName:"p"},"s")," character. So in the example above, the relation name will be ",(0,o.kt)("inlineCode",{parentName:"p"},"roles"),"."),(0,o.kt)("h4",{id:"defining-the-inverse-of-the-relationship-1"},"Defining The Inverse Of The Relationship"),(0,o.kt)("p",null,'To define the "inverse" of a many-to-many relationship, you should define a method on the related model which also returns the result of the ',(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany")," method. To complete our user / role example, let's define the ",(0,o.kt)("inlineCode",{parentName:"p"},"users")," method on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Role")," model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef ROLE_HPP\n#define ROLE_HPP\n\n#include <orm/tiny/relations/pivot.hpp>\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::Relations::Pivot;\n\nclass User; // Forward declaration to avoid cyclic dependency\n\nclass Role final : public Model<Role, User, Pivot>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The users that belong to the role. */\n std::unique_ptr<BelongsToMany<Role, User>>\n users()\n {\n return belongsToMany<User>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"users", [](auto &v) { v(&Role::users); }},\n };\n};\n\n#endif // ROLE_HPP\n')),(0,o.kt)("p",null,"As you can see, the relationship is defined exactly the same as its ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model counterpart with the exception of referencing the ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model. Since we're reusing the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany"),' method, all of the usual table and key customization options are available when defining the "inverse" of many-to-many relationships.'),(0,o.kt)("h3",{id:"retrieving-intermediate-table-columns"},"Retrieving Intermediate Table Columns"),(0,o.kt)("p",null,"As you have already learned, working with many-to-many relations requires the presence of an intermediate table. TinyORM provides some very helpful ways of interacting with this table. For example, let's assume our ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model has many ",(0,o.kt)("inlineCode",{parentName:"p"},"Role")," models that it is related to. After accessing this relationship, we may access the intermediate table using the ",(0,o.kt)("inlineCode",{parentName:"p"},"pivot")," attribute on the models:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include "models/user.hpp"\n\nusing Orm::Tiny::Relations::Pivot;\n\nauto user = User::find(1);\n\nfor (auto *role : user->getRelationValue<Role>("roles"))\n qDebug() << role->getRelation<Pivot, Orm::One>("pivot")\n ->getAttribute("created_at");\n')),(0,o.kt)("p",null,"Notice that each ",(0,o.kt)("inlineCode",{parentName:"p"},"Role")," model we retrieve has automatically assigned a ",(0,o.kt)("inlineCode",{parentName:"p"},"pivot")," relationship. This relation contains a model representing the intermediate table and it is an instance of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Relations::Pivot")," model class."),(0,o.kt)("p",null,"By default, only the model keys will be present on the ",(0,o.kt)("inlineCode",{parentName:"p"},"pivot")," model. If your intermediate table contains extra attributes, you must specify them when defining the relationship:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'// Ownership of a unique_ptr()\nauto relation = belongsToMany<Role>();\n\nrelation->withPivot({"active", "created_by"});\n\nreturn relation;\n')),(0,o.kt)("p",null,"If you would like your intermediate table to have ",(0,o.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamps that are automatically maintained by TinyORM, call the ",(0,o.kt)("inlineCode",{parentName:"p"},"withTimestamps")," method when defining the relationship:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"// Ownership of a unique_ptr()\nauto relation = belongsToMany<Role>();\n\nrelation->withTimestamps();\n\nreturn relation;\n")),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Intermediate tables that utilize TinyORM's automatically maintained timestamps are required to have both ",(0,o.kt)("inlineCode",{parentName:"p"},"created_at")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamp columns.")),(0,o.kt)("h4",{id:"customizing-the-pivot-relation-name"},"Customizing The ",(0,o.kt)("inlineCode",{parentName:"h4"},"pivot")," Relation Name"),(0,o.kt)("p",null,"As noted previously, attributes from the intermediate table may be accessed on models via the ",(0,o.kt)("inlineCode",{parentName:"p"},"pivot")," relation name. However, you are free to customize the name of this relation to better reflect its purpose within your application."),(0,o.kt)("p",null,"For example, if your application contains users that may subscribe to podcasts, you likely have a many-to-many relationship between users and podcasts. If this is the case, you may wish to rename your intermediate table relation name to ",(0,o.kt)("inlineCode",{parentName:"p"},"subscription")," instead of ",(0,o.kt)("inlineCode",{parentName:"p"},"pivot"),". This can be done using the ",(0,o.kt)("inlineCode",{parentName:"p"},"as")," method when defining the relationship:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'// Ownership of a unique_ptr()\nauto relation = belongsToMany<Podcast>();\n\nrelation->as("subscription")\n .withTimestamps();\n\nreturn relation;\n')),(0,o.kt)("p",null,"Once the custom intermediate table relation name has been specified, you may access the intermediate table data using the customized name:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include "models/user.hpp"\n\nusing Orm::Tiny::Relations::Pivot;\n\nauto users = User::with("podcasts")->get();\n\nfor (auto &user : users)\n for (auto *podcast : user.getRelation<Podcast>("podcasts"))\n qDebug() << podcast->getRelation<Pivot, Orm::One>("subscription")\n ->getAttribute("created_at");\n')),(0,o.kt)("h3",{id:"defining-custom-intermediate-table-models"},"Defining Custom Intermediate Table Models"),(0,o.kt)("p",null,"If you would like to define a custom model to represent the intermediate table of your many-to-many relationship, you may pass the custom pivot type as a second template argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany<Related, PivotType = Pivot>")," method when defining the relationship. Custom pivot models give you the opportunity to define additional methods on the pivot model."),(0,o.kt)("p",null,"Custom many-to-many pivot models should extend the ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Relations::BasePivot<PivotModel>")," class. For example, we may define a ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model which uses a custom ",(0,o.kt)("inlineCode",{parentName:"p"},"RoleUser")," pivot model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef USER_HPP\n#define USER_HPP\n\n#include <orm/tiny/relations/pivot.hpp>\n\n#include "models/role.hpp"\n\nusing Orm::Tiny::Model;\nusing Orm::Tiny::Relations::Pivot;\n\nclass User final : public Model<User, Role, Pivot>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The roles that belong to the user. */\n std::unique_ptr<BelongsToMany<User, Role, RoleUser>>\n roles()\n {\n return belongsToMany<Role, RoleUser>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"roles", [](auto &v) { v(&User::roles); }},\n };\n};\n\n#endif // USER_HPP\n')),(0,o.kt)("p",null,"When defining the ",(0,o.kt)("inlineCode",{parentName:"p"},"RoleUser")," model, you should extend the ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::Tiny::Relations::BasePivot<PivotModel>")," class:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"#pragma once\n#ifndef ROLEUSER_HPP\n#define ROLEUSER_HPP\n\n#include <orm/tiny/relations/basepivot.hpp>\n\nusing Orm::Tiny::Relations::BasePivot;\n\nclass RoleUser final : public BasePivot<RoleUser>\n{\n friend Model;\n friend BasePivot;\n\n using BasePivot::BasePivot;\n};\n\n#endif // ROLEUSER_HPP\n")),(0,o.kt)("p",null,"You have to pass a custom pivot type to the ",(0,o.kt)("inlineCode",{parentName:"p"},"AllRelations")," template parameter pack on ",(0,o.kt)("inlineCode",{parentName:"p"},"Model<Derived, AllRelations...>")," so that the ",(0,o.kt)("inlineCode",{parentName:"p"},"Model")," knows how to generate a ",(0,o.kt)("inlineCode",{parentName:"p"},"std::variant"),", which holds all the relations and also you have to add a new mapping from the relation name to the custom pivot model type-id, this is described in more detail in the ",(0,o.kt)("a",{parentName:"p",href:"#common-rules"},"Common Rules"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#pragma once\n#ifndef ROLE_HPP\n#define ROLE_HPP\n\n#include <orm/tiny/model.hpp>\n\n#include "models/roleuser.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User; // Forward declaration to avoid cyclic dependency\n\nclass Role final : public Model<Role, User, RoleUser>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! The users that belong to the role. */\n std::unique_ptr<BelongsToMany<Role, User>>\n users()\n {\n return belongsToMany<User>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"users", [](auto &v) { v(&Role::users); }},\n };\n};\n\n#endif // ROLE_HPP\n')),(0,o.kt)("p",null,"Once the custom pivot model ",(0,o.kt)("inlineCode",{parentName:"p"},"RoleUser")," has been defined, ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelation")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue")," method returns proper pivot type:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include "models/user.hpp"\n\nauto users = User::with("roles")->get();\n\nfor (auto &user : users)\n for (auto *role : user.getRelation<Role>("roles"))\n qDebug() << role->getRelation<RoleUser, Orm::One>("pivot")\n ->getAttribute("created_at");\n')),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Custom Pivot models may not use the ",(0,o.kt)("inlineCode",{parentName:"p"},"SoftDeletes")," base class. If you need to soft delete pivot records consider converting your pivot model to an actual TinyORM model.")),(0,o.kt)("h4",{id:"custom-pivot-models-and-incrementing-ids"},"Custom Pivot Models And Incrementing IDs"),(0,o.kt)("p",null,"If you have defined a many-to-many relationship that uses a custom pivot model, and that pivot model has an auto-incrementing primary key, you should ensure your custom pivot model class defines an ",(0,o.kt)("inlineCode",{parentName:"p"},"u_incrementing")," data member that is set to ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"/*! Indicates if the IDs are auto-incrementing. */\nbool u_incrementing = true;\n")),(0,o.kt)("h4",{id:"closer-look-at-defining-custom-intermediate-table-models"},"Closer Look At Defining Custom Intermediate Table Models"),(0,o.kt)("p",null,"I can tell that defining a custom intermediate table models is the most confusing part of the TinyORM framework, let's look closer at it."),(0,o.kt)("p",null,"If you are defining a custom ",(0,o.kt)("inlineCode",{parentName:"p"},"RoleUser")," intermediate table for the ",(0,o.kt)("inlineCode",{parentName:"p"},"Role")," model like in the example above then you have to pass the ",(0,o.kt)("inlineCode",{parentName:"p"},"RoleUser")," pivot type as the second template argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"User::roles()")," ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsToMany")," relationship method and you have to pass the ",(0,o.kt)("inlineCode",{parentName:"p"},"RoleUser")," pivot type to the ",(0,o.kt)("inlineCode",{parentName:"p"},"AllRelations")," template parameter pack ",(0,o.kt)("strong",{parentName:"p"},"on the ",(0,o.kt)("inlineCode",{parentName:"strong"},"Role")," model!")),(0,o.kt)("p",null,"Do you see the confusing part? In short, if defining the ",(0,o.kt)("inlineCode",{parentName:"p"},"User::roles()")," relation with the custom ",(0,o.kt)("inlineCode",{parentName:"p"},"UserRole")," pivot model then add the ",(0,o.kt)("inlineCode",{parentName:"p"},"UserRole")," type to the ",(0,o.kt)("inlineCode",{parentName:"p"},"AllRelations")," template parameter pack on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Role")," model."),(0,o.kt)("p",null,"The same is true for the basic ",(0,o.kt)("inlineCode",{parentName:"p"},"Pivot")," model, if you are using a basic pivot model and not a custom pivot model you still need to add the ",(0,o.kt)("inlineCode",{parentName:"p"},"Pivot")," type to the ",(0,o.kt)("inlineCode",{parentName:"p"},"AllRelations")," template parameter pack on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Model")," class!"),(0,o.kt)("p",null,"The reason for all of this is that the ",(0,o.kt)("inlineCode",{parentName:"p"},"Model")," knows how to generate and work with the ",(0,o.kt)("inlineCode",{parentName:"p"},"std::variant")," that holds the pivot model in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Model::m_relations")," data member map, then you can get the pivot model using the ",(0,o.kt)("inlineCode",{parentName:"p"},"Model::getRelationValue")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"Model::getRelation")," methods."),(0,o.kt)("h5",{id:"user-data-members-on-custom-intermediate-table-models"},"User Data Members on Custom Intermediate Table Models"),(0,o.kt)("p",null,"This is another nonstandard part of the custom pivot models. The ",(0,o.kt)("inlineCode",{parentName:"p"},"u_connection")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"u_timestamps")," user data members and the ",(0,o.kt)("inlineCode",{parentName:"p"},"CREATED_AT()")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"UPDATED_AT()")," static getter methods are ignored when obtaining pivot records from the database during the lazy or eager loading."),(0,o.kt)("p",null,"Let's describe how these data members are resolved:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"u_connection")," - inferred from the parent model"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"u_timestamps")," - true if obtained pivot attributes contain both the ",(0,o.kt)("inlineCode",{parentName:"li"},"CREATED_AT")," and ",(0,o.kt)("inlineCode",{parentName:"li"},"UPDATED_AT")," attributes"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"CREATED_AT"),", ",(0,o.kt)("inlineCode",{parentName:"li"},"UPDATED_AT")," - inferred from the parent model, can be overridden using the ",(0,o.kt)("inlineCode",{parentName:"li"},"withTimestamps()")," method")),(0,o.kt)("p",null,"All these data members are taken into account normally when you call the ",(0,o.kt)("inlineCode",{parentName:"p"},"create"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"save"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"update"),", ... on the Custom Pivot models!"),(0,o.kt)("h2",{id:"querying-relations"},"Querying Relations"),(0,o.kt)("p",null,"Since all TinyORM relationships are defined via methods, you may call those methods to obtain an instance of the relationship without actually executing a query to load the related models. In addition, all types of TinyORM relationships also serve as ",(0,o.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builders"),", allowing you to continue to chain constraints onto the relationship query before finally executing the SQL query against your database."),(0,o.kt)("p",null,"For example, imagine a blog application in which a ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model has many associated ",(0,o.kt)("inlineCode",{parentName:"p"},"Post")," models:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/post.hpp"\n\nusing Orm::Tiny::Model;\n\nclass User final : public Model<User, Post>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get all of the posts for the user. */\n std::unique_ptr<HasMany<User, Post>>\n posts()\n {\n return hasMany<Post>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"posts", [](auto &v) { v(&User::posts); }},\n };\n};\n')),(0,o.kt)("p",null,"You may query the ",(0,o.kt)("inlineCode",{parentName:"p"},"posts")," relationship and add additional constraints to the relationship like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/user.hpp"\n\nauto user = User::find(1);\n\nuser->posts()->whereEq("active", 1).get();\n')),(0,o.kt)("p",null,"You are able to use any of the TinyORM ",(0,o.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builder's")," methods on the relationship, so be sure to explore the query builder documentation to learn about all of the methods that are available to you."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"All the ",(0,o.kt)("inlineCode",{parentName:"p"},"TinyBuilder")," methods which are related to building queries are proxied on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Relation")," base class.")),(0,o.kt)("h4",{id:"chaining-orwhere-clauses-after-relationships"},"Chaining ",(0,o.kt)("inlineCode",{parentName:"h4"},"orWhere")," Clauses After Relationships"),(0,o.kt)("p",null,"As demonstrated in the example above, you are free to add additional constraints to relationships when querying them. However, be careful when chaining ",(0,o.kt)("inlineCode",{parentName:"p"},"orWhere")," clauses onto a relationship, as the ",(0,o.kt)("inlineCode",{parentName:"p"},"orWhere")," clauses will be logically grouped at the same level as the relationship constraint:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'user->posts()\n ->whereEq("active", 1)\n .orWhere("votes", ">=", 100)\n .get();\n')),(0,o.kt)("p",null,"The example above will generate the following SQL. As you can see, the ",(0,o.kt)("inlineCode",{parentName:"p"},"or")," clause instructs the query to return ",(0,o.kt)("em",{parentName:"p"},"any")," user with greater than 100 votes. The query is no longer constrained to a specific user:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-sql"},"select *\nfrom posts\nwhere user_id = ? and active = 1 or votes >= 100\n")),(0,o.kt)("p",null,"In most situations, you should use ",(0,o.kt)("a",{parentName:"p",href:"/database/query-builder#logical-grouping"},"logical groups")," to group the conditional checks between parentheses:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'user->posts()\n ->where([](auto &query)\n {\n query.whereEq("active", 1)\n .orWhere("votes", ">=", 100);\n })\n .get();\n')),(0,o.kt)("p",null,"The example above will produce the following SQL. Note that the logical grouping has properly grouped the constraints and the query remains constrained to a specific user:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-sql"},"select *\nfrom posts\nwhere user_id = ? and (active = 1 or votes >= 100)\n")),(0,o.kt)("h3",{id:"relationship-methods"},"Relationship Methods"),(0,o.kt)("p",null,"If you do not need to add additional constraints to the TinyORM relationship query, you may access the relationship directly. For example, continuing to use our ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"Post")," example models, we may access all of a user's posts like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/user.hpp"\n\nauto user = User::find(1);\n\nfor (auto *post : user->getRelationValue<Post>("posts")) {\n //\n}\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue<Related>"),' method performs "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use ',(0,o.kt)("a",{parentName:"p",href:"#eager-loading"},"eager loading")," to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations."),(0,o.kt)("p",null,"To access eager loaded relationship use Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelation<Related>")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto user = User::find(1);\n\nfor (auto *post : user->getRelation<Post>("posts")) {\n //\n}\n')),(0,o.kt)("p",null,"As described above TinyORM offers two methods to access relationships; ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelation")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue"),"."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelation"),' method is for "eager loaded" relations, when the relationship is not loaded, it throws the exception ',(0,o.kt)("inlineCode",{parentName:"p"},"RelationNotLoadedError"),". The ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue"),' is for "lazy loading", when the relationship is not loaded, it will load it.'),(0,o.kt)("p",null,"Both methods have two overloads, the ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelation<Related, Container = QVector>")," overload is for obtaining many type relationships:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto posts = User::find(1)->getRelation<Post>("posts");\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelation<Related, Tag>"),' overload is for obtaining "one" type relationships:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto user = Post::find(1)->getRelation<User, Orm::One>("user");\n')),(0,o.kt)("p",null,"The same is true for the ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue")," method."),(0,o.kt)("h3",{id:"querying-relationship-existence"},"Querying Relationship Existence"),(0,o.kt)("p",null,"When retrieving model records, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the ",(0,o.kt)("inlineCode",{parentName:"p"},"has")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"orHas")," methods:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/post.hpp"\n\n// Retrieve all posts that have at least one comment...\nauto posts = Post::has("comments")->get();\n')),(0,o.kt)("p",null,"You may also specify an operator and count value to further customize the query:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'// Retrieve all posts that have three or more comments...\nauto posts = Post::has("comments", ">=", 3)->get();\n')),(0,o.kt)("p",null,"Nested ",(0,o.kt)("inlineCode",{parentName:"p"},"has"),' statements may be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment that has at least one image:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'// Retrieve posts that have at least one comment with images...\nauto posts = Post::has<Image>("comments.images")->get();\n')),(0,o.kt)("p",null,"If you need even more power, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"whereHas")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"orWhereHas")," methods to define additional query constraints on your ",(0,o.kt)("inlineCode",{parentName:"p"},"has")," queries, such as inspecting the content of a comment:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'// Retrieve posts with at least one comment containing words like code%...\nauto posts = Post::whereHas("comments", [](auto &query)\n{\n query.where("content", LIKE, "code%");\n})->get();\n\n// Retrieve posts with at least ten comments containing words like code%...\nauto posts = Post::whereHas("comments", [](auto &query)\n{\n query.where("content", LIKE, "code%");\n}, ">=", 10)->get();\n')),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"TinyORM does not currently support querying for relationship existence across databases. The relationships must exist within the same database.")),(0,o.kt)("h4",{id:"related-template-parameter"},"Related template parameter"),(0,o.kt)("p",null,"All the ",(0,o.kt)("inlineCode",{parentName:"p"},"has"),"-related methods are templated by the ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template parameter, it looks something like the following ",(0,o.kt)("inlineCode",{parentName:"p"},"has<Related>(..., const std::function<void(CallbackType<Related> &)> &callback = nullptr)"),", you can pass a query callback to this methods and on the base of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," template argument will be decided whether the ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::QueryBuilder")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::TinyBuilder<Related>")," will be passed to the callback. As you can see this ",(0,o.kt)("inlineCode",{parentName:"p"},"Related")," parameter exists because the ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::TinyBuilder<Related>")," needs it."),(0,o.kt)("p",null,"The rule of thumbs are:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"if you don't pass the ",(0,o.kt)("inlineCode",{parentName:"li"},"Related")," template parameter or you pass ",(0,o.kt)("inlineCode",{parentName:"li"},"void")," then the ",(0,o.kt)("inlineCode",{parentName:"li"},"Orm::QueryBuilder &")," will be passed to the callback"),(0,o.kt)("li",{parentName:"ul"},"if you pass it, then the ",(0,o.kt)("inlineCode",{parentName:"li"},"Orm::TinyBuilder<Related> &")," will be passed to the callback"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Related")," has to be of the same type as a relation name passed to the ",(0,o.kt)("inlineCode",{parentName:"li"},"has"),"-related method (a real type of the relation eg. type of the ",(0,o.kt)("inlineCode",{parentName:"li"},"posts")," relation name is ",(0,o.kt)("inlineCode",{parentName:"li"},"Post"),")"),(0,o.kt)("li",{parentName:"ul"},"you have to always pass the ",(0,o.kt)("inlineCode",{parentName:"li"},"Related")," template parameter for nested relations, you can not use nested relations with ",(0,o.kt)("inlineCode",{parentName:"li"},"Related = void")),(0,o.kt)("li",{parentName:"ul"},'in nested relations, where you can pass more relation names using "dot" notation, ',(0,o.kt)("inlineCode",{parentName:"li"},"Related")," has to be of the same type as the ",(0,o.kt)("strong",{parentName:"li"},"last")," relation name passed to the ",(0,o.kt)("inlineCode",{parentName:"li"},"has"),"-related method like you can see in the nested example above or below")),(0,o.kt)("h3",{id:"querying-relationship-absence"},"Querying Relationship Absence"),(0,o.kt)("p",null,"When retrieving model records, you may wish to limit your results based on the absence of a relationship. For example, imagine you want to retrieve all blog posts that ",(0,o.kt)("strong",{parentName:"p"},"don't")," have any comments. To do so, you may pass the name of the relationship to the ",(0,o.kt)("inlineCode",{parentName:"p"},"doesntHave")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"orDoesntHave")," methods:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/post.hpp"\n\nauto posts = Post::doesntHave("comments")->get();\n')),(0,o.kt)("p",null,"If you need even more power, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"whereDoesntHave")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"orWhereDoesntHave")," methods to add additional query constraints to your ",(0,o.kt)("inlineCode",{parentName:"p"},"doesntHave")," queries, such as inspecting the content of a comment:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto posts = Post::whereDoesntHave("comments", [](auto &query)\n{\n query.where("content", LIKE, "code%");\n})->get();\n')),(0,o.kt)("p",null,'You may use "dot" notation to execute a query against a nested relationship. For example, the following query will retrieve all posts that have comments from authors that are not banned:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto posts = Post::whereDoesntHave<Author>("comments.author",\n [](auto &query)\n{\n query.where("banned", false);\n})->get();\n')),(0,o.kt)("h2",{id:"eager-loading"},"Eager Loading"),(0,o.kt)("p",null,"When accessing TinyORM relationships by Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue"),' method, the related models are "lazy loaded". This means the relationship data is not actually loaded until you first access them. However, TinyORM can "eager load" relationships at the time you query the parent model. Eager loading alleviates the "N + 1" query problem. To illustrate the N + 1 query problem, consider a ',(0,o.kt)("inlineCode",{parentName:"p"},"Book"),' model that "belongs to" to an ',(0,o.kt)("inlineCode",{parentName:"p"},"Author")," model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'using Orm::Tiny::Model;\n\nclass Book final : public Model<Book, Author>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the author that wrote the book. */\n std::unique_ptr<BelongsTo<Book, Author>>\n author()\n {\n return belongsTo<Author>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"author", [](auto &v) { v(&Book::author); }},\n };\n};\n')),(0,o.kt)("p",null,"Now, let's retrieve all books and their authors:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include "models/book.hpp"\n\nauto books = Book::all();\n\nfor (auto &book : books)\n qDebug() << book.getRelationValue<Author, Orm::One>("author")\n ->getAttribute<QString>("name");\n')),(0,o.kt)("p",null,"This loop will execute one query to retrieve all of the books within the database table, then another query for each book in order to retrieve the book's author. So, if we have 25 books, the code above would run 26 queries: one for the original book, and 25 additional queries to retrieve the author of each book."),(0,o.kt)("p",null,"Thankfully, we can use eager loading to reduce this operation to just two queries. When building a query, you may specify which relationships should be eager loaded using the ",(0,o.kt)("inlineCode",{parentName:"p"},"with")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto books = Book::with("author")->get();\n\nfor (auto &book : books)\n qDebug() << book.getRelation<Author, Orm::One>("author")\n ->getAttribute<QString>("name");\n')),(0,o.kt)("p",null,"For this operation, only two queries will be executed - one query to retrieve all of the books and one query to retrieve all of the authors for all of the books:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-sql"},"select * from books\n\nselect * from authors where id in (1, 2, 3, 4, 5, ...)\n")),(0,o.kt)("h4",{id:"eager-loading-multiple-relationships"},"Eager Loading Multiple Relationships"),(0,o.kt)("p",null,"Sometimes you may need to eager load several different relationships. To do so, just pass a ",(0,o.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WithItem>")," of relationships to the ",(0,o.kt)("inlineCode",{parentName:"p"},"with")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto books = Book::with({"author", "publisher"})->get();\n')),(0,o.kt)("h4",{id:"nested-eager-loading"},"Nested Eager Loading"),(0,o.kt)("p",null,"To eager a relationship's relationships, you may use \"dot\" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto books = Book::with("author.contacts")->get();\n')),(0,o.kt)("h4",{id:"eager-loading-specific-columns"},"Eager Loading Specific Columns"),(0,o.kt)("p",null,"You may not always need every column from the relationships you are retrieving. For this reason, TinyORM allows you to specify which columns of the relationship you would like to retrieve:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto books = Book::with("author:id,name,book_id")->get();\n')),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"When using this feature, you should always include the ",(0,o.kt)("inlineCode",{parentName:"p"},"id")," column and any relevant foreign key columns in the list of columns you wish to retrieve, otherwise relations will not be loaded correctly.")),(0,o.kt)("h4",{id:"eager-loading-by-default"},"Eager Loading By Default"),(0,o.kt)("p",null,"Sometimes you might want to always load some relationships when retrieving a model. To accomplish this, you may define a ",(0,o.kt)("inlineCode",{parentName:"p"},"u_with")," data member on the model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'using Orm::Tiny::Model;\n\nclass Book final : public Model<Book, Author>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the author that wrote the book. */\n std::unique_ptr<BelongsTo<Book, Author>>\n author()\n {\n return belongsTo<Author>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"author", [](auto &v) { v(&Book::author); }},\n };\n\n /*! The relationships that should always be loaded. */\n QVector<QString> u_with {\n "author",\n };\n};\n')),(0,o.kt)("p",null,"If you would like to remove an item from the ",(0,o.kt)("inlineCode",{parentName:"p"},"u_with")," data member for a single query, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"without")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto books = Book::without("author")->get();\n')),(0,o.kt)("p",null,"If you would like to override all items within the ",(0,o.kt)("inlineCode",{parentName:"p"},"u_with")," data member for a single query, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"withOnly")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto books = Book::withOnly("genre")->get();\n')),(0,o.kt)("h3",{id:"constraining-eager-loads"},"Constraining Eager Loads"),(0,o.kt)("p",null,"Sometimes you may wish to eager load a relationship but also specify additional query conditions for the eager loading query. You can accomplish this by passing a ",(0,o.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WithItem>")," of relationships to the ",(0,o.kt)("inlineCode",{parentName:"p"},"with")," method where the ",(0,o.kt)("inlineCode",{parentName:"p"},"name")," data member of ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::WithItem")," struct is a relationship name and the ",(0,o.kt)("inlineCode",{parentName:"p"},"constraints")," data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the ",(0,o.kt)("inlineCode",{parentName:"p"},"constraints")," lambda expression is an underlying ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::QueryBuilder")," for a related model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/user.hpp"\n\nauto users = User::with({{"posts", [](auto &query)\n{\n query.where("title", "like", "%code%");\n}}})->get();\n')),(0,o.kt)("p",null,"In this example, TinyORM will only eager load posts where the post's ",(0,o.kt)("inlineCode",{parentName:"p"},"title")," column contains the word ",(0,o.kt)("inlineCode",{parentName:"p"},"code"),". You may call other ",(0,o.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builder")," methods to further customize the eager loading operation:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto users = User::with({{"posts", [](auto &query)\n{\n query.orderBy("created_at", "desc");\n}}})->get();\n')),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"The ",(0,o.kt)("inlineCode",{parentName:"p"},"limit")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"take")," query builder methods may not be used when constraining eager loads.")),(0,o.kt)("h3",{id:"lazy-eager-loading"},"Lazy Eager Loading"),(0,o.kt)("p",null,"Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/book.hpp"\n\nauto book = Book::find(1);\n\nif (someCondition)\n book->load("author");\n')),(0,o.kt)("p",null,"You may load more relationships at once, to do so, just pass a ",(0,o.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WithItem>")," of relationships to the ",(0,o.kt)("inlineCode",{parentName:"p"},"load")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'Book::find(1)->load({"author", "publisher"});\n')),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"So far, this only works on models, not on containers returned from Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"get")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"all")," methods.")),(0,o.kt)("p",null,"If you need to set additional query constraints on the eager loading query, you may pass a ",(0,o.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WithItem>")," of relationships to the ",(0,o.kt)("inlineCode",{parentName:"p"},"load")," method where the ",(0,o.kt)("inlineCode",{parentName:"p"},"name")," data member of ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::WithItem")," struct is a relationship name and the ",(0,o.kt)("inlineCode",{parentName:"p"},"constraints")," data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the ",(0,o.kt)("inlineCode",{parentName:"p"},"constraints")," lambda expression is an underlying ",(0,o.kt)("inlineCode",{parentName:"p"},"Orm::QueryBuilder")," for a related model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'author->load({{"books", [](auto &query)\n{\n query.orderBy("published_date", "asc");\n}}});\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"You can also use eager constraining in the Model's ",(0,o.kt)("inlineCode",{parentName:"p"},"fresh")," method.")),(0,o.kt)("h2",{id:"inserting-and-updating-related-models"},"Inserting & Updating Related Models"),(0,o.kt)("h3",{id:"the-save-method"},"The ",(0,o.kt)("inlineCode",{parentName:"h3"},"save")," Method"),(0,o.kt)("p",null,"TinyORM provides convenient methods for adding new models to relationships. For example, perhaps you need to add a new comment to a post. Instead of manually setting the ",(0,o.kt)("inlineCode",{parentName:"p"},"post_id")," attribute on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Comment")," model you may insert the comment using the relationship's ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/comment.hpp"\n#include "models/post.hpp"\n\nComment comment({{"message", "A new comment."}});\n\nauto post = Post::find(1);\n\npost->comments()->save(comment);\n')),(0,o.kt)("p",null,"Note that we did not access the ",(0,o.kt)("inlineCode",{parentName:"p"},"comments")," relationship with the ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelation")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"getRelationValue")," method. Instead, we called the ",(0,o.kt)("inlineCode",{parentName:"p"},"comments")," method to obtain an instance of the relationship. The ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," method will automatically add the appropriate ",(0,o.kt)("inlineCode",{parentName:"p"},"post_id")," value to the new ",(0,o.kt)("inlineCode",{parentName:"p"},"Comment")," model."),(0,o.kt)("p",null,"If you need to save multiple related models, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"saveMany")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto post = Post::find(1);\n\npost->comments()->saveMany({\n {{"message", "A new comment."}},\n {{\'message", "Another new comment."}},\n});\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"saveMany")," methods will not add the new models to any in-memory relationships that are already loaded onto the parent model. If you plan on accessing the relationship after using the ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"saveMany")," methods, you may wish to use the ",(0,o.kt)("inlineCode",{parentName:"p"},"refresh")," method to reload the model and its relationships:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'post->comments()->save(comment);\n\npost->refresh();\n\n// All comments, including the newly saved comment...\npost->getRelation<Comment>("comments");\n')),(0,o.kt)("p",null,"The many-to-many relationship also supports the ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"saveMany")," methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto user = User::find(2);\n\nRole role {{"name", "admin"}};\n\nuser->roles()->save(role, {{"active", true}});\n\nRole role1 {{"name", "edit"}};\nRole role2 {{"name", "view"}};\n\nuser->roles()->saveMany({role1, role2}, {{{"active", true}},\n {{"active", false}}});\n\n// No pivot attributes for role1\nuser->roles()->saveMany({role1, role2}, {{}, {{"active", false}}});\n')),(0,o.kt)("h4",{id:"recursively-saving-models--relationships"},"Recursively Saving Models & Relationships"),(0,o.kt)("p",null,"If you would like to ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," your model and all of its associated relationships, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"push")," method. In this example, the ",(0,o.kt)("inlineCode",{parentName:"p"},"Post")," model will be saved as well as its comments and the comment's authors:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto post = Post::find(1);\n\npost->getRelationValue<Comment>("comments").at(0)->setAttribute("message", "Message");\n\npost->getRelationValue<Comment>("comments").first()\n ->getRelationValue<User, Orm::One>("author")->setAttribute("name", "Author Name");\n\npost->push();\n')),(0,o.kt)("h3",{id:"the-create-method"},"The ",(0,o.kt)("inlineCode",{parentName:"h3"},"create")," Method"),(0,o.kt)("p",null,"In addition to the ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"saveMany")," methods, you may also use the ",(0,o.kt)("inlineCode",{parentName:"p"},"create")," method, which accepts a vector of attributes, creates a model, and inserts it into the database. The difference between ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"create")," is that ",(0,o.kt)("inlineCode",{parentName:"p"},"save")," accepts a full TinyORM model instance while ",(0,o.kt)("inlineCode",{parentName:"p"},"create")," accepts a ",(0,o.kt)("inlineCode",{parentName:"p"},"QVector<Orm::AttributeItem>"),". The newly created model will be returned by the ",(0,o.kt)("inlineCode",{parentName:"p"},"create")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/post.hpp"\n\nauto post = Post::find(1);\n\nauto comment = post->comments()->create({\n {"message", "A new comment."},\n});\n')),(0,o.kt)("p",null,"You may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"createMany")," method to create multiple related models:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto post = Post::find(1);\n\nauto comments = post->comments()->createMany({\n {{"message", "A new comment."}, {"is_published", true}},\n {{"message", "Another new comment."}, {"is_published", false}},\n});\n')),(0,o.kt)("p",null,"The many-to-many relationship also supports the ",(0,o.kt)("inlineCode",{parentName:"p"},"create")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"createMany")," methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto user = User::find(2);\n\nuser->roles()->create({{"name", "admin"}}, {{"active", true}});\n\nuser->roles()->createMany({\n {{"name", "edit"}},\n {{"name", "view"}},\n}, {\n {{"active", true}},\n {{"active", false}},\n});\n\n// No pivot attributes for the first role\nuser->roles()->createMany({\n {{"name", "edit"}},\n {{"name", "view"}},\n}, {\n {},\n {{"active", false}},\n});\n')),(0,o.kt)("p",null,"You may also use the ",(0,o.kt)("inlineCode",{parentName:"p"},"findOrNew"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"firstOrNew"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"firstOrCreate"),", and ",(0,o.kt)("inlineCode",{parentName:"p"},"updateOrCreate")," methods to ",(0,o.kt)("a",{parentName:"p",href:"/tinyorm/getting-started#retrieving-or-creating-models"},"create and update models on relationships"),"."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Before using the ",(0,o.kt)("inlineCode",{parentName:"p"},"create")," method, be sure to review the ",(0,o.kt)("a",{parentName:"p",href:"/tinyorm/getting-started#mass-assignment"},"mass assignment")," documentation.")),(0,o.kt)("h3",{id:"updating-belongs-to-relationships"},"Belongs To Relationships"),(0,o.kt)("p",null,"If you would like to assign a child model to a new parent model, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"associate")," method. In this example, the ",(0,o.kt)("inlineCode",{parentName:"p"},"User")," model defines a ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo")," relationship to the ",(0,o.kt)("inlineCode",{parentName:"p"},"Account")," model. The ",(0,o.kt)("inlineCode",{parentName:"p"},"associate")," method will set the foreign key on the child model:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/user.hpp"\n\nUser user {{"name", "Mike"}};\n\nauto account = Account::find(10);\n\nuser.account()->associate(*account);\n\nuser.save();\n')),(0,o.kt)("p",null,"To remove a parent model from a child model, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"dissociate")," method. This method will set the relationship's foreign key to ",(0,o.kt)("inlineCode",{parentName:"p"},"null"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"user.account()->dissociate();\n\nuser.save();\n")),(0,o.kt)("h3",{id:"updating-many-to-many-relationships"},"Many To Many Relationships"),(0,o.kt)("h4",{id:"attaching--detaching"},"Attaching / Detaching"),(0,o.kt)("p",null,"TinyORM also provides methods to make working with many-to-many relationships more convenient. For example, let's imagine a user can have many roles and a role can have many users. You may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"attach")," method to attach a role to a user by inserting a record in the relationship's intermediate table:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'#include "models/user.hpp"\n\nauto user = User::find(1);\n\nuser->roles()->attach(roleId);\n')),(0,o.kt)("p",null,"When attaching a relationship to a model, you may also pass a vector of additional data to be inserted into the intermediate table:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'const auto expires = true;\n\nuser->roles()->attach(roleId, {{"expires", expires}});\n')),(0,o.kt)("p",null,"Sometimes it may be necessary to remove a role from a user. To remove a many-to-many relationship record, use the ",(0,o.kt)("inlineCode",{parentName:"p"},"detach")," method. The ",(0,o.kt)("inlineCode",{parentName:"p"},"detach")," method will delete the appropriate record out of the intermediate table; however, both models will remain in the database:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"// Detach a single role from the user...\nuser->roles()->detach(roleId);\n\n// Detach all roles from the user...\nuser->roles()->detachAll();\n")),(0,o.kt)("p",null,"For convenience, ",(0,o.kt)("inlineCode",{parentName:"p"},"attach")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"detach")," also accept vectors of IDs or Model instances as input:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto user = User::find(1);\n\nuser->roles()->detach({1, 2, 3});\n\nRole role1({{"name", "Role 1"}});\nrole1.save();\nRole role2({{"name", "Role 2"}});\nrole2.save();\n\nuser->roles()->attach({{role1}, {role2}});\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"attach")," method also accepts ",(0,o.kt)("inlineCode",{parentName:"p"},"std::map")," as input, so you can pass different attributes for each model you are attaching:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'user->roles()->attach({\n {1, {{"expires", true}, {"is_active", false}}},\n {2, {{"expires", false}, {"is_active", true}}},\n});\n')),(0,o.kt)("h4",{id:"syncing-associations"},"Syncing Associations"),(0,o.kt)("p",null,"You may also use the ",(0,o.kt)("inlineCode",{parentName:"p"},"sync")," method to construct many-to-many associations. The ",(0,o.kt)("inlineCode",{parentName:"p"},"sync")," method accepts a vector of IDs to place on the intermediate table. Any IDs that are not in the given vector will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given vector will exist in the intermediate table:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"user->roles()->sync({1, 2, 3});\n")),(0,o.kt)("p",null,"You may also pass additional intermediate table values with the IDs:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'user->roles()->sync({\n {1, {{"expires", true}}},\n {2, {}},\n {3, {}},\n});\n')),(0,o.kt)("p",null,"If you do not want to detach existing IDs that are missing from the given vector, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"syncWithoutDetaching")," method:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"user->roles()->syncWithoutDetaching({1, 2, 3});\n")),(0,o.kt)("h4",{id:"updating-a-record-on-the-intermediate-table"},"Updating A Record On The Intermediate Table"),(0,o.kt)("p",null,"If you need to update an existing row in your relationship's intermediate table, you may use the ",(0,o.kt)("inlineCode",{parentName:"p"},"updateExistingPivot")," method. This method accepts the intermediate record foreign key and the vector of attributes to update:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'auto user = User::find(1);\n\nuser->roles()->updateExistingPivot(roleId, {\n {"active", false},\n});\n')),(0,o.kt)("h2",{id:"touching-parent-timestamps"},"Touching Parent Timestamps"),(0,o.kt)("p",null,"When a model defines a ",(0,o.kt)("inlineCode",{parentName:"p"},"belongsTo")," relationship to another model, such as a ",(0,o.kt)("inlineCode",{parentName:"p"},"Comment")," which belongs to a ",(0,o.kt)("inlineCode",{parentName:"p"},"Post"),", it is sometimes helpful to update the parent's timestamp when the child model is updated."),(0,o.kt)("p",null,"For example, when a ",(0,o.kt)("inlineCode",{parentName:"p"},"Comment"),' model is updated, you may want to automatically "touch" the ',(0,o.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamp of the owning ",(0,o.kt)("inlineCode",{parentName:"p"},"Post")," so that it is set to the current date and time. To accomplish this, you may add a ",(0,o.kt)("inlineCode",{parentName:"p"},"u_touches")," data member to your child model containing the names of the relationships that should have their ",(0,o.kt)("inlineCode",{parentName:"p"},"updated_at")," timestamps updated when the child model is updated:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'using Orm::Tiny::Model;\n\nclass Comment final : public Model<Comment, Post>\n{\n friend Model;\n using Model::Model;\n\npublic:\n /*! Get the post that owns the comment. */\n std::unique_ptr<BelongsTo<Comment, Post>>\n post()\n {\n return belongsTo<Post>();\n }\n\nprivate:\n /*! Map of relation names to methods. */\n QHash<QString, RelationVisitor> u_relations {\n {"post", [](auto &v) { v(&Comment::post); }},\n };\n\n /*! All of the relationships to be touched. */\n QStringList u_touches {"post"};\n};\n')),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Parent model timestamps will only be updated if the child model is updated using TinyORM's ",(0,o.kt)("inlineCode",{parentName:"p"},"save"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"push"),", or ",(0,o.kt)("inlineCode",{parentName:"p"},"remove")," method.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8a8faf8d.83cd2a22.js b/assets/js/8a8faf8d.83cd2a22.js deleted file mode 100644 index 41f8f5988..000000000 --- a/assets/js/8a8faf8d.83cd2a22.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[225],{5162:(e,t,n)=>{n.d(t,{Z:()=>r});var a=n(7294),i=n(6010);const o={tabItem:"tabItem_Ymn6"};function r(e){let{children:t,hidden:n,className:r}=e;return a.createElement("div",{role:"tabpanel",className:(0,i.Z)(o.tabItem,r),hidden:n},t)}},4866:(e,t,n)=>{n.d(t,{Z:()=>y});var a=n(7462),i=n(7294),o=n(6010),r=n(2466),l=n(6550),s=n(1980),p=n(7392),m=n(12);function d(e){return function(e){return i.Children.map(e,(e=>{if(!e||(0,i.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(e).map((e=>{let{props:{value:t,label:n,attributes:a,default:i}}=e;return{value:t,label:n,attributes:a,default:i}}))}function u(e){const{values:t,children:n}=e;return(0,i.useMemo)((()=>{const e=t??d(n);return function(e){const t=(0,p.l)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e}),[t,n])}function c(e){let{value:t,tabValues:n}=e;return n.some((e=>e.value===t))}function k(e){let{queryString:t=!1,groupId:n}=e;const a=(0,l.k6)(),o=function(e){let{queryString:t=!1,groupId:n}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!n)throw new Error('Docusaurus error: The <Tabs> 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 n??null}({queryString:t,groupId:n});return[(0,s._X)(o),(0,i.useCallback)((e=>{if(!o)return;const t=new URLSearchParams(a.location.search);t.set(o,e),a.replace({...a.location,search:t.toString()})}),[o,a])]}function h(e){const{defaultValue:t,queryString:n=!1,groupId:a}=e,o=u(e),[r,l]=(0,i.useState)((()=>function(e){let{defaultValue:t,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(t){if(!c({value:t,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const a=n.find((e=>e.default))??n[0];if(!a)throw new Error("Unexpected error: 0 tabValues");return a.value}({defaultValue:t,tabValues:o}))),[s,p]=k({queryString:n,groupId:a}),[d,h]=function(e){let{groupId:t}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(t),[a,o]=(0,m.Nk)(n);return[a,(0,i.useCallback)((e=>{n&&o.set(e)}),[n,o])]}({groupId:a}),g=(()=>{const e=s??d;return c({value:e,tabValues:o})?e:null})();(0,i.useLayoutEffect)((()=>{g&&l(g)}),[g]);return{selectedValue:r,selectValue:(0,i.useCallback)((e=>{if(!c({value:e,tabValues:o}))throw new Error(`Can't select invalid tab value=${e}`);l(e),p(e),h(e)}),[p,h,o]),tabValues:o}}var g=n(2389);const b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function N(e){let{className:t,block:n,selectedValue:l,selectValue:s,tabValues:p}=e;const m=[],{blockElementScrollPositionUntilNextRender:d}=(0,r.o5)(),u=e=>{const t=e.currentTarget,n=m.indexOf(t),a=p[n].value;a!==l&&(d(t),s(a))},c=e=>{let t=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{const n=m.indexOf(e.currentTarget)+1;t=m[n]??m[0];break}case"ArrowLeft":{const n=m.indexOf(e.currentTarget)-1;t=m[n]??m[m.length-1];break}}t?.focus()};return i.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":n},t)},p.map((e=>{let{value:t,label:n,attributes:r}=e;return i.createElement("li",(0,a.Z)({role:"tab",tabIndex:l===t?0:-1,"aria-selected":l===t,key:t,ref:e=>m.push(e),onKeyDown:c,onClick:u},r,{className:(0,o.Z)("tabs__item",b.tabItem,r?.className,{"tabs__item--active":l===t})}),n??t)})))}function f(e){let{lazy:t,children:n,selectedValue:a}=e;const o=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){const e=o.find((e=>e.props.value===a));return e?(0,i.cloneElement)(e,{className:"margin-top--md"}):null}return i.createElement("div",{className:"margin-top--md"},o.map(((e,t)=>(0,i.cloneElement)(e,{key:t,hidden:e.props.value!==a}))))}function T(e){const t=h(e);return i.createElement("div",{className:(0,o.Z)("tabs-container",b.tabList)},i.createElement(N,(0,a.Z)({},e,t)),i.createElement(f,(0,a.Z)({},e,t)))}function y(e){const t=(0,g.Z)();return i.createElement(T,(0,a.Z)({key:String(t)},e))}},2044:(e,t,n)=>{n.d(t,{$t:()=>d,Ae:()=>g,C:()=>k,DK:()=>b,Fo:()=>l,Fs:()=>i,IM:()=>h,IZ:()=>a,RS:()=>C,VE:()=>N,Wg:()=>T,_A:()=>p,al:()=>_,jk:()=>c,js:()=>s,of:()=>m,q5:()=>r,qb:()=>y,vk:()=>u,wU:()=>o,zg:()=>f});const a="shell",i="database",o="application",r="bash",l="pwsh",s="zsh",p="maria",m="mysql",d="postgres",u="sqlite",c="application",k="bash",h="pwsh",g="zsh",b="MariaDB",N="MySQL",f="PostgreSQL",T="SQLite",y="tinyorm.org",_="$HOME/Code/c/",C="$env:USERPROFILE\\Code\\c\\"},4355:(e,t,n)=>{n.d(t,{Z:()=>o});var a=n(7294),i=n(9482);function o(){const e=(0,a.useContext)(i.Z);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6005:(e,t,n)=>{n.d(t,{AE:()=>l,EA:()=>r,em:()=>p,go:()=>s,mT:()=>m,we:()=>d});var a=n(4355),i=n(2389),o=n(2044);const r=function(e,t){return void 0===t&&(t=!0),u((0,a.Z)().rootFolder[e]??p(e),e,t)},l=()=>(0,a.Z)().rootFolder[o.wU]??p(o.wU),s=function(e,t){if(void 0===t&&(t=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const n=t||e!==o.Fo?"/":"\\";return u(r(e)+n+l(),e,t)};function p(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,i.Z)())return"";switch(e){case o.Fo:return o.RS;case o.q5:return o.al;case o.wU:return o.qb;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function m(e){return e===o.wU}function d(e,t){if(null==t||""===t)return t;const n="$ENV{$1}$2";switch(e){case o.Fo:return k(t).replace(/\$env:(.+?)(\/.*)/,n);case o.q5:return t.replace(/\$(.+?)(\/.*)/,n);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function u(e,t,n){if(void 0===n&&(n=!0),null==e||""===e)return e;if(t!==o.Fo)return c(e);const a=c(e);return n?k(a):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(a)}function c(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function k(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},3974:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>d,default:()=>b,frontMatter:()=>m,metadata:()=>u,toc:()=>k});var a=n(7462),i=(n(7294),n(3905)),o=n(7693),r=n(5162),l=n(4866),s=n(2044),p=n(6005);const m={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"]},d="Building: Migrations",u={unversionedId:"building/migrations",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,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/building/migrations.mdx",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"}},c={},k=[{value:"Introduction",id:"introduction",level:2},{value:"Install dependencies",id:"install-dependencies",level:2},{value:"Using vcpkg.json <small>(manifest mode)</small>",id:"using-vcpkg-json-manifest-mode",level:4},{value:"Using vcpkg install <small>(manually)</small>",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:"<code>Auto-configure</code> using <code>.qmake.conf</code> and <code>.env</code>",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}],h={toc:k},g="wrapper";function b(e){let{components:t,...m}=e;return(0,i.kt)(g,(0,a.Z)({},h,m,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"building-migrations"},"Building: Migrations"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#install-dependencies"},"Install dependencies"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#using-vcpkg-json-manifest-mode"},"Using vcpkg.json")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#using-vcpkg-install-manually"},"Using vcpkg install")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#source-code"},"Source code"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#main-file"},"Main file")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#migrations"},"Migrations")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#seeders"},"Seeders")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#migrations-with-cmake"},"Migrations with CMake"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#cmake-project"},"CMake project")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#build-migrations-cmake"},"Build migrations")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#execute-migrations-cmake"},"Execute migrations")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#migrations-with-qmake"},"Migrations with qmake"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#qmake-project"},"qmake project")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#build-migrations-qmake"},"Build migrations")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#execute-migrations-qmake"},"Execute migrations")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#finish"},"Finish"))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,"We will try to create a working migrations console application called as ",(0,i.kt)("abbr",{title:"TinyORM migrations"},(0,i.kt)("inlineCode",{parentName:"p"},"tom"))," in the terminal with the ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," and in the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtCreator IDE")," with the ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," build systems."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," console application also expects the following ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},"folders structure"),", let's create them."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,p.go)(s.Fo)}\nmkdir tom/tom\ncd tom`)),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,p.go)(s.q5)}\nmkdir -p tom/tom\ncd tom`))),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," source tree contains the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," example application, you can inspire or look at the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/tree/main/examples/tom"},"source code"),". Also, ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," unit tests use a ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," migrations internally to create the database structure, internally called as the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/tree/main/tests/testdata_tom"},(0,i.kt)("inlineCode",{parentName:"a"},"tom")," migrations for unit tests"),"."),(0,i.kt)("p",null,"All these three console applications the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," example, ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," migrations for unit tests, and the application described in this tutorial have practically identical source code (the main.cpp file)."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," is able to generate ",(0,i.kt)("a",{href:"https://en.wikipedia.org/wiki/Data_definition_language",title:"Data Definition Language"},"DDL")," queries for all the ",(0,i.kt)("a",{parentName:"p",href:"/database/getting-started#introduction"},"supported databases")," databases.")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"You can see the ",(0,i.kt)("a",{parentName:"p",href:"/features-summary#tom-console-application"},"Tom showcase image")," of how the resulting ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," console application will look like.")),(0,i.kt)("h2",{id:"install-dependencies"},"Install dependencies"),(0,i.kt)("p",null,"First, install the ",(0,i.kt)("inlineCode",{parentName:"p"},"vcpkg")," package manager as is described ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#vcpkg"},"here"),"."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"range-v3")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"tabulate")," libraries are required dependencies because ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," uses them in header files, you have to install them before you can use ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM"),". The ",(0,i.kt)("inlineCode",{parentName:"p"},"tabulate")," library is only needed in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," migrations it's used by the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:status")," command."),(0,i.kt)("p",null,"There are two ways how to install the ",(0,i.kt)("inlineCode",{parentName:"p"},"range-v3")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"tabulate")," libraries using ",(0,i.kt)("inlineCode",{parentName:"p"},"vcpkg"),"."),(0,i.kt)("p",null,"Also, don't forget to build the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," library with the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," source code enabled (it's enabled by default) as is described ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm"},"here"),"."),(0,i.kt)("h4",{id:"using-vcpkg-json-manifest-mode"},"Using vcpkg.json ",(0,i.kt)("small",null,"(manifest mode)")),(0,i.kt)("p",null,"Create a ",(0,i.kt)("inlineCode",{parentName:"p"},"vcpkg.json")," file with the following content. ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," example below uses this method."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd tom\nvim vcpkg.json\n")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json",metastring:"title='vcpkg.json'",title:"'vcpkg.json'"},'{\n "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",\n "name": "tom",\n "version-semver": "0.1.0",\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 "maintainers": "Silver Zachara <silver.zachara@gmail.com>",\n "supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",\n "dependencies": [\n "range-v3",\n "tabulate"\n ]\n}\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"Only ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," via the ",(0,i.kt)("inlineCode",{parentName:"p"},"toolchain file")," supports this method.")),(0,i.kt)("h4",{id:"using-vcpkg-install-manually"},"Using vcpkg install ",(0,i.kt)("small",null,"(manually)")),(0,i.kt)("p",null,"This method can be used with both ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd ../../vcpkg\n\nvcpkg search range-v3\nvcpkg search tabulate\nvcpkg install range-v3 tabulate\nvcpkg list\n")),(0,i.kt)("h2",{id:"source-code"},"Source code"),(0,i.kt)("p",null,"Let's start in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," project folder."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,p.go)(s.Fo)}/tom/tom`)),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,p.go)(s.q5)}/tom/tom`))),(0,i.kt)("h3",{id:"main-file"},"Main file"),(0,i.kt)("p",null,"Create ",(0,i.kt)("inlineCode",{parentName:"p"},"main.cpp")," source file."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"vim main.cpp\n")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"To paste a source code correctly in ",(0,i.kt)("inlineCode",{parentName:"p"},"vim"),", press ",(0,i.kt)("kbd",null,"Shift")," + ",(0,i.kt)("kbd",null,"p"),".")),(0,i.kt)("p",null,"And paste the following code."),(0,i.kt)("a",{id:"string-constants-example"}),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp",metastring:"title='main.cpp'",title:"'main.cpp'"},'#include <orm/db.hpp>\n\n#include <tom/application.hpp>\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<DatabaseManager> 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<CreatePostsTable>()\n .seeders<DatabaseSeeder>()\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<DatabaseManager> 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')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"If you have defined more database connections then you can tag the lines with the database connection names with the ",(0,i.kt)("inlineCode",{parentName:"p"},"// shell:connection")," comment and this connection names will be provided to the bash, zsh, pwsh completions for the ",(0,i.kt)("inlineCode",{parentName:"p"},"--database=")," option \ud83d\ude0e, ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/examples/tom/main.cpp#L74"},"example"),".")),(0,i.kt)("h3",{id:"migrations"},"Migrations"),(0,i.kt)("p",null,"If you have already built the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application then you can generate a migrations using the ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations#generating-migrations"},(0,i.kt)("inlineCode",{parentName:"a"},"make:migration"))," command \ud83d\ude0e."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:migration create_posts_table\n")),(0,i.kt)("p",null,"Below is the expected folders structure for the migrations. The ",(0,i.kt)("a",{parentName:"p",href:"#migrations-source-files"},(0,i.kt)("inlineCode",{parentName:"a"},"migrations.pri"))," file is used only by the ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," build system and is not needed with ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," builds."),(0,i.kt)("a",{id:"folders-structure"}),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-text"},"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")),(0,i.kt)("p",null,"Let's create the first migration manually."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},"mkdir database/migrations\n\nvim database/migrations/2014_10_12_000000_create_posts_table.hpp")),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},"mkdir -p database/migrations\n\nvim database/migrations/2014_10_12_000000_create_posts_table.hpp"))),(0,i.kt)("p",null,"And paste the following code."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp",metastring:"title='database/migrations/2014_10_12_000000_create_posts_table.hpp'",title:"'database/migrations/2014_10_12_000000_create_posts_table.hpp'"},'#pragma once\n\n#include <tom/migration.hpp>\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')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," source tree contains the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/tests/database/migrations/2014_10_12_000000_create_posts_table.hpp#L5"},(0,i.kt)("inlineCode",{parentName:"a"},"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.")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"If you want, you can also build the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application without the migrations, simply comment out the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrations")," method and the corresponding ",(0,i.kt)("inlineCode",{parentName:"p"},'#include "migrations/xyz.hpp"')," files.")),(0,i.kt)("h3",{id:"seeders"},"Seeders"),(0,i.kt)("p",null,"If you have already built the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application then you can generate a seeder using the ",(0,i.kt)("a",{parentName:"p",href:"/database/seeding#writing-seeders"},(0,i.kt)("inlineCode",{parentName:"a"},"make:seeder"))," command \ud83d\ude0e."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:seeder PostSeeder\n")),(0,i.kt)("p",null,"The expected folders structure is described a few paragraphs ",(0,i.kt)("a",{parentName:"p",href:"#folders-structure"},"above"),". The ",(0,i.kt)("a",{parentName:"p",href:"#seeders-source-files"},(0,i.kt)("inlineCode",{parentName:"a"},"seeders.pri"))," file is used only by the ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," build system and is not needed with ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," builds."),(0,i.kt)("p",null,"Let's create the root seeder class manually."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},"mkdir database/seeders\n\nvim database/seeders/databaseseeder.hpp")),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},"mkdir -p database/seeders\n\nvim database/seeders/databaseseeder.hpp"))),(0,i.kt)("p",null,"And paste the following code."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cpp",metastring:"title='database/seeders/databaseseeder.hpp'",title:"'database/seeders/databaseseeder.hpp'"},'#pragma once\n\n#include <tom/seeder.hpp>\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')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," source tree contains the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/tests/database/seeders/databaseseeder.hpp#L8"},(0,i.kt)("inlineCode",{parentName:"a"},"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.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can create more seeder classes like this and use the ",(0,i.kt)("inlineCode",{parentName:"p"},"call<>()")," method to invoke them as is described in the ",(0,i.kt)("a",{parentName:"p",href:"/database/seeding#calling-additional-seeders"},"Calling Additional Seeders")," section.")),(0,i.kt)("h2",{id:"migrations-with-cmake"},"Migrations with CMake"),(0,i.kt)("p",null,"Create a folder for the ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," build."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},"cd ..\nmkdir tom-builds-cmake/build-debug\n\ncd tom")),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},"cd ..\nmkdir -p tom-builds-cmake/build-debug\n\ncd tom"))),(0,i.kt)("h3",{id:"cmake-project"},"CMake project"),(0,i.kt)("p",null,"Create ",(0,i.kt)("inlineCode",{parentName:"p"},"CMakeLists.txt")," file with the following content. I leave the comments in the ",(0,i.kt)("inlineCode",{parentName:"p"},"CMakeLists.txt")," file because it's not as simple as the ",(0,i.kt)("inlineCode",{parentName:"p"},"Hello world")," example; to make it clear what's going on."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-cmake",metastring:"title='CMakeLists.txt'",title:"'CMakeLists.txt'"},'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 "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/database>"\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')),(0,i.kt)("h3",{id:"build-migrations-cmake"},"Build migrations"),(0,i.kt)("p",null,"Now you are ready to configure ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," application. Don't forget to prepare the build environment with the ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#windows-prerequisites"},(0,i.kt)("inlineCode",{parentName:"a"},"qtenv6.ps1"))," command if you are building with the ",(0,i.kt)("inlineCode",{parentName:"p"},"msvc"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd ../tom-builds-cmake/build-debug\n")),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cmake.exe \`\n-S "${(0,p.go)(s.Fo)}/tom/tom" \`\n-B "${(0,p.go)(s.Fo)}/tom/tom-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,p.EA)(s.Fo)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,p.EA)(s.Fo)}/tmp/tom"`)),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cmake \\\n-S "${(0,p.go)(s.q5)}/tom/tom" \\\n-B "${(0,p.go)(s.q5)}/tom/tom-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,p.EA)(s.q5)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,p.EA)(s.q5)}/tmp/tom"`))),(0,i.kt)("p",null,"And build."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cmake --build . --target all\n")),(0,i.kt)("h3",{id:"execute-migrations-cmake"},"Execute migrations"),(0,i.kt)("p",null,"Do not forget to add ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyOrm0d.dll")," on the path on Windows and on the ",(0,i.kt)("inlineCode",{parentName:"p"},"LD_LIBRARY_PATH")," on Linux, so ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application can find it during execution, as is described ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#tinyorm-on-path-cmake"},"here"),"."),(0,i.kt)(l.Z,{groupId:s.IZ,name:"tinyorm-on-path",mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`$env:Path = "${(0,p.go)(s.Fo,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`)),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`export LD_LIBRARY_PATH=${(0,p.go)(s.q5)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`))),(0,i.kt)("p",null,"Execute ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-powershell"},".\\tom.exe migrate:status\n"))),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"./tom migrate:status\n")))),(0,i.kt)("p",null,"The output will look something like this."),(0,i.kt)("img",{src:n(3086).Z,alt:"Tom migrations - migrate:status command output",width:"660"}),(0,i.kt)("p",null,"See also the ",(0,i.kt)("a",{parentName:"p",href:"#finish"},"final thoughts")," on how to verify the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," executable file properties."),(0,i.kt)("p",null,"Happy migrating \ud83c\udf89\ud83d\udc4c"),(0,i.kt)("h2",{id:"migrations-with-qmake"},"Migrations with qmake"),(0,i.kt)("p",null,"Create a folder for the ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," build."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:s.IM,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,p.go)(s.Fo)}/tom\n\nmkdir tom-builds-qmake`)),(0,i.kt)(r.Z,{value:s.q5,label:s.C,mdxType:"TabItem"},(0,i.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,p.go)(s.q5)}/tom\n\nmkdir tom-builds-qmake`))),(0,i.kt)("p",null,"The ",(0,i.kt)("a",{parentName:"p",href:"#source-code"},(0,i.kt)("inlineCode",{parentName:"a"},"source code"))," is the same as for the ",(0,i.kt)("inlineCode",{parentName:"p"},"Migrations with CMake")," console application."),(0,i.kt)("h3",{id:"qmake-project"},"qmake project"),(0,i.kt)("p",null,"Create ",(0,i.kt)("inlineCode",{parentName:"p"},"tom.pro")," qmake file with the following content."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd tom\nvim tom.pro\n")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"To paste a source code correctly in ",(0,i.kt)("inlineCode",{parentName:"p"},"vim"),", press ",(0,i.kt)("kbd",null,"Shift")," + ",(0,i.kt)("kbd",null,"p"),".")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='tom.pro'",title:"'tom.pro'"},"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")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The exact ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},"folders structure")," is crucial in this example because the paths to the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," source and build folders are relative.")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!")),(0,i.kt)("h4",{id:"auto-configure-using-qmakeconf-and-env"},(0,i.kt)("inlineCode",{parentName:"h4"},"Auto-configure")," using ",(0,i.kt)("inlineCode",{parentName:"h4"},".qmake.conf")," and ",(0,i.kt)("inlineCode",{parentName:"h4"},".env")),(0,i.kt)("p",null,"If you want to have properly configured ",(0,i.kt)("inlineCode",{parentName:"p"},"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,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," qmake features (",(0,i.kt)("inlineCode",{parentName:"p"},".prf")," files) which handle this correctly; this path is provided by the ",(0,i.kt)("inlineCode",{parentName:"p"},"QMAKEFEATURES")," variable and can only be set in the ",(0,i.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Read the ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#consume-tinyorm-library-qmake"},"Consume TinyOrm library (qmake)")," section, as everything that is described in that section applies here as well.")),(0,i.kt)("p",null,"Create the ",(0,i.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application root folder with the following content."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='.qmake.conf'",title:"'.qmake.conf'"},"# 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")),(0,i.kt)("p",null,"Then, create a ",(0,i.kt)("code",null,".env.(win32","|","unix","|","mingw)")," file in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application root folder with the following content."),(0,i.kt)(l.Z,{groupId:s.IZ,mdxType:"Tabs"},(0,i.kt)(r.Z,{value:s.Fo,label:".env.win32",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-qmake"},"# 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_0_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 *= tiny_ccache_win32\n"))),(0,i.kt)(r.Z,{value:s.q5,label:".env.unix",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-qmake"},"# 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_0_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,i.kt)(r.Z,{value:"mingw",label:".env.mingw",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-qmake"},"# 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_0_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 *= tiny_ccache_win32\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")))),(0,i.kt)("p",null,"Don't forget to update the ",(0,i.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"TINY_VCPKG_ROOT")," folder paths to your needs if you are not using the recommended ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},(0,i.kt)("inlineCode",{parentName:"a"},"Folders structure")),"."),(0,i.kt)("p",null,"You can use the ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree"},"Partial guessing of the ",(0,i.kt)("inlineCode",{parentName:"a"},"TINYORM_BUILD_TREE"))," if you don't like to specify it manually. Just comment out the ",(0,i.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," and uncomment the ",(0,i.kt)("inlineCode",{parentName:"p"},"TINY_BUILD_TREE = $$shadowed($$PWD)")," in the ",(0,i.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file."),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can entirely avoid the ",(0,i.kt)("inlineCode",{parentName:"p"},".env")," files, just move the ",(0,i.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},".qmake.conf")," or remove it by help of ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree"},"Partial guessing of the ",(0,i.kt)("inlineCode",{parentName:"a"},"TINYORM_BUILD_TREE"))," and set the ",(0,i.kt)("inlineCode",{parentName:"p"},"VCPKG_ROOT")," environment variable at system level as is described in ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#set-up-vcpkg-environment"},(0,i.kt)("inlineCode",{parentName:"a"},"Set up vcpkg environment")),".")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Configuring by the ",(0,i.kt)("inlineCode",{parentName:"p"},".qmake.conf")," and ",(0,i.kt)("inlineCode",{parentName:"p"},".env")," files has one big advantage, which is that you don't have to modify the project files.")),(0,i.kt)("h4",{id:"migrations-source-files"},"Migrations source files"),(0,i.kt)("p",null,"Create ",(0,i.kt)("inlineCode",{parentName:"p"},"database/migrations.pri")," file and paste the following code."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='database/migrations.pri'",title:"'database/migrations.pri'"},"INCLUDEPATH *= $$PWD\n\nHEADERS += \\\n $$PWD/migrations/2014_10_12_000000_create_posts_table.hpp \\\n")),(0,i.kt)("h4",{id:"seeders-source-files"},"Seeders source files"),(0,i.kt)("p",null,"Create ",(0,i.kt)("inlineCode",{parentName:"p"},"database/seeders.pri")," file and paste the following code."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='database/seeders.pri'",title:"'database/seeders.pri'"},"INCLUDEPATH *= $$PWD\n\nHEADERS += \\\n $$PWD/seeders/databaseseeder.hpp \\\n")),(0,i.kt)("h3",{id:"build-migrations-qmake"},"Build migrations"),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"I recommend creating a new ",(0,i.kt)("inlineCode",{parentName:"p"},"Session")," in the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtCreator IDE")," as is described ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#open-qtcreator-ide"},"here"),".")),(0,i.kt)("p",null,"Now you can open the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom.pro")," project in the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtCreator IDE"),"."),(0,i.kt)("p",null,"This will open the ",(0,i.kt)("inlineCode",{parentName:"p"},"Configure Project")," tab, select some kit and update build folder paths to meet our ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},"folders structure")," or like you want."),(0,i.kt)("img",{src:n(6191).Z,alt:"tom - QtCreator - Configure Project",width:"760"}),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can force the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtCreator")," to generate a build folders structure as is described ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#qtcreator-default-build-directory"},"here"),".")),(0,i.kt)("p",null,"You are ready to configure build options, hit ",(0,i.kt)("kbd",null,"Ctrl"),"+",(0,i.kt)("kbd",null,"5")," to open ",(0,i.kt)("inlineCode",{parentName:"p"},"Project Settings")," tab and select ",(0,i.kt)("inlineCode",{parentName:"p"},"Build")," in the left sidebar to open the ",(0,i.kt)("inlineCode",{parentName:"p"},"Build Settings"),", it should look similar to the following picture."),(0,i.kt)("img",{src:n(5539).Z,className:"no-blurry",alt:"tom - QtCreator - Build Settings",width:"760"}),(0,i.kt)("p",null,"Disable ",(0,i.kt)("inlineCode",{parentName:"p"},"QML debugging and profiling")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"Qt Quick Compiler"),", they are not used."),(0,i.kt)("p",null,"In the left sidebar open ",(0,i.kt)("inlineCode",{parentName:"p"},"Dependencies")," and check ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," project and ",(0,i.kt)("inlineCode",{parentName:"p"},"Synchronize configuration"),", this setting ensures that the current project will be rebuilt correctly when the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," library source code changes."),(0,i.kt)("p",null,"Everything is ready to build, you can press ",(0,i.kt)("kbd",null,"Ctrl"),"+",(0,i.kt)("kbd",null,"b")," to build the project."),(0,i.kt)("h3",{id:"execute-migrations-qmake"},"Execute migrations"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"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,i.kt)("inlineCode",{parentName:"p"},"LD_LIBRARY_PATH")," on Linux."),(0,i.kt)("p",null,"The only thing you might want to change is to run the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application in the new terminal window. To do so, hit ",(0,i.kt)("kbd",null,"Ctrl"),"+",(0,i.kt)("kbd",null,"5")," to open the ",(0,i.kt)("inlineCode",{parentName:"p"},"Project Settings")," tab and select ",(0,i.kt)("inlineCode",{parentName:"p"},"Run")," in the left sidebar to open the ",(0,i.kt)("inlineCode",{parentName:"p"},"Run Settings"),", then in the ",(0,i.kt)("inlineCode",{parentName:"p"},"Run")," section select the ",(0,i.kt)("inlineCode",{parentName:"p"},"Run in terminal")," checkbox."),(0,i.kt)("p",null,"You can also set the ",(0,i.kt)("inlineCode",{parentName:"p"},"Command line arguments")," in this ",(0,i.kt)("inlineCode",{parentName:"p"},"Run")," section, eg. the ",(0,i.kt)("inlineCode",{parentName:"p"},"migrate:status"),"."),(0,i.kt)("p",null,"To execute the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," application press ",(0,i.kt)("kbd",null,"Ctrl")," + ",(0,i.kt)("kbd",null,"r"),"."),(0,i.kt)("p",null,"The output will look ",(0,i.kt)("strong",{parentName:"p"},"very similar")," to this if you add more migrations."),(0,i.kt)("img",{src:n(3086).Z,alt:"Tom migrations - migrate:status command output",width:"660"}),(0,i.kt)("p",null,"Happy migrating \ud83c\udf89\ud83d\udc4c"),(0,i.kt)("h2",{id:"finish"},"Finish"),(0,i.kt)("p",null,"As the last thing, you can check that all the file properties were correctly set by the ",(0,i.kt)("a",{parentName:"p",href:"https://docs.microsoft.com/en-us/windows/win32/menurc/resource-compiler"},(0,i.kt)("inlineCode",{parentName:"a"},"rc"))," compiler."),(0,i.kt)("p",null,"Find the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom.exe")," file and press ",(0,i.kt)("kbd",null,"Alt")," + ",(0,i.kt)("kbd",null,"Enter")," to open the file properties. To check the executable manifest you can use eg. the ",(0,i.kt)("a",{parentName:"p",href:"http://www.angusj.com/resourcehacker/"},"Resource Hacker"),"."),(0,i.kt)("img",{src:n(643).Z,alt:"tom.exe file properties detail",width:"440"}))}b.isMDXComponent=!0},5539:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/qmake-build_settings-e10927d1c4ed852620f9eb7564198940.png"},6191:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/qmake-configure_project-4721257090370204b0272d166512adef.png"},643:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/tom_file_properties-0df513c47ceadd5c09165e41c6b53086.png"},3086:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/tom_migrate_status-63c129a10bfe6bffe8d2d5ea280860e5.png"}}]); \ No newline at end of file diff --git a/assets/js/8a8faf8d.aa357c14.js b/assets/js/8a8faf8d.aa357c14.js new file mode 100644 index 000000000..739ef44ab --- /dev/null +++ b/assets/js/8a8faf8d.aa357c14.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[129],{5270:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>m,contentTitle:()=>h,default:()=>x,frontMatter:()=>c,metadata:()=>u,toc:()=>p});var s=i(4848),t=i(8453),a=i(2364),r=i(9365),l=i(1470),o=i(7324),d=i(6694);const c={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"]},h="Building: Migrations",u={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"}},m={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Install dependencies",id:"install-dependencies",level:2},{value:"Using vcpkg.json <small>(manifest mode)</small>",id:"using-vcpkg-json-manifest-mode",level:4},{value:"Using vcpkg install <small>(manually)</small>",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:"<code>Auto-configure</code> using <code>.qmake.conf</code> and <code>.env</code>",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 g(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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:`cd ${(0,d.OZ)(o.b)}\nmkdir tom/tom\ncd tom`})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.A,{className:"language-bash",children:`cd ${(0,d.OZ)(o.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 <silver.zachara@gmail.com>",\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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:`cd ${(0,d.OZ)(o.b)}/tom/tom`})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.A,{className:"language-bash",children:`cd ${(0,d.OZ)(o.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",{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 <orm/db.hpp>\n\n#include <tom/application.hpp>\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<DatabaseManager> 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<CreatePostsTable>()\n .seeders<DatabaseSeeder>()\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<DatabaseManager> 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",{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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:"mkdir database/migrations\n\nvim database/migrations/2014_10_12_000000_create_posts_table.hpp"})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.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 <tom/migration.hpp>\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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:"mkdir database/seeders\n\nvim database/seeders/databaseseeder.hpp"})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.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 <tom/seeder.hpp>\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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:"cd ..\nmkdir tom-builds-cmake/build-debug\n\ncd tom"})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.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 "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/database>"\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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:`cmake.exe \`\n-S "${(0,d.OZ)(o.b)}/tom/tom" \`\n-B "${(0,d.OZ)(o.b)}/tom/tom-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,d.Sn)(o.b)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,d.Sn)(o.b)}/tmp/tom"`})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.A,{className:"language-bash",children:`cmake \\\n-S "${(0,d.OZ)(o.xj)}/tom/tom" \\\n-B "${(0,d.OZ)(o.xj)}/tom/tom-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,d.Sn)(o.xj)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,d.Sn)(o.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)(l.A,{groupId:o.vf,name:"tinyorm-on-path",children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:`$env:Path = "${(0,d.OZ)(o.b,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,d.OZ)(o.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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.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)(r.A,{value:o.xj,label:o.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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.b,label:o.ux,children:(0,s.jsx)(a.A,{className:"language-powershell",children:`cd ${(0,d.OZ)(o.b)}/tom\n\nmkdir tom-builds-qmake`})}),(0,s.jsx)(r.A,{value:o.xj,label:o.gg,children:(0,s.jsx)(a.A,{className:"language-bash",children:`cd ${(0,d.OZ)(o.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)(l.A,{groupId:o.vf,children:[(0,s.jsx)(r.A,{value:o.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_0_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 *= tiny_ccache_win32\n"})})}),(0,s.jsx)(r.A,{value:o.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_0_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)(r.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_0_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 *= tiny_ccache_win32\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 x(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(g,{...e})}):g(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(9466);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 <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> 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 <Tabs>. 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 <Tabs> 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 <Tabs> component requires at least one <TabItem> children component");if(n){if(!m({value:n,tabValues:i}))throw new Error(`Docusaurus error: The <Tabs> 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/945.62d4a71f.js b/assets/js/913.3fa60236.js similarity index 55% rename from assets/js/945.62d4a71f.js rename to assets/js/913.3fa60236.js index a62c84341..69664f427 100644 --- a/assets/js/945.62d4a71f.js +++ b/assets/js/913.3fa60236.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[945],{6945:(r,e,s)=>{s.r(e)}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[913],{8913:(r,e,s)=>{s.r(e)}}]); \ No newline at end of file diff --git a/assets/js/935f2afb.68cd247f.js b/assets/js/935f2afb.68cd247f.js deleted file mode 100644 index 148e69612..000000000 --- a/assets/js/935f2afb.68cd247f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[53],{1109:e=>{e.exports=JSON.parse('{"pluginId":"default","version":"current","label":"Next","banner":null,"badge":false,"noIndex":false,"className":"docs-version-current","isLast":true,"docsSidebars":{"tinyormSidebar":[{"type":"link","label":"\ud83d\udd25 Prologue","href":"/","docId":"README"},{"type":"link","label":"\ud83d\udd27 Dependencies","href":"/dependencies","docId":"dependencies"},{"type":"link","label":"\ud83d\ude80 Supported Compilers","href":"/supported-compilers","docId":"supported-compilers"},{"type":"category","label":"\u2728 Database","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/database/getting-started","docId":"database/getting-started"},{"type":"link","label":"Query Builder","href":"/database/query-builder","docId":"database/query-builder"},{"type":"link","label":"Migrations","href":"/database/migrations","docId":"database/migrations"},{"type":"link","label":"Seeding","href":"/database/seeding","docId":"database/seeding"}]},{"type":"category","label":"\ud83c\udf89 TinyORM","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/tinyorm/getting-started","docId":"tinyorm/getting-started"},{"type":"link","label":"Relationships","href":"/tinyorm/relationships","docId":"tinyorm/relationships"},{"type":"link","label":"Collections","href":"/tinyorm/collections","docId":"tinyorm/collections"},{"type":"link","label":"Casts","href":"/tinyorm/casts","docId":"tinyorm/casts"},{"type":"link","label":"Serialization","href":"/tinyorm/serialization","docId":"tinyorm/serialization"}]},{"type":"category","label":"\ud83e\uddec TinyDrivers","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"Getting Started","href":"/tinydrivers/getting-started","docId":"tinydrivers/getting-started"}]},{"type":"category","label":"\ud83d\udea7 Building","collapsible":true,"collapsed":true,"items":[{"type":"link","label":"TinyORM","href":"/building/tinyorm","docId":"building/tinyorm"},{"type":"link","label":"Hello world","href":"/building/hello-world","docId":"building/hello-world"},{"type":"link","label":"Migrations","href":"/building/migrations","docId":"building/migrations"}]},{"type":"link","label":"\ud83d\udcc4 Features Summary","href":"/features-summary","docId":"features-summary"},{"type":"link","label":"\u2764\ufe0f Sponsors","href":"/sponsors","docId":"sponsors"}]},"docs":{"building/hello-world":{"id":"building/hello-world","title":"Building: Hello world","description":"Hello world example created in the terminal and QtCreator IDE.","sidebar":"tinyormSidebar"},"building/migrations":{"id":"building/migrations","title":"Building: Migrations","description":"How to compile the TinyORM migrations (tom) C++ console application on Windows and Linux.","sidebar":"tinyormSidebar"},"building/tinyorm":{"id":"building/tinyorm","title":"Building: TinyORM","description":"How to compile the TinyORM C++ library on Windows and Linux.","sidebar":"tinyormSidebar"},"database/getting-started":{"id":"database/getting-started","title":"Database: Getting Started","description":"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.","sidebar":"tinyormSidebar"},"database/migrations":{"id":"database/migrations","title":"Database: Migrations","description":"Migrations are like version control for your database, allowing your team to define and share the application\'s database schema definition. Migrations use the Schema facade that provides database agnostic support for creating and manipulating tables across all of TinyORM\'s supported database systems.","sidebar":"tinyormSidebar"},"database/query-builder":{"id":"database/query-builder","title":"Database: Query Builder","description":"TinyORM\'s database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.","sidebar":"tinyormSidebar"},"database/seeding":{"id":"database/seeding","title":"Database: Seeding","description":"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.","sidebar":"tinyormSidebar"},"dependencies":{"id":"dependencies","title":"Dependencies","description":"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.","sidebar":"tinyormSidebar"},"features-summary":{"id":"features-summary","title":"Features Summary","description":"List that fastly summarizes all TinyORM features.","sidebar":"tinyormSidebar"},"README":{"id":"README","title":"Prologue","description":"TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries. The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests.","sidebar":"tinyormSidebar"},"sponsors":{"id":"sponsors","title":"Sponsors","description":"How to sponsor and support the TinyORM project.","sidebar":"tinyormSidebar"},"supported-compilers":{"id":"supported-compilers","title":"Supported Compilers","description":"Platform requirements, supported compilers and build systems for TinyORM C++ library.","sidebar":"tinyormSidebar"},"tinydrivers/getting-started":{"id":"tinydrivers/getting-started","title":"TinyDrivers: Getting Started","description":"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.","sidebar":"tinyormSidebar"},"tinyorm/casts":{"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.","sidebar":"tinyormSidebar"},"tinyorm/collections":{"id":"tinyorm/collections","title":"TinyORM: Collections","description":"The ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. Is much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. All TinyORM methods that return more than one model result will return instances of the ModelsCollection class.","sidebar":"tinyormSidebar"},"tinyorm/getting-started":{"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.","sidebar":"tinyormSidebar"},"tinyorm/relationships":{"id":"tinyorm/relationships","title":"TinyORM: Relationships","description":"TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities.","sidebar":"tinyormSidebar"},"tinyorm/serialization":{"id":"tinyorm/serialization","title":"TinyORM: Serialization","description":"TinyORM models serialization allows you to serialize models and collection of models including all nested relations to JSON. It also supports converting to vectors or maps and allows controlling a custom date format during serialization.","sidebar":"tinyormSidebar"}}}')}}]); \ No newline at end of file diff --git a/assets/js/972.b9e804c8.js b/assets/js/972.b9e804c8.js deleted file mode 100644 index 358a6b670..000000000 --- a/assets/js/972.b9e804c8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[972],{4972:(e,t,n)=>{n.r(t),n.d(t,{default:()=>i});var a=n(7294),o=n(5999),l=n(833),r=n(7452);function i(){return a.createElement(a.Fragment,null,a.createElement(l.d,{title:(0,o.I)({id:"theme.NotFound.title",message:"Page Not Found"})}),a.createElement(r.Z,null,a.createElement("main",{className:"container margin-vert--xl"},a.createElement("div",{className:"row"},a.createElement("div",{className:"col col--6 col--offset-3"},a.createElement("h1",{className:"hero__title"},a.createElement(o.Z,{id:"theme.NotFound.title",description:"The title of the 404 page"},"Page Not Found")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page"},"We could not find what you were looking for.")),a.createElement("p",null,a.createElement(o.Z,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page"},"Please contact the owner of the site that linked you to the original URL and let them know their link is broken.")))))))}}}]); \ No newline at end of file diff --git a/assets/js/a4d3e054.2c177800.js b/assets/js/a4d3e054.2c177800.js deleted file mode 100644 index f47e578f1..000000000 --- a/assets/js/a4d3e054.2c177800.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[454],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var d=a.createContext({}),l=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(d.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,d=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),c=r,h=u["".concat(d,".").concat(c)]||u[c]||m[c]||i;return n?a.createElement(h,o(o({ref:t},p),{},{components:n})):a.createElement(h,o({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=c;var s={};for(var d in t)hasOwnProperty.call(t,d)&&(s[d]=t[d]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var l=2;l<i;l++)o[l]=n[l];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},8261:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:3,sidebar_label:"Seeding",description:"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.",keywords:["c++ orm","database","seeder","seeding","tinyorm"]},o="Database: Seeding",s={unversionedId:"database/seeding",id:"database/seeding",title:"Database: Seeding",description:"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.",source:"@site/docs/database/seeding.mdx",sourceDirName:"database",slug:"/database/seeding",permalink:"/database/seeding",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/database/seeding.mdx",tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,sidebar_label:"Seeding",description:"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.",keywords:["c++ orm","database","seeder","seeding","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Migrations",permalink:"/database/migrations"},next:{title:"Getting Started",permalink:"/tinyorm/getting-started"}},d={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Writing Seeders",id:"writing-seeders",level:2},{value:"Calling Additional Seeders",id:"calling-additional-seeders",level:3},{value:"Call with additional arguments",id:"call-with-additional-arguments",level:4},{value:"Running Seeders",id:"running-seeders",level:2},{value:"Forcing Seeders To Run In Production",id:"forcing-seeders-to-run-in-production",level:4}],p={toc:l},u="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"database-seeding"},"Database: Seeding"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#writing-seeders"},"Writing Seeders"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#calling-additional-seeders"},"Calling Additional Seeders")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#running-seeders"},"Running Seeders"))),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"TinyORM includes the ability to seed your database with data using seed classes. All seed classes should be stored in the ",(0,r.kt)("inlineCode",{parentName:"p"},"database/seeders")," directory. The ",(0,r.kt)("inlineCode",{parentName:"p"},"DatabaseSeeder")," class is considered as the root seeder. From this class, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"call")," method to run other seed classes, allowing you to control the seeding order."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("a",{parentName:"p",href:"/tinyorm/getting-started#mass-assignment"},"Mass assignment protection")," is automatically disabled during database seeding.")),(0,r.kt)("h2",{id:"writing-seeders"},"Writing Seeders"),(0,r.kt)("p",null,"To generate a seeder, execute the ",(0,r.kt)("inlineCode",{parentName:"p"},"make:seeder")," ",(0,r.kt)("inlineCode",{parentName:"p"},"tom")," command. A new seeder will be placed in the ",(0,r.kt)("inlineCode",{parentName:"p"},"database/seeders")," directory relative to the current ",(0,r.kt)("abbr",{title:"Current working directory"},"pwd"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"tom make:seeder UserSeeder\n")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"You can omit the ",(0,r.kt)("inlineCode",{parentName:"p"},"Seeder")," word in the class name, ",(0,r.kt)("inlineCode",{parentName:"p"},"tom")," appends it for you.")),(0,r.kt)("p",null,"A seeder class only contains one method by default: ",(0,r.kt)("inlineCode",{parentName:"p"},"run"),". This method is called when the ",(0,r.kt)("inlineCode",{parentName:"p"},"db:seed")," tom command is executed. Within the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method, you may insert data into your database however you wish. You may use the ",(0,r.kt)("a",{parentName:"p",href:"/database/query-builder#insert-statements"},"query builder")," to manually insert data."),(0,r.kt)("p",null,"As an example, let's modify the default ",(0,r.kt)("inlineCode",{parentName:"p"},"DatabaseSeeder")," class and add a database insert statement to the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#pragma once\n\n#include <tom/seeder.hpp>\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("users")->insert({"name", "email"},\n {\n {"1. user", "user1@example.com"},\n {"2. user", "user2@example.com"},\n });\n }\n };\n\n} // namespace Seeders\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The multi-insert ",(0,r.kt)("a",{parentName:"p",href:"/database/query-builder#multi-insert-overload"},(0,r.kt)("inlineCode",{parentName:"a"},"insert"))," method overload is ideal for seeding data.")),(0,r.kt)("h3",{id:"calling-additional-seeders"},"Calling Additional Seeders"),(0,r.kt)("p",null,"Within the ",(0,r.kt)("inlineCode",{parentName:"p"},"DatabaseSeeder")," class, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"call")," method to execute additional seed classes. Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"call")," method allows you to break up your database seeding into multiple files so that no single seeder class becomes too large. The ",(0,r.kt)("inlineCode",{parentName:"p"},"call")," method accepts the template parameter pack of seeder classes that should be executed:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"/*! Run the database seeders. */\nvoid run() override\n{\n call<UserSeeder, PostSeeder, CommentSeeder>();\n}\n")),(0,r.kt)("h4",{id:"call-with-additional-arguments"},"Call with additional arguments"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"call")," method allows to pass additional arguments to the seeder/s, but it has additional requirements."),(0,r.kt)("p",null,"If you define a ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method without parameters then this method is called using the virtual dispatch (polymorphism) and in this case, you should use the ",(0,r.kt)("inlineCode",{parentName:"p"},"override")," specifier."),(0,r.kt)("p",null,"If you define your ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method eg. like this ",(0,r.kt)("inlineCode",{parentName:"p"},"run(bool shouldSeed)")," or whatever parameters you want, then this method is called using the fold expression (virtual dispatch is not used in this case) so you can't use the ",(0,r.kt)("inlineCode",{parentName:"p"},"override")," specifier and you must call the ",(0,r.kt)("inlineCode",{parentName:"p"},"call<>()")," method with exactly the same arguments like the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method was defined with, in our example, it should look like this ",(0,r.kt)("inlineCode",{parentName:"p"},"call<ExampleSeeder>(true)"),"."),(0,r.kt)("p",null,"Let's demonstrate it on a small example, following is the ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method in the root ",(0,r.kt)("inlineCode",{parentName:"p"},"DatabaseSeeder")," class."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"/*! Run the database seeders. */\nvoid run() override\n{\n // This value can be based eg. on data from the database\n const auto shouldSeed = true;\n\n call<UserSeeder>(shouldSeed);\n}\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"run")," method in the ",(0,r.kt)("inlineCode",{parentName:"p"},"UserSeeder")," class."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'/*! Run the database seeders. */\nvoid run(const bool shouldSeed)\n{\n if (!shouldSeed)\n return;\n\n DB::table("users")->insert({\n {"name", "1. user"},\n });\n}\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"call")," method provides two shortcut methods, ",(0,r.kt)("inlineCode",{parentName:"p"},"callWith")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"callSilent")," (no output from seeders).")),(0,r.kt)("h2",{id:"running-seeders"},"Running Seeders"),(0,r.kt)("p",null,"You may execute the ",(0,r.kt)("inlineCode",{parentName:"p"},"db:seed")," tom command to seed your database. By default, the ",(0,r.kt)("inlineCode",{parentName:"p"},"db:seed")," command runs the ",(0,r.kt)("inlineCode",{parentName:"p"},"Seeders::DatabaseSeeder")," class, which may in turn invoke other seed classes. However, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"--class")," option to specify a specific seeder class to run individually:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"tom db:seed\n\ntom db:seed --class=UserSeeder\n")),(0,r.kt)("p",null,"You may also seed your database using the ",(0,r.kt)("inlineCode",{parentName:"p"},"migrate"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"migrate:fresh")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"migrate:refresh")," commands in combination with the ",(0,r.kt)("inlineCode",{parentName:"p"},"--seed")," option. For example the ",(0,r.kt)("inlineCode",{parentName:"p"},"migrate:fresh")," command drops all tables and re-run all of your migrations. This command is useful for completely re-building your database:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"tom migrate:fresh --seed\n")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"You can change the default seeders path as is described in the ",(0,r.kt)("a",{parentName:"p",href:"/building/tinyorm#TINYTOM_SEEDERS_DIR"},(0,r.kt)("inlineCode",{parentName:"a"},"C preprocessor macros")),", CMake provides the ",(0,r.kt)("a",{parentName:"p",href:"/building/tinyorm#TOM_SEEDERS_DIR"},(0,r.kt)("inlineCode",{parentName:"a"},"TOM_SEEDERS_DIR"))," option.")),(0,r.kt)("h4",{id:"forcing-seeders-to-run-in-production"},"Forcing Seeders To Run In Production"),(0,r.kt)("p",null,"Some seeding operations may cause you to alter or lose data. In order to protect you from running seeding commands against your production database, you will be prompted for confirmation before the seeders are executed in the ",(0,r.kt)("inlineCode",{parentName:"p"},"production")," environment. To force the seeders to run without a prompt, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"--force")," flag:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"tom db:seed --force\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a4d3e054.fedc061b.js b/assets/js/a4d3e054.fedc061b.js new file mode 100644 index 000000000..bd0f0eb6d --- /dev/null +++ b/assets/js/a4d3e054.fedc061b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[755],{7667:(e,s,n)=>{n.r(s),n.d(s,{assets:()=>o,contentTitle:()=>t,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>l});var d=n(4848),i=n(8453);const r={sidebar_position:3,sidebar_label:"Seeding",description:"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.",keywords:["c++ orm","database","seeder","seeding","tinyorm"]},t="Database: Seeding",a={id:"database/seeding",title:"Database: Seeding",description:"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.",source:"@site/docs/database/seeding.mdx",sourceDirName:"database",slug:"/database/seeding",permalink:"/database/seeding",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:3,frontMatter:{sidebar_position:3,sidebar_label:"Seeding",description:"TinyORM includes the ability to seed your database with data using seed classes. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the `call` method to run other seed classes, allowing you to control the seeding order.",keywords:["c++ orm","database","seeder","seeding","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Migrations",permalink:"/database/migrations"},next:{title:"Getting Started",permalink:"/tinyorm/getting-started"}},o={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Writing Seeders",id:"writing-seeders",level:2},{value:"Calling Additional Seeders",id:"calling-additional-seeders",level:3},{value:"Call with additional arguments",id:"call-with-additional-arguments",level:4},{value:"Running Seeders",id:"running-seeders",level:2},{value:"Forcing Seeders To Run In Production",id:"forcing-seeders-to-run-in-production",level:4}];function c(e){const s={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components};return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(s.h1,{id:"database-seeding",children:"Database: Seeding"}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,d.jsxs)(s.li,{children:[(0,d.jsx)(s.a,{href:"#writing-seeders",children:"Writing Seeders"}),"\n",(0,d.jsxs)(s.ul,{children:["\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"#calling-additional-seeders",children:"Calling Additional Seeders"})}),"\n"]}),"\n"]}),"\n",(0,d.jsx)(s.li,{children:(0,d.jsx)(s.a,{href:"#running-seeders",children:"Running Seeders"})}),"\n"]}),"\n",(0,d.jsx)(s.h2,{id:"introduction",children:"Introduction"}),"\n",(0,d.jsxs)(s.p,{children:["TinyORM includes the ability to seed your database with data using seed classes. All seed classes should be stored in the ",(0,d.jsx)(s.code,{children:"database/seeders"})," directory. The ",(0,d.jsx)(s.code,{children:"DatabaseSeeder"})," class is considered as the root seeder. From this class, you may use the ",(0,d.jsx)(s.code,{children:"call"})," method to run other seed classes, allowing you to control the seeding order."]}),"\n",(0,d.jsx)(s.admonition,{type:"tip",children:(0,d.jsxs)(s.p,{children:[(0,d.jsx)(s.a,{href:"/tinyorm/getting-started#mass-assignment",children:"Mass assignment protection"})," is automatically disabled during database seeding."]})}),"\n",(0,d.jsx)(s.h2,{id:"writing-seeders",children:"Writing Seeders"}),"\n",(0,d.jsxs)(s.p,{children:["To generate a seeder, execute the ",(0,d.jsx)(s.code,{children:"make:seeder"})," ",(0,d.jsx)(s.code,{children:"tom"})," command. A new seeder will be placed in the ",(0,d.jsx)(s.code,{children:"database/seeders"})," directory relative to the current ",(0,d.jsx)("abbr",{title:"Current working directory",children:"pwd"}),":"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-bash",children:"tom make:seeder UserSeeder\n"})}),"\n",(0,d.jsx)(s.admonition,{type:"tip",children:(0,d.jsxs)(s.p,{children:["You can omit the ",(0,d.jsx)(s.code,{children:"Seeder"})," word in the class name, ",(0,d.jsx)(s.code,{children:"tom"})," appends it for you."]})}),"\n",(0,d.jsxs)(s.p,{children:["A seeder class only contains one method by default: ",(0,d.jsx)(s.code,{children:"run"}),". This method is called when the ",(0,d.jsx)(s.code,{children:"db:seed"})," tom command is executed. Within the ",(0,d.jsx)(s.code,{children:"run"})," method, you may insert data into your database however you wish. You may use the ",(0,d.jsx)(s.a,{href:"/database/query-builder#insert-statements",children:"query builder"})," to manually insert data."]}),"\n",(0,d.jsxs)(s.p,{children:["As an example, let's modify the default ",(0,d.jsx)(s.code,{children:"DatabaseSeeder"})," class and add a database insert statement to the ",(0,d.jsx)(s.code,{children:"run"})," method:"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-cpp",children:'#pragma once\n\n#include <tom/seeder.hpp>\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("users")->insert({"name", "email"},\n {\n {"1. user", "user1@example.com"},\n {"2. user", "user2@example.com"},\n });\n }\n };\n\n} // namespace Seeders\n'})}),"\n",(0,d.jsx)(s.admonition,{type:"tip",children:(0,d.jsxs)(s.p,{children:["The multi-insert ",(0,d.jsx)(s.a,{href:"/database/query-builder#multi-insert-overload",children:(0,d.jsx)(s.code,{children:"insert"})})," method overload is ideal for seeding data."]})}),"\n",(0,d.jsx)(s.h3,{id:"calling-additional-seeders",children:"Calling Additional Seeders"}),"\n",(0,d.jsxs)(s.p,{children:["Within the ",(0,d.jsx)(s.code,{children:"DatabaseSeeder"})," class, you may use the ",(0,d.jsx)(s.code,{children:"call"})," method to execute additional seed classes. Using the ",(0,d.jsx)(s.code,{children:"call"})," method allows you to break up your database seeding into multiple files so that no single seeder class becomes too large. The ",(0,d.jsx)(s.code,{children:"call"})," method accepts the template parameter pack of seeder classes that should be executed:"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-cpp",children:"/*! Run the database seeders. */\nvoid run() override\n{\n call<UserSeeder, PostSeeder, CommentSeeder>();\n}\n"})}),"\n",(0,d.jsx)(s.h4,{id:"call-with-additional-arguments",children:"Call with additional arguments"}),"\n",(0,d.jsxs)(s.p,{children:["The ",(0,d.jsx)(s.code,{children:"call"})," method allows to pass additional arguments to the seeder/s, but it has additional requirements."]}),"\n",(0,d.jsxs)(s.p,{children:["If you define a ",(0,d.jsx)(s.code,{children:"run"})," method without parameters then this method is called using the virtual dispatch (polymorphism) and in this case, you should use the ",(0,d.jsx)(s.code,{children:"override"})," specifier."]}),"\n",(0,d.jsxs)(s.p,{children:["If you define your ",(0,d.jsx)(s.code,{children:"run"})," method eg. like this ",(0,d.jsx)(s.code,{children:"run(bool shouldSeed)"})," or whatever parameters you want, then this method is called using the fold expression (virtual dispatch is not used in this case) so you can't use the ",(0,d.jsx)(s.code,{children:"override"})," specifier and you must call the ",(0,d.jsx)(s.code,{children:"call<>()"})," method with exactly the same arguments like the ",(0,d.jsx)(s.code,{children:"run"})," method was defined with, in our example, it should look like this ",(0,d.jsx)(s.code,{children:"call<ExampleSeeder>(true)"}),"."]}),"\n",(0,d.jsxs)(s.p,{children:["Let's demonstrate it on a small example, following is the ",(0,d.jsx)(s.code,{children:"run"})," method in the root ",(0,d.jsx)(s.code,{children:"DatabaseSeeder"})," class."]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-cpp",children:"/*! Run the database seeders. */\nvoid run() override\n{\n // This value can be based eg. on data from the database\n const auto shouldSeed = true;\n\n call<UserSeeder>(shouldSeed);\n}\n"})}),"\n",(0,d.jsxs)(s.p,{children:["The ",(0,d.jsx)(s.code,{children:"run"})," method in the ",(0,d.jsx)(s.code,{children:"UserSeeder"})," class."]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-cpp",children:'/*! Run the database seeders. */\nvoid run(const bool shouldSeed)\n{\n if (!shouldSeed)\n return;\n\n DB::table("users")->insert({\n {"name", "1. user"},\n });\n}\n'})}),"\n",(0,d.jsx)(s.admonition,{type:"tip",children:(0,d.jsxs)(s.p,{children:["The ",(0,d.jsx)(s.code,{children:"call"})," method provides two shortcut methods, ",(0,d.jsx)(s.code,{children:"callWith"})," and ",(0,d.jsx)(s.code,{children:"callSilent"})," (no output from seeders)."]})}),"\n",(0,d.jsx)(s.h2,{id:"running-seeders",children:"Running Seeders"}),"\n",(0,d.jsxs)(s.p,{children:["You may execute the ",(0,d.jsx)(s.code,{children:"db:seed"})," tom command to seed your database. By default, the ",(0,d.jsx)(s.code,{children:"db:seed"})," command runs the ",(0,d.jsx)(s.code,{children:"Seeders::DatabaseSeeder"})," class, which may in turn invoke other seed classes. However, you may use the ",(0,d.jsx)(s.code,{children:"--class"})," option to specify a specific seeder class to run individually:"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-bash",children:"tom db:seed\n\ntom db:seed --class=UserSeeder\n"})}),"\n",(0,d.jsxs)(s.p,{children:["You may also seed your database using the ",(0,d.jsx)(s.code,{children:"migrate"}),", ",(0,d.jsx)(s.code,{children:"migrate:fresh"})," or ",(0,d.jsx)(s.code,{children:"migrate:refresh"})," commands in combination with the ",(0,d.jsx)(s.code,{children:"--seed"})," option. For example the ",(0,d.jsx)(s.code,{children:"migrate:fresh"})," command drops all tables and re-run all of your migrations. This command is useful for completely re-building your database:"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-bash",children:"tom migrate:fresh --seed\n"})}),"\n",(0,d.jsx)(s.admonition,{type:"tip",children:(0,d.jsxs)(s.p,{children:["You can change the default seeders path as is described in the ",(0,d.jsx)(s.a,{href:"/building/tinyorm#TINYTOM_SEEDERS_DIR",children:(0,d.jsx)(s.code,{children:"C preprocessor macros"})}),", CMake provides the ",(0,d.jsx)(s.a,{href:"/building/tinyorm#TOM_SEEDERS_DIR",children:(0,d.jsx)(s.code,{children:"TOM_SEEDERS_DIR"})})," option."]})}),"\n",(0,d.jsx)(s.h4,{id:"forcing-seeders-to-run-in-production",children:"Forcing Seeders To Run In Production"}),"\n",(0,d.jsxs)(s.p,{children:["Some seeding operations may cause you to alter or lose data. In order to protect you from running seeding commands against your production database, you will be prompted for confirmation before the seeders are executed in the ",(0,d.jsx)(s.code,{children:"production"})," environment. To force the seeders to run without a prompt, use the ",(0,d.jsx)(s.code,{children:"--force"})," flag:"]}),"\n",(0,d.jsx)(s.pre,{children:(0,d.jsx)(s.code,{className:"language-bash",children:"tom db:seed --force\n"})})]})}function h(e={}){const{wrapper:s}={...(0,i.R)(),...e.components};return s?(0,d.jsx)(s,{...e,children:(0,d.jsx)(c,{...e})}):c(e)}},8453:(e,s,n)=>{n.d(s,{R:()=>t,x:()=>a});var d=n(6540);const i={},r=d.createContext(i);function t(e){const s=d.useContext(r);return d.useMemo((function(){return"function"==typeof e?e(s):{...s,...e}}),[s,e])}function a(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:t(e.components),d.createElement(r.Provider,{value:s},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/a7bd4aaa.80cc43c0.js b/assets/js/a7bd4aaa.80cc43c0.js new file mode 100644 index 000000000..35df6a3ba --- /dev/null +++ b/assets/js/a7bd4aaa.80cc43c0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[98],{4532:(n,e,s)=>{s.r(e),s.d(e,{default:()=>x});s(6540);var r=s(9024),o=s(2967),t=s(2252),i=s(2831),c=s(1463),u=s(4848);function a(n){const{version:e}=n;return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(c.A,{version:e.version,tag:(0,o.tU)(e.pluginId,e.version)}),(0,u.jsx)(r.be,{children:e.noIndex&&(0,u.jsx)("meta",{name:"robots",content:"noindex, nofollow"})})]})}function l(n){const{version:e,route:s}=n;return(0,u.jsx)(r.e3,{className:e.className,children:(0,u.jsx)(t.n,{version:e,children:(0,i.v)(s.routes)})})}function x(n){return(0,u.jsxs)(u.Fragment,{children:[(0,u.jsx)(a,{...n}),(0,u.jsx)(l,{...n})]})}}}]); \ No newline at end of file diff --git a/assets/js/a94703ab.29c38115.js b/assets/js/a94703ab.29c38115.js new file mode 100644 index 000000000..d07a97180 --- /dev/null +++ b/assets/js/a94703ab.29c38115.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[48],{2559:(e,t,n)=>{n.r(t),n.d(t,{default:()=>be});var a=n(6540),o=n(4164),i=n(9024),s=n(7559),l=n(4142),r=n(6588),c=n(1312),d=n(3104),u=n(5062);const m={backToTopButton:"backToTopButton_sjWU",backToTopButtonShow:"backToTopButtonShow_xfvO"};var b=n(4848);function h(){const{shown:e,scrollToTop:t}=function(e){let{threshold:t}=e;const[n,o]=(0,a.useState)(!1),i=(0,a.useRef)(!1),{startScroll:s,cancelScroll:l}=(0,d.gk)();return(0,d.Mq)(((e,n)=>{let{scrollY:a}=e;const s=n?.scrollY;s&&(i.current?i.current=!1:a>=s?(l(),o(!1)):a<t?o(!1):a+window.innerHeight<document.documentElement.scrollHeight&&o(!0))})),(0,u.$)((e=>{e.location.hash&&(i.current=!0,o(!1))})),{shown:n,scrollToTop:()=>s(0)}}({threshold:300});return(0,b.jsx)("button",{"aria-label":(0,c.T)({id:"theme.BackToTopButton.buttonAriaLabel",message:"Scroll back to top",description:"The ARIA label for the back to top button"}),className:(0,o.A)("clean-btn",s.G.common.backToTopButton,m.backToTopButton,e&&m.backToTopButtonShow),type:"button",onClick:t})}var p=n(3109),x=n(6347),j=n(4581),f=n(6342),v=n(3465);function _(e){return(0,b.jsx)("svg",{width:"20",height:"20","aria-hidden":"true",...e,children:(0,b.jsxs)("g",{fill:"#7a7a7a",children:[(0,b.jsx)("path",{d:"M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"}),(0,b.jsx)("path",{d:"M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"})]})})}const g={collapseSidebarButton:"collapseSidebarButton_PEFL",collapseSidebarButtonIcon:"collapseSidebarButtonIcon_kv0_"};function A(e){let{onClick:t}=e;return(0,b.jsx)("button",{type:"button",title:(0,c.T)({id:"theme.docs.sidebar.collapseButtonTitle",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.collapseButtonAriaLabel",message:"Collapse sidebar",description:"The title attribute for collapse button of doc sidebar"}),className:(0,o.A)("button button--secondary button--outline",g.collapseSidebarButton),onClick:t,children:(0,b.jsx)(_,{className:g.collapseSidebarButtonIcon})})}var k=n(5041),C=n(9532);const S=Symbol("EmptyContext"),T=a.createContext(S);function N(e){let{children:t}=e;const[n,o]=(0,a.useState)(null),i=(0,a.useMemo)((()=>({expandedItem:n,setExpandedItem:o})),[n]);return(0,b.jsx)(T.Provider,{value:i,children:t})}var I=n(1422),B=n(9169),y=n(8774),w=n(2303);function L(e){let{collapsed:t,categoryLabel:n,onClick:a}=e;return(0,b.jsx)("button",{"aria-label":t?(0,c.T)({id:"theme.DocSidebarItem.expandCategoryAriaLabel",message:"Expand sidebar category '{label}'",description:"The ARIA label to expand the sidebar category"},{label:n}):(0,c.T)({id:"theme.DocSidebarItem.collapseCategoryAriaLabel",message:"Collapse sidebar category '{label}'",description:"The ARIA label to collapse the sidebar category"},{label:n}),"aria-expanded":!t,type:"button",className:"clean-btn menu__caret",onClick:a})}function E(e){let{item:t,onItemClick:n,activePath:i,level:r,index:c,...d}=e;const{items:u,label:m,collapsible:h,className:p,href:x}=t,{docs:{sidebar:{autoCollapseCategories:j}}}=(0,f.p)(),v=function(e){const t=(0,w.A)();return(0,a.useMemo)((()=>e.href&&!e.linkUnlisted?e.href:!t&&e.collapsible?(0,l.Nr)(e):void 0),[e,t])}(t),_=(0,l.w8)(t,i),g=(0,B.ys)(x,i),{collapsed:A,setCollapsed:k}=(0,I.u)({initialState:()=>!!h&&(!_&&t.collapsed)}),{expandedItem:N,setExpandedItem:E}=function(){const e=(0,a.useContext)(T);if(e===S)throw new C.dV("DocSidebarItemsExpandedStateProvider");return e}(),M=function(e){void 0===e&&(e=!A),E(e?null:c),k(e)};return function(e){let{isActive:t,collapsed:n,updateCollapsed:o}=e;const i=(0,C.ZC)(t);(0,a.useEffect)((()=>{t&&!i&&n&&o(!1)}),[t,i,n,o])}({isActive:_,collapsed:A,updateCollapsed:M}),(0,a.useEffect)((()=>{h&&null!=N&&N!==c&&j&&k(!0)}),[h,N,c,k,j]),(0,b.jsxs)("li",{className:(0,o.A)(s.G.docs.docSidebarItemCategory,s.G.docs.docSidebarItemCategoryLevel(r),"menu__list-item",{"menu__list-item--collapsed":A},p),children:[(0,b.jsxs)("div",{className:(0,o.A)("menu__list-item-collapsible",{"menu__list-item-collapsible--active":g}),children:[(0,b.jsx)(y.A,{className:(0,o.A)("menu__link",{"menu__link--sublist":h,"menu__link--sublist-caret":!x&&h,"menu__link--active":_}),onClick:h?e=>{n?.(t),x?M(!1):(e.preventDefault(),M())}:()=>{n?.(t)},"aria-current":g?"page":void 0,role:h&&!x?"button":void 0,"aria-expanded":h&&!x?!A:void 0,href:h?v??"#":v,...d,children:m}),x&&h&&(0,b.jsx)(L,{collapsed:A,categoryLabel:m,onClick:e=>{e.preventDefault(),M()}})]}),(0,b.jsx)(I.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:A,children:(0,b.jsx)(U,{items:u,tabIndex:A?-1:0,onItemClick:n,activePath:i,level:r+1})})]})}var M=n(6654),H=n(3186);const G={menuExternalLink:"menuExternalLink_NmtK"};function W(e){let{item:t,onItemClick:n,activePath:a,level:i,index:r,...c}=e;const{href:d,label:u,className:m,autoAddBaseUrl:h}=t,p=(0,l.w8)(t,a),x=(0,M.A)(d);return(0,b.jsx)("li",{className:(0,o.A)(s.G.docs.docSidebarItemLink,s.G.docs.docSidebarItemLinkLevel(i),"menu__list-item",m),children:(0,b.jsxs)(y.A,{className:(0,o.A)("menu__link",!x&&G.menuExternalLink,{"menu__link--active":p}),autoAddBaseUrl:h,"aria-current":p?"page":void 0,to:d,...x&&{onClick:n?()=>n(t):void 0},...c,children:[u,!x&&(0,b.jsx)(H.A,{})]})},u)}const P={menuHtmlItem:"menuHtmlItem_M9Kj"};function R(e){let{item:t,level:n,index:a}=e;const{value:i,defaultStyle:l,className:r}=t;return(0,b.jsx)("li",{className:(0,o.A)(s.G.docs.docSidebarItemLink,s.G.docs.docSidebarItemLinkLevel(n),l&&[P.menuHtmlItem,"menu__list-item"],r),dangerouslySetInnerHTML:{__html:i}},a)}function D(e){let{item:t,...n}=e;switch(t.type){case"category":return(0,b.jsx)(E,{item:t,...n});case"html":return(0,b.jsx)(R,{item:t,...n});default:return(0,b.jsx)(W,{item:t,...n})}}function F(e){let{items:t,...n}=e;const a=(0,l.Y)(t,n.activePath);return(0,b.jsx)(N,{children:a.map(((e,t)=>(0,b.jsx)(D,{item:e,index:t,...n},t)))})}const U=(0,a.memo)(F),V={menu:"menu_SIkG",menuWithAnnouncementBar:"menuWithAnnouncementBar_GW3s"};function Y(e){let{path:t,sidebar:n,className:i}=e;const l=function(){const{isActive:e}=(0,k.Mj)(),[t,n]=(0,a.useState)(e);return(0,d.Mq)((t=>{let{scrollY:a}=t;e&&n(0===a)}),[e]),e&&t}();return(0,b.jsx)("nav",{"aria-label":(0,c.T)({id:"theme.docs.sidebar.navAriaLabel",message:"Docs sidebar",description:"The ARIA label for the sidebar navigation"}),className:(0,o.A)("menu thin-scrollbar",V.menu,l&&V.menuWithAnnouncementBar,i),children:(0,b.jsx)("ul",{className:(0,o.A)(s.G.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(U,{items:n,activePath:t,level:1})})})}const K="sidebar_njMd",z="sidebarWithHideableNavbar_wUlq",q="sidebarHidden_VK0M",O="sidebarLogo_isFc";function J(e){let{path:t,sidebar:n,onCollapse:a,isHidden:i}=e;const{navbar:{hideOnScroll:s},docs:{sidebar:{hideable:l}}}=(0,f.p)();return(0,b.jsxs)("div",{className:(0,o.A)(K,s&&z,i&&q),children:[s&&(0,b.jsx)(v.A,{tabIndex:-1,className:O}),(0,b.jsx)(Y,{path:t,sidebar:n}),l&&(0,b.jsx)(A,{onClick:a})]})}const Q=a.memo(J);var X=n(5600),Z=n(2069);const $=e=>{let{sidebar:t,path:n}=e;const a=(0,Z.M)();return(0,b.jsx)("ul",{className:(0,o.A)(s.G.docs.docSidebarMenu,"menu__list"),children:(0,b.jsx)(U,{items:t,activePath:n,onItemClick:e=>{"category"===e.type&&e.href&&a.toggle(),"link"===e.type&&a.toggle()},level:1})})};function ee(e){return(0,b.jsx)(X.GX,{component:$,props:e})}const te=a.memo(ee);function ne(e){const t=(0,j.l)(),n="desktop"===t||"ssr"===t,a="mobile"===t;return(0,b.jsxs)(b.Fragment,{children:[n&&(0,b.jsx)(Q,{...e}),a&&(0,b.jsx)(te,{...e})]})}const ae={expandButton:"expandButton_TmdG",expandButtonIcon:"expandButtonIcon_i1dp"};function oe(e){let{toggleSidebar:t}=e;return(0,b.jsx)("div",{className:ae.expandButton,title:(0,c.T)({id:"theme.docs.sidebar.expandButtonTitle",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),"aria-label":(0,c.T)({id:"theme.docs.sidebar.expandButtonAriaLabel",message:"Expand sidebar",description:"The ARIA label and title attribute for expand button of doc sidebar"}),tabIndex:0,role:"button",onKeyDown:t,onClick:t,children:(0,b.jsx)(_,{className:ae.expandButtonIcon})})}const ie={docSidebarContainer:"docSidebarContainer_YfHR",docSidebarContainerHidden:"docSidebarContainerHidden_DPk8",sidebarViewport:"sidebarViewport_aRkj"};function se(e){let{children:t}=e;const n=(0,r.t)();return(0,b.jsx)(a.Fragment,{children:t},n?.name??"noSidebar")}function le(e){let{sidebar:t,hiddenSidebarContainer:n,setHiddenSidebarContainer:i}=e;const{pathname:l}=(0,x.zy)(),[r,c]=(0,a.useState)(!1),d=(0,a.useCallback)((()=>{r&&c(!1),!r&&(0,p.O)()&&c(!0),i((e=>!e))}),[i,r]);return(0,b.jsx)("aside",{className:(0,o.A)(s.G.docs.docSidebarContainer,ie.docSidebarContainer,n&&ie.docSidebarContainerHidden),onTransitionEnd:e=>{e.currentTarget.classList.contains(ie.docSidebarContainer)&&n&&c(!0)},children:(0,b.jsx)(se,{children:(0,b.jsxs)("div",{className:(0,o.A)(ie.sidebarViewport,r&&ie.sidebarViewportHidden),children:[(0,b.jsx)(ne,{sidebar:t,path:l,onCollapse:d,isHidden:r}),r&&(0,b.jsx)(oe,{toggleSidebar:d})]})})})}const re={docMainContainer:"docMainContainer_TBSr",docMainContainerEnhanced:"docMainContainerEnhanced_lQrH",docItemWrapperEnhanced:"docItemWrapperEnhanced_JWYK"};function ce(e){let{hiddenSidebarContainer:t,children:n}=e;const a=(0,r.t)();return(0,b.jsx)("main",{className:(0,o.A)(re.docMainContainer,(t||!a)&&re.docMainContainerEnhanced),children:(0,b.jsx)("div",{className:(0,o.A)("container padding-top--md padding-bottom--lg",re.docItemWrapper,t&&re.docItemWrapperEnhanced),children:n})})}const de={docRoot:"docRoot_UBD9",docsWrapper:"docsWrapper_hBAB"};function ue(e){let{children:t}=e;const n=(0,r.t)(),[o,i]=(0,a.useState)(!1);return(0,b.jsxs)("div",{className:de.docsWrapper,children:[(0,b.jsx)(h,{}),(0,b.jsxs)("div",{className:de.docRoot,children:[n&&(0,b.jsx)(le,{sidebar:n.items,hiddenSidebarContainer:o,setHiddenSidebarContainer:i}),(0,b.jsx)(ce,{hiddenSidebarContainer:o,children:t})]})]})}var me=n(3363);function be(e){const t=(0,l.B5)(e);if(!t)return(0,b.jsx)(me.A,{});const{docElement:n,sidebarName:a,sidebarItems:c}=t;return(0,b.jsx)(i.e3,{className:(0,o.A)(s.G.page.docsDocPage),children:(0,b.jsx)(r.V,{name:a,items:c,children:(0,b.jsx)(ue,{children:n})})})}},3363:(e,t,n)=>{n.d(t,{A:()=>l});n(6540);var a=n(4164),o=n(1312),i=n(1107),s=n(4848);function l(e){let{className:t}=e;return(0,s.jsx)("main",{className:(0,a.A)("container margin-vert--xl",t),children:(0,s.jsx)("div",{className:"row",children:(0,s.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,s.jsx)(i.A,{as:"h1",className:"hero__title",children:(0,s.jsx)(o.A,{id:"theme.NotFound.title",description:"The title of the 404 page",children:"Page Not Found"})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p1",description:"The first paragraph of the 404 page",children:"We could not find what you were looking for."})}),(0,s.jsx)("p",{children:(0,s.jsx)(o.A,{id:"theme.NotFound.p2",description:"The 2nd paragraph of the 404 page",children:"Please contact the owner of the site that linked you to the original URL and let them know their link is broken."})})]})})})}}}]); \ No newline at end of file diff --git a/assets/js/8156e19a.5e01ccd6.js b/assets/js/aba21aa0.cb1d9d7d.js similarity index 65% rename from assets/js/8156e19a.5e01ccd6.js rename to assets/js/aba21aa0.cb1d9d7d.js index 39ca73fc3..24f758b91 100644 --- a/assets/js/8156e19a.5e01ccd6.js +++ b/assets/js/aba21aa0.cb1d9d7d.js @@ -1 +1 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[683],{3769:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[742],{7093:e=>{e.exports=JSON.parse('{"name":"docusaurus-plugin-content-docs","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/ba3d4959.0b166b7a.js b/assets/js/ba3d4959.0b166b7a.js new file mode 100644 index 000000000..af699f7c2 --- /dev/null +++ b/assets/js/ba3d4959.0b166b7a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[170],{3418:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>Q,contentTitle:()=>v,default:()=>L,frontMatter:()=>y,metadata:()=>_,toc:()=>T});var i=t(4848),r=t(8453),a=t(9365),s=t(1470),o=t(6540);let l=null,c=null;function d(){const[e,n]=(0,o.useState)(!1),[t,r]=(0,o.useState)(!1);return(0,o.useEffect)((()=>(h(),()=>{h()})),[]),(0,i.jsxs)("form",{children:[(0,i.jsxs)("div",{className:"tinyorm-configuration-row",children:[(0,i.jsx)("label",{htmlFor:"tinyorm-toggle-full",children:"Full configuration"}),(0,i.jsx)("input",{id:"tinyorm-toggle-full",type:"checkbox",checked:e,onChange:()=>n(u),title:"Show full configuration example"})]}),(0,i.jsxs)("div",{className:"tinyorm-configuration-row",children:[(0,i.jsx)("label",{htmlFor:"tinyorm-toggle-prefix",children:"Prefix environment"}),(0,i.jsx)("input",{id:"tinyorm-toggle-prefix",type:"checkbox",checked:t,onChange:()=>r(j),title:"Prefix all environment variables by the database type"})]})]})}function h(){l=null,c=null}function u(e){const n=l||(l=document.getElementById("tinyorm-configuration")?.querySelectorAll(".tabs-container")),t=!e;if(!n)return e;if(2!==n.length)throw new Error(`Wrong number of .tabs-container (!== 2) found in the toggle configuration feature, found ${n.length}.`);return t?(n[0].style.display="none",n[1].style.display="block"):(n[0].style.display="block",n[1].style.display="none"),!e}const p='"DB_',m="MARIA",g="MYSQL",x="PGSQL",f="SQLITE",b=[g,x,f,m,g,x,f,m];function j(e){const n=function(){if(c)return c;const e=document.getElementById("tinyorm-configuration")?.querySelectorAll(".prism-code > code");if(!e)return e;if(8!==e.length)throw new Error(`Wrong number of .prism-code > code (!== 8) found in the prefix env. feature, found ${e.length}.`);return c=new Array(e.length),e.forEach(((e,n)=>{c[n]=Array.from(e.querySelectorAll(".token.string")).filter((e=>e?.textContent.startsWith(p)))})),c}(),t=!e;return n?(n.forEach(((e,n)=>{e.forEach((e=>{const i=e.textContent,r=`${p}${b[n]}_`;if(t)e.textContent=`${r}${i.substring(4)}`;else{if(!i.startsWith(r))throw new Error(`Token doesn't start with the '${r}' prefix.`);e.textContent=`${p}${i.substring(r.length)}`}}))})),!e):e}var S=t(7324);const y={sidebar_position:0,sidebar_label:"Getting Started",description:"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.",keywords:["c++ orm","database","getting started","tinyorm"]},v="Database: Getting Started",_={id:"database/getting-started",title:"Database: Getting Started",description:"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.",source:"@site/docs/database/getting-started.mdx",sourceDirName:"database",slug:"/database/getting-started",permalink:"/database/getting-started",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"Getting Started",description:"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.",keywords:["c++ orm","database","getting started","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\ude80 Supported Compilers",permalink:"/supported-compilers"},next:{title:"Query Builder",permalink:"/database/query-builder"}},Q={},T=[{value:"Introduction",id:"introduction",level:2},{value:"Configuration",id:"configuration",level:3},{value:"SQLite Configuration",id:"sqlite-configuration",level:4},{value:"SSL Connections",id:"ssl-connections",level:3},{value:"MySQL",id:"mysql",level:5},{value:"PostgreSQL",id:"postgresql",level:5},{value:"Running SQL Queries",id:"running-sql-queries",level:2},{value:"Running A Select Query",id:"running-a-select-query",level:4},{value:"Selecting Scalar Values",id:"selecting-scalar-values",level:4},{value:"Running An Insert Statement",id:"running-an-insert-statement",level:4},{value:"Running An Update Statement",id:"running-an-update-statement",level:4},{value:"Running A Delete Statement",id:"running-a-delete-statement",level:4},{value:"Running A General Statement",id:"running-a-general-statement",level:4},{value:"Running An Unprepared Statement",id:"running-an-unprepared-statement",level:4},{value:"Implicit Commits",id:"implicit-commits",level:4},{value:"Using Multiple Database Connections",id:"using-multiple-database-connections",level:3},{value:"Database Transactions",id:"database-transactions",level:2},{value:"Manually Using Transactions",id:"manually-using-transactions",level:4},{value:"Multi-threading support",id:"multi-threading-support",level:2}];function D(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"database-getting-started",children:"Database: Getting Started"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#introduction",children:"Introduction"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#configuration",children:"Configuration"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#ssl-connections",children:"SSL Connections"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#running-sql-queries",children:"Running SQL Queries"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#using-multiple-database-connections",children:"Using Multiple Database Connections"})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#database-transactions",children:"Database Transactions"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#multi-threading-support",children:"Multi-threading support"})}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(n.p,{children:["Almost every modern application interacts with a database. TinyORM makes interacting with a database extremely simple using raw SQL, a ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"fluent query builder"}),", and the ",(0,i.jsx)(n.a,{href:"/tinyorm/getting-started",children:"TinyORM"}),". Currently, TinyORM provides first-party support for four databases:"]}),"\n",(0,i.jsx)("div",{id:"databases-supported-versions",children:(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["MySQL ",(0,i.jsx)(n.code,{children:">=5.7"})," (",(0,i.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/MySQL#Release_history",children:"Version Policy"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["MariaDB ",(0,i.jsx)(n.code,{children:">=10.3"})," (",(0,i.jsx)(n.a,{href:"https://mariadb.org/about/#maintenance-policy",children:"Version Policy"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["PostgreSQL ",(0,i.jsx)(n.code,{children:">=11"})," (",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/support/versioning/",children:"Version Policy"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["SQLite ",(0,i.jsx)(n.code,{children:">=3.8.8"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["native rename column ",(0,i.jsx)(n.code,{children:">=3.25.0"})," (",(0,i.jsx)(n.a,{href:"https://www.sqlite.org/lang_altertable.html#alter_table_rename_column",children:"docs"})," , ",(0,i.jsx)(n.a,{href:"https://www.sqlite.org/releaselog/3_25_0.html",children:"release notes"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["native drop column ",(0,i.jsx)(n.code,{children:">=3.35.0"})," (",(0,i.jsx)(n.a,{href:"https://www.sqlite.org/lang_altertable.html#alter_table_drop_column",children:"docs"}),", ",(0,i.jsx)(n.a,{href:"https://www.sqlite.org/releaselog/3_35_0.html",children:"release notes"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:["generated columns ",(0,i.jsx)(n.code,{children:">=3.31.0"})," (",(0,i.jsx)(n.a,{href:"https://www.sqlite.org/gencol.html",children:"docs"}),", ",(0,i.jsx)(n.a,{href:"https://www.sqlite.org/releaselog/3_31_0.html",children:"release notes"}),")"]}),"\n"]}),"\n"]}),"\n"]})}),"\n",(0,i.jsxs)(n.p,{children:["TinyORM internally uses ",(0,i.jsx)(n.code,{children:"QtSql"})," module, you can look for ",(0,i.jsx)(n.a,{href:"https://doc.qt.io/qt/sql-driver.html#supported-databases",children:"supported databases"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsx)(n.p,{children:"TinyORM's code is ready and designed to simply add support for the SQL Server."})}),"\n",(0,i.jsx)(n.h3,{id:"configuration",children:"Configuration"}),"\n",(0,i.jsxs)(n.p,{children:["You can create and configure a new database connection using the ",(0,i.jsx)(n.code,{children:"create"})," method provided by the ",(0,i.jsx)(n.code,{children:"DB"})," facade:"]}),"\n",(0,i.jsxs)("div",{id:"tinyorm-configuration",children:[(0,i.jsx)(d,{}),(0,i.jsxs)(s.A,{className:"tinyorm-configuration-basic",groupId:S.OO,children:[(0,i.jsx)(a.A,{value:S.Dx,label:S.A3,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_PORT", "3306")},\n {"database", qEnvironmentVariable("DB_DATABASE", "")},\n {"username", qEnvironmentVariable("DB_USERNAME", "root")},\n {"password", qEnvironmentVariable("DB_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_CHARSET", "utf8mb4")},\n {"collation", qEnvironmentVariable("DB_COLLATION", "utf8mb4_0900_ai_ci")},\n {"timezone", "+00:00"},\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 {"prefix", ""},\n {"prefix_indexes", false},\n {"strict", true},\n {"engine", "InnoDB"},\n {"options", QVariantHash()},\n});\n'})})}),(0,i.jsx)(a.A,{value:S.os,label:S.LQ,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_PORT", "5432")},\n {"database", qEnvironmentVariable("DB_DATABASE", "")},\n {"search_path", qEnvironmentVariable("DB_SEARCHPATH", "public")},\n {"username", qEnvironmentVariable("DB_USERNAME", "postgres")},\n {"password", qEnvironmentVariable("DB_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_CHARSET", "utf8")},\n {"timezone", "UTC"},\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 {"prefix", ""},\n {"prefix_indexes", false},\n {"options", QVariantHash()},\n});\n'})})}),(0,i.jsx)(a.A,{value:S.F4,label:S.Q7,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("DB_DATABASE", "/example/example.sqlite3")},\n {"foreign_key_constraints", qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},\n {"check_database_exists", true},\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 /* Return a QDateTime/QDate with the correct time zone instead of the QString,\n only works when the qt_timezone isn\'t set to the DontConvert. */\n {"return_qdatetime", true},\n {"prefix", ""},\n {"prefix_indexes", false},\n});\n'})})}),(0,i.jsx)(a.A,{value:S.Fi,label:S.CW,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_PORT", "3306")},\n {"database", qEnvironmentVariable("DB_DATABASE", "")},\n {"username", qEnvironmentVariable("DB_USERNAME", "root")},\n {"password", qEnvironmentVariable("DB_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_CHARSET", "utf8mb4")},\n {"collation", qEnvironmentVariable("DB_COLLATION", "utf8mb4_unicode_520_ci")},\n {"timezone", "+00:00"},\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 {"prefix", ""},\n {"prefix_indexes", false},\n {"strict", true},\n {"engine", "InnoDB"},\n {"options", QVariantHash()},\n});\n'})})})]}),(0,i.jsxs)(s.A,{className:"tinyorm-configuration-full",groupId:S.OO,children:[(0,i.jsx)(a.A,{value:S.Dx,label:S.A3,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QMYSQL},\n {host_, qEnvironmentVariable("DB_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_PORT", P3306)},\n {database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},\n {username_, qEnvironmentVariable("DB_USERNAME", ROOT)},\n {password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_CHARSET", UTF8MB4)},\n {collation_, qEnvironmentVariable("DB_COLLATION", UTF8MB40900aici)},\n // SSL-related\n {ssl_ca, QStringLiteral("C:/mysql/data/ca.pem")},\n {ssl_cert, QStringLiteral("C:/mysql/data/client-cert.pem")},\n {ssl_key, QStringLiteral("C:/mysql/data/client-key.pem")},\n {ssl_mode, VerifyCA},\n // Or\n// {options, ConfigUtils::mysqlSslOptions()},\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 {prefix_, EMPTY},\n {prefix_indexes, false},\n {strict_, true},\n// {isolation_level, QStringLiteral("REPEATABLE READ")}, // MySQL default is REPEATABLE READ for InnoDB\n {engine_, InnoDB},\n {Version, {}}, // Autodetect\n {options_, QVariantHash()},\n // Examples\n// {options_, QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT = 1 ; MYSQL_OPT_READ_TIMEOUT=1")},\n// {options_, QVariantHash {{QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT"), 1},\n// {QStringLiteral("MYSQL_OPT_READ_TIMEOUT"), 1}}},\n});\n'})})}),(0,i.jsx)(a.A,{value:S.os,label:S.LQ,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QPSQL},\n {application_name, QStringLiteral("Example application")},\n {host_, qEnvironmentVariable("DB_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_PORT", P5432)},\n {database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},\n {search_path, qEnvironmentVariable("DB_SEARCHPATH", PUBLIC)},\n {username_, qEnvironmentVariable("DB_USERNAME", postgres_)},\n {password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_CHARSET", UTF8)},\n // SSL-related\n {sslmode_, QStringLiteral("verify-full")},\n {sslcert, QStringLiteral("C:/example/postgres.crt")},\n {sslkey, QStringLiteral("C:/example/postgres.key")},\n {sslrootcert, QStringLiteral("C:/example/root.crt")},\n // Or\n// {options_, ConfigUtils::postgresSslOptions()},\n {timezone_, UTC},\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 {prefix_, EMPTY},\n {prefix_indexes, false},\n// {isolation_level, QStringLiteral("REPEATABLE READ")}, // Postgres default is READ COMMITTED\n// {synchronous_commit, QStringLiteral("off")}, // Postgres default is on\n // ConnectionFactory provides a default value for this, this is only for reference\n// {dont_drop, QStringList {spatial_ref_sys}},\n {options_, QVariantHash()},\n});\n'})})}),(0,i.jsx)(a.A,{value:S.F4,label:S.Q7,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QSQLITE},\n {database_, qEnvironmentVariable("DB_DATABASE", "C:/SQLite/example.sqlite3")},\n {foreign_key_constraints, qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},\n {check_database_exists, true},\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 /* Return a QDateTime/QDate with the correct time zone instead of the QString,\n only works when the qt_timezone isn\'t set to the DontConvert. */\n {return_qdatetime, true},\n {prefix_, EMPTY},\n {prefix_indexes, false},\n});\n'})})}),(0,i.jsx)(a.A,{value:S.Fi,label:S.CW,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QMYSQL},\n {host_, qEnvironmentVariable("DB_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_PORT", P3306)},\n {database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},\n {username_, qEnvironmentVariable("DB_USERNAME", ROOT)},\n {password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_CHARSET", UTF8MB4)},\n {collation_, qEnvironmentVariable("DB_COLLATION", UTF8MB4Unicode520ci)},\n // SSL-related\n {ssl_ca, QStringLiteral("C:/maria/data/ca.pem")},\n {ssl_cert, QStringLiteral("C:/maria/data/client-cert.pem")},\n {ssl_key, QStringLiteral("C:/maria/data/client-key.pem")},\n // Or\n// {options, ConfigUtils::mariaSslOptions()},\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 {prefix_, EMPTY},\n {prefix_indexes, false},\n {strict_, true},\n// {isolation_level, QStringLiteral("REPEATABLE READ")}, // MariaDB default is REPEATABLE READ for InnoDB\n {engine_, InnoDB},\n {Version, {}}, // Autodetect\n {options_, QVariantHash()},\n // Examples\n// {options_, QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT = 1 ; MYSQL_OPT_READ_TIMEOUT=1")},\n// {options_, QVariantHash {{QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT"), 1},\n// {QStringLiteral("MYSQL_OPT_READ_TIMEOUT"), 1}}},\n});\n'})})})]})]}),"\n",(0,i.jsxs)(n.p,{children:["The first argument is configuration hash which is of type ",(0,i.jsx)(n.code,{children:"QVariantHash"})," and the second argument specifies the name of the ",(0,i.jsx)(n.em,{children:"connection"}),", this connection will also be a ",(0,i.jsx)(n.em,{children:"default connection"}),". You can configure multiple database connections at once and choose the needed one before executing SQL query, section ",(0,i.jsx)(n.a,{href:"#using-multiple-database-connections",children:"Using Multiple Database Connections"})," describes how to create and use multiple database connections."]}),"\n",(0,i.jsxs)(n.p,{children:["You may also configure connection options by ",(0,i.jsx)(n.code,{children:"options"})," key as ",(0,i.jsx)(n.code,{children:"QVariantHash"})," or ",(0,i.jsx)(n.code,{children:"QString"}),", you can pass any ",(0,i.jsx)(n.a,{href:"https://doc.qt.io/qt/qsqldatabase.html#setConnectOptions",children:"connection options"})," supported by ",(0,i.jsx)(n.code,{children:"QSqlDatabase"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["You can also configure ",(0,i.jsx)(n.a,{href:"https://dev.mysql.com/doc/refman/8.3/en/innodb-transaction-isolation-levels.html",children:"Transaction Isolation Levels"})," for MySQL connection with the ",(0,i.jsx)(n.code,{children:"isolation_level"})," configuration option."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"version"})," option is relevant only for the MySQL connections and you can save/avoid one database query (select version()) if you provide it manually. On the base of this version will be decided which ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/src/orm/connectors/mysqlconnector.cpp#L154",children:"session variables"})," will be set if strict mode is enabled and whether to use an ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/src/orm/query/grammars/mysqlgrammar.cpp#L36",children:"alias"})," during the ",(0,i.jsx)(n.code,{children:"upsert"})," method call."]}),"\n",(0,i.jsxs)(n.p,{children:["Breaking values are as follows; use an upsert alias on the MySQL >=8.0.19 and remove the ",(0,i.jsx)(n.code,{children:"NO_AUTO_CREATE_USER"})," sql mode on the MySQL >=8.0.11 if the strict mode is enabled."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["A database connection is resolved lazily, which means that the connection configuration is only saved after the ",(0,i.jsx)(n.code,{children:"DB::create"})," method call. The connection will be resolved after you run some query or you can create it using the ",(0,i.jsx)(n.code,{children:"DB::connection"})," method."]})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["You can also use predefined string constants to avoid unnecessary ",(0,i.jsx)(n.code,{children:"QString"})," instantiations, as used in the ",(0,i.jsx)(n.code,{children:"tom"})," migrations ",(0,i.jsx)(n.a,{href:"/building/migrations#string-constants-example",children:"example"}),"."]})}),"\n",(0,i.jsx)(n.h4,{id:"sqlite-configuration",children:"SQLite Configuration"}),"\n",(0,i.jsxs)(n.p,{children:["SQLite databases are contained within a single file on your filesystem. You can create a new SQLite database using the ",(0,i.jsx)(n.code,{children:"touch"})," command in your terminal: ",(0,i.jsx)(n.code,{children:"touch database.sqlite3"}),". After the database has been created, you may configure SQLite database connection:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("DB_DATABASE", "/absolute/path/to/database.sqlite3")},\n {"foreign_key_constraints", qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},\n {"check_database_exists", true},\n {"prefix", ""},\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"database"})," configuration value is the absolute path to the database. To enable foreign key constraints for SQLite connections, you should set the ",(0,i.jsx)(n.code,{children:"foreign_key_constraints"})," configuration value to ",(0,i.jsx)(n.code,{children:"true"}),", if this configuration value is not set, then the default of the SQLite driver will be used (currently the default is ",(0,i.jsx)(n.strong,{children:"disabled"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:["If the ",(0,i.jsx)(n.code,{children:"check_database_exists"})," configuration value is set to the ",(0,i.jsx)(n.code,{children:"true"})," value, then the database connection throws an ",(0,i.jsx)(n.code,{children:"Orm::InvalidArgumentError"})," exception, when the SQLite database file doesn't exist. If it is set to the ",(0,i.jsx)(n.code,{children:"false"})," value and the SQLite database file doesn't exist, then it will be created for you by SQLite driver. The default value is ",(0,i.jsx)(n.code,{children:"true"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"ssl-connections",children:"SSL Connections"}),"\n",(0,i.jsxs)(n.p,{children:["SSL connections are supported for the ",(0,i.jsx)(n.code,{children:"MySQL"})," and ",(0,i.jsx)(n.code,{children:"PostgreSQL"})," databases. They can be set using the ",(0,i.jsx)(n.code,{children:"options"})," configuration option."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["This feature is heavily dependent on the underlying ",(0,i.jsx)(n.code,{children:"QSqlDatabase"})," module. What means that you can pass the same ",(0,i.jsx)(n.a,{href:"https://doc.qt.io/qt/qsqldatabase.html#setConnectOptions",children:"connection options"})," to the ",(0,i.jsx)(n.code,{children:"TinyORM"})," that the ",(0,i.jsx)(n.code,{children:"QSqlDatabase"})," accepts."]})}),"\n",(0,i.jsx)(n.h5,{id:"mysql",children:"MySQL"}),"\n",(0,i.jsxs)(n.p,{children:["You have to pass the ",(0,i.jsx)(n.code,{children:"SSL_CA"}),", ",(0,i.jsx)(n.code,{children:"SSL_CERT"}),", ",(0,i.jsx)(n.code,{children:"SSL_KEY"}),", and ",(0,i.jsx)(n.code,{children:"MYSQL_OPT_SSL_MODE"})," options."]}),"\n",(0,i.jsxs)(s.A,{groupId:S.vf,children:[(0,i.jsx)(a.A,{value:S.b,label:S.ux,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"options", QVariantHash({{"SSL_CA", "C:/mysql/data/ca.pem"},\n {"SSL_CERT", "C:/mysql/data/client-cert.pem"},\n {"SSL_KEY", "C:/mysql/data/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"}})},\n // highlight-end\n});\n'})})}),(0,i.jsx)(a.A,{value:S.xj,label:S.gg,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"options", QVariantHash({{"SSL_CA", "~/.local/share/TinyORM/ssl/ca.pem"},\n {"SSL_CERT", "~/.local/share/TinyORM/ssl/client-cert.pem"},\n {"SSL_KEY", "~/.local/share/TinyORM/ssl/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"}})},\n // highlight-end\n});\n'})})})]}),"\n",(0,i.jsxs)(n.p,{children:["You may also use the ",(0,i.jsx)(n.code,{children:"ConfigUtils::mysqlSslOptions()"})," or the ",(0,i.jsx)(n.code,{children:"ConfigUtils::insertMySqlSslOptions()"})," methods to insert these options for you and define them using the ",(0,i.jsx)(n.code,{children:"DB_MYSQL_SSL_CA"}),", ",(0,i.jsx)(n.code,{children:"DB_MYSQL_SSL_CERT"}),", ",(0,i.jsx)(n.code,{children:"DB_MYSQL_SSL_KEY"}),", and ",(0,i.jsx)(n.code,{children:"DB_MYSQL_SSL_MODE"})," environment variables."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", ConfigUtils::mysqlSslOptions()},\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["You can define these SSL-related options in the top-level configuration, they will be copied to the ",(0,i.jsx)(n.code,{children:"options"})," option hash during configuration parsing. The top-level configuration takes precedence and overwrites the options in the ",(0,i.jsx)(n.code,{children:"options"})," hash."]}),"\n",(0,i.jsxs)(s.A,{groupId:S.vf,children:[(0,i.jsx)(a.A,{value:S.b,label:S.ux,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"SSL_CA", "C:/mysql/data/ca.pem"},\n {"SSL_CERT", "C:/mysql/data/client-cert.pem"},\n {"SSL_KEY", "C:/mysql/data/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"},\n // highlight-end\n});\n'})})}),(0,i.jsx)(a.A,{value:S.xj,label:S.gg,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"SSL_CA", "~/.local/share/TinyORM/ssl/ca.pem"},\n {"SSL_CERT", "~/.local/share/TinyORM/ssl/client-cert.pem"},\n {"SSL_KEY", "~/.local/share/TinyORM/ssl/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"},\n // highlight-end\n});\n'})})})]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["You can take a look at the GitHub actions how the ",(0,i.jsx)(n.code,{children:"MySQL"})," certificates are generated in the CI pipeline for ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/msvc2022-qt6.yml",children:"Windows"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/linux-qt6.yml",children:"Linux"}),"."]})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["You can also pass the ",(0,i.jsx)(n.code,{children:"QString"})," to the ",(0,i.jsx)(n.code,{children:"options"})," configuration separated by the ",(0,i.jsx)(n.code,{children:";"})," semicolon character and use the ",(0,i.jsx)(n.code,{children:"="})," to assign values."]})}),"\n",(0,i.jsx)(n.h5,{id:"postgresql",children:"PostgreSQL"}),"\n",(0,i.jsxs)(n.p,{children:["You have to pass the ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS",children:(0,i.jsx)(n.code,{children:"sslmode"})})," or the deprecated ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-REQUIRESSL",children:(0,i.jsx)(n.code,{children:"requiressl"})})," options."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", QVariantHash({{"sslmode", "verify-full"}})},\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["And place your ",(0,i.jsx)(n.strong,{children:"client"})," certificates to the ",(0,i.jsx)(n.code,{children:"~/.postgres/"})," on ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-FILE-USAGE",children:"Linux"})," and ",(0,i.jsx)(n.code,{children:"$env:APPDATA/postgres/"})," on Windows. Everything is described in the PostgreSQL's ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-ssl.html",children:"libpq client"})," and ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/15/ssl-tcp.html#SSL-FILE-USAGE",children:"server"})," documentation."]}),"\n",(0,i.jsxs)(n.p,{children:["If you want to keep your ",(0,i.jsx)(n.strong,{children:"client"})," certificates in your own location, you can set the ",(0,i.jsx)(n.code,{children:"sslcert"}),", ",(0,i.jsx)(n.code,{children:"sslkey"}),", and ",(0,i.jsx)(n.code,{children:"sslrootcert"})," options."]}),"\n",(0,i.jsxs)(s.A,{groupId:S.vf,children:[(0,i.jsx)(a.A,{value:S.b,label:S.ux,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", QVariantHash({{"sslmode", "verify-full"},\n // highlight-start\n {"sslcert", "C:/example/postgres.crt"},\n {"sslkey", "C:/example/postgres.key"},\n {"sslrootcert", "C:/example/root.crt"}})},\n // highlight-end\n});\n'})})}),(0,i.jsx)(a.A,{value:S.xj,label:S.gg,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", QVariantHash({{"sslmode", "verify-full"},\n // highlight-start\n {"sslcert", "/example/postgres.crt"},\n {"sslkey", "/example/postgres.key"},\n {"sslrootcert", "/example/root.crt"}})},\n // highlight-end\n});\n'})})})]}),"\n",(0,i.jsxs)(n.p,{children:["You can define these SSL-related options in the top-level configuration, they will be copied to the ",(0,i.jsx)(n.code,{children:"options"})," option hash during a configuration parsing. The top-level configuration takes precedence and overwrites the options in the ",(0,i.jsx)(n.code,{children:"options"})," hash."]}),"\n",(0,i.jsxs)(s.A,{groupId:S.vf,children:[(0,i.jsx)(a.A,{value:S.b,label:S.ux,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"sslmode", "verify-full"},\n {"sslcert", "C:/example/postgres.crt"},\n {"sslkey", "C:/example/postgres.key"},\n {"sslrootcert", "C:/example/root.crt"},\n // highlight-end\n});\n'})})}),(0,i.jsx)(a.A,{value:S.xj,label:S.gg,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"sslmode", "verify-full"},\n {"sslcert", "/example/postgres.crt"},\n {"sslkey", "/example/postgres.key"},\n {"sslrootcert", "/example/root.crt"},\n // highlight-end\n});\n'})})})]}),"\n",(0,i.jsxs)(n.p,{children:["You may also use the ",(0,i.jsx)(n.code,{children:"ConfigUtils::postgresSslOptions()"})," or the ",(0,i.jsx)(n.code,{children:"ConfigUtils::insertPostgresSslOptions()"})," methods to insert the ",(0,i.jsx)(n.code,{children:"sslmode"}),", ",(0,i.jsx)(n.code,{children:"sslcert"}),", ",(0,i.jsx)(n.code,{children:"sslkey"}),", and ",(0,i.jsx)(n.code,{children:"sslrootcert"})," options for you and define them using the ",(0,i.jsx)(n.code,{children:"DB_PGSQL_SSLMODE"}),", ",(0,i.jsx)(n.code,{children:"DB_PGSQL_SSLCERT"}),", ",(0,i.jsx)(n.code,{children:"DB_PGSQL_SSLKEY"}),", and ",(0,i.jsx)(n.code,{children:"DB_PGSQL_SSLROOTCERT"})," environment variable."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", ConfigUtils::postgresSslOptions()},\n});\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["The PostgreSQL's libpq client library provides the ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.13.1.1",children:(0,i.jsx)(n.code,{children:"PGSSLMODE"})}),", ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.16.1.1",children:(0,i.jsx)(n.code,{children:"PGSSLCERT"})}),", ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.17.1.1",children:(0,i.jsx)(n.code,{children:"PGSSLKEY"})}),", and ",(0,i.jsx)(n.a,{href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.18.1.1",children:(0,i.jsx)(n.code,{children:"PGSSLROOTCERT"})})," environment variables, so you don't have to use TinyORM's ",(0,i.jsx)(n.code,{children:"options"})," configuration and may use these environment variables instead."]})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["You can take a look at the GitHub actions how the ",(0,i.jsx)(n.code,{children:"PostgreSQL"})," certificates are generated in the CI pipeline for ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/msvc2022-qt6.yml",children:"Windows"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/linux-qt6.yml",children:"Linux"}),"."]})}),"\n",(0,i.jsx)(n.h2,{id:"running-sql-queries",children:"Running SQL Queries"}),"\n",(0,i.jsxs)(n.p,{children:["Once you have configured your database connection, you may run queries using the ",(0,i.jsx)(n.code,{children:"DB"})," facade. The ",(0,i.jsx)(n.code,{children:"DB"})," facade provides methods for each type of query: ",(0,i.jsx)(n.code,{children:"select"}),", ",(0,i.jsx)(n.code,{children:"update"}),", ",(0,i.jsx)(n.code,{children:"insert"}),", ",(0,i.jsx)(n.code,{children:"delete"}),", and ",(0,i.jsx)(n.code,{children:"statement"}),"."]}),"\n",(0,i.jsx)(n.h4,{id:"running-a-select-query",children:"Running A Select Query"}),"\n",(0,i.jsxs)(n.p,{children:["To run a basic SELECT query, you may use the ",(0,i.jsx)(n.code,{children:"select"})," method on the ",(0,i.jsx)(n.code,{children:"DB"})," facade:"]}),"\n",(0,i.jsxs)(n.p,{children:['auto users = DB::select("select * from users where active = ?", ',1,");"]}),"\n",(0,i.jsxs)(n.p,{children:["The first argument passed to the ",(0,i.jsx)(n.code,{children:"select"})," method is the SQL query, while the second argument is any parameter bindings that need to be bound to the query. Typically, these are the values of the ",(0,i.jsx)(n.code,{children:"where"})," clause constraints. Parameter binding provides protection against SQL injection."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"select"})," method returns a ",(0,i.jsx)(n.code,{children:"QSqlQuery"})," containing the results of the query, where each result can be accessed by ",(0,i.jsx)(n.code,{children:"QSqlQuery::next"})," method. Look into the ",(0,i.jsx)(n.code,{children:"QSqlQuery"}),' documentation on how to obtain results from the "query". You may access each column\'s value by ',(0,i.jsx)(n.code,{children:"QSqlQuery::value"})," method. The first ",(0,i.jsx)(n.code,{children:"bool"})," return value is the value returned from ",(0,i.jsx)(n.code,{children:"QSqlQuery::exec"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include <orm/db.hpp>\n\nauto users = DB::select("select * from users");\n\nwhile(users.next())\n qDebug() << users.value("name").toString();\n'})}),"\n",(0,i.jsx)(n.h4,{id:"selecting-scalar-values",children:"Selecting Scalar Values"}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes your database query may result in a single, scalar value. Instead of being required to retrieve the query's scalar result from a record instance, TinyORM allows you to retrieve this value directly using the ",(0,i.jsx)(n.code,{children:"scalar"})," shortcut method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nauto states = DB::scalar(\n "select count(case when state = \'pending\' then 1 end) as states "\n "from comments"\n);\n\n// With binding\nauto states = DB::scalar(\n "select count(case when state = ? then 1 end) as states from comments",\n {"pending"}\n);\n'})}),"\n",(0,i.jsx)(n.h4,{id:"running-an-insert-statement",children:"Running An Insert Statement"}),"\n",(0,i.jsxs)(n.p,{children:["To execute an ",(0,i.jsx)(n.code,{children:"insert"})," statement, you may use the ",(0,i.jsx)(n.code,{children:"insert"})," method on the ",(0,i.jsx)(n.code,{children:"DB"})," facade. Like ",(0,i.jsx)(n.code,{children:"select"}),", this method accepts the SQL query as its first argument and bindings as its second argument and returns ",(0,i.jsx)(n.code,{children:"QSqlQuery"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nDB::insert("insert into users (id, name) values (?, ?)", {1, "Marc"});\n'})}),"\n",(0,i.jsx)(n.h4,{id:"running-an-update-statement",children:"Running An Update Statement"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"update"})," method should be used to update existing records in the database. The number of rows affected by the statement and ",(0,i.jsx)(n.code,{children:"QSqlQuery"})," is returned by the method as ",(0,i.jsx)(n.code,{children:"std::tuple<int, QSqlQuery>"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <QDateTime>\n\n#include <orm/db.hpp>\n\nauto [affected, query] = DB::update(\n "update users set updated_at = ? where name = ?",\n {QDateTime::currentDateTimeUtc(), "Anita"}\n);\n\nif (!affected)\n qDebug() << "Any record was updated.";\n'})}),"\n",(0,i.jsx)(n.h4,{id:"running-a-delete-statement",children:"Running A Delete Statement"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"remove"})," method should be used to delete records from the database. Like ",(0,i.jsx)(n.code,{children:"update"}),", the number of affected rows and ",(0,i.jsx)(n.code,{children:"QSqlQuery"})," will be returned by the method as ",(0,i.jsx)(n.code,{children:"std::tuple<int, QSqlQuery>"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nauto [affected, query] = DB::remove("delete from users");\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"delete"})," can not be used as the method name because it is the reserved word."]})}),"\n",(0,i.jsx)(n.h4,{id:"running-a-general-statement",children:"Running A General Statement"}),"\n",(0,i.jsxs)(n.p,{children:["Some database statements do not return any value. For these types of operations, you may use the ",(0,i.jsx)(n.code,{children:"statement"})," method on the ",(0,i.jsx)(n.code,{children:"DB"})," facade:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'DB::statement("drop table users");\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"DB::statement"})," method should be used for ",(0,i.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Data_definition_language",children:"DDL"}),' queries, don\'t use it for "select" queries because it internally calls ',(0,i.jsx)(n.code,{children:"recordsHaveBeenModified"})," method."]})}),"\n",(0,i.jsx)(n.h4,{id:"running-an-unprepared-statement",children:"Running An Unprepared Statement"}),"\n",(0,i.jsxs)(n.p,{children:["Sometimes you may want to execute an SQL statement without binding any values. You may use the ",(0,i.jsx)(n.code,{children:"DB"})," facade's ",(0,i.jsx)(n.code,{children:"unprepared"})," method to accomplish this:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"DB::unprepared(\"update users set votes = 100 where name = 'Dries'\");\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsx)(n.p,{children:"Since unprepared statements do not bind parameters, they may be vulnerable to SQL injection. You should never allow user controlled values within an unprepared statement."})}),"\n",(0,i.jsx)(n.h4,{id:"implicit-commits",children:"Implicit Commits"}),"\n",(0,i.jsxs)(n.p,{children:["When using the ",(0,i.jsx)(n.code,{children:"DB"})," facade's ",(0,i.jsx)(n.code,{children:"statement"})," methods within transactions, you must be careful to avoid statements that cause ",(0,i.jsx)(n.a,{href:"https://dev.mysql.com/doc/refman/8.3/en/implicit-commit.html",children:"implicit commits"}),". These statements will cause the database engine to indirectly commit the entire transaction, leaving TinyORM unaware of the database's transaction level. An example of such a statement is creating a database table:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'DB::statement("create table users (name varchar(255) null)");\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Please refer to the MySQL manual for ",(0,i.jsx)(n.a,{href:"https://dev.mysql.com/doc/refman/8.3/en/implicit-commit.html",children:"a list of all statements"})," that trigger implicit commits."]}),"\n",(0,i.jsx)(n.h3,{id:"using-multiple-database-connections",children:"Using Multiple Database Connections"}),"\n",(0,i.jsxs)(n.p,{children:["You can configure multiple database connections at once during ",(0,i.jsx)(n.code,{children:"DatabaseManager"})," instantiation using the ",(0,i.jsx)(n.code,{children:"DB::create"})," overload, where the first argument is a hash of multiple connections and is of type ",(0,i.jsx)(n.code,{children:"QHash<QString, QVariantHash>"})," and the second argument is the name of the default connection:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"mysql", {\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_MYSQL_PORT", "3306")},\n {"database", qEnvironmentVariable("DB_MYSQL_DATABASE", "")},\n {"username", qEnvironmentVariable("DB_MYSQL_USERNAME", "root")},\n {"password", qEnvironmentVariable("DB_MYSQL_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_MYSQL_CHARSET", "utf8mb4")},\n {"collation", qEnvironmentVariable("DB_MYSQL_COLLATION", "utf8mb4_0900_ai_ci")},\n {"strict", true},\n {"options", QVariantHash()},\n }},\n {"sqlite", {\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("DB_SQLITE_DATABASE", "")},\n {"foreign_key_constraints", qEnvironmentVariable("DB_SQLITE_FOREIGN_KEYS", "true")},\n {"check_database_exists", true},\n {"prefix", ""},\n }},\n}, "mysql");\n'})}),"\n",(0,i.jsxs)(n.p,{children:["If your application needs to use multiple connections, you may access each connection via the ",(0,i.jsx)(n.code,{children:"connection"})," method provided by the ",(0,i.jsx)(n.code,{children:"DB"})," facade. The connection name passed to the ",(0,i.jsx)(n.code,{children:"connection"})," method should correspond to one of the connections key listed in your configuration:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nauto query = DB::connection("mysql_test").select(...);\n'})}),"\n",(0,i.jsxs)(n.p,{children:["You may access the raw underlying ",(0,i.jsx)(n.code,{children:"QSqlQuery"})," instance of a connection using the ",(0,i.jsx)(n.code,{children:"getQtQuery"})," method on a connection instance:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"auto query = DB::connection().getQtQuery();\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Or you can use the shortcut method ",(0,i.jsx)(n.code,{children:"qtQuery"})," provided by the ",(0,i.jsx)(n.code,{children:"DB"})," facade:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"auto query = DB::qtQuery();\n"})}),"\n",(0,i.jsx)(n.h2,{id:"database-transactions",children:"Database Transactions"}),"\n",(0,i.jsx)(n.h4,{id:"manually-using-transactions",children:"Manually Using Transactions"}),"\n",(0,i.jsxs)(n.p,{children:["If you would like to begin a transaction manually and have complete control over rollbacks and commits, you may use the ",(0,i.jsx)(n.code,{children:"beginTransaction"})," method provided by the ",(0,i.jsx)(n.code,{children:"DB"})," facade:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"#include <orm/db.hpp>\n\nDB::beginTransaction();\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You can rollback the transaction via the ",(0,i.jsx)(n.code,{children:"rollBack"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"DB::rollBack();\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Lastly, you can commit a transaction via the ",(0,i.jsx)(n.code,{children:"commit"})," method:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:"DB::commit();\n"})}),"\n",(0,i.jsx)(n.p,{children:"All transaction methods accept a connection name as the optional argument:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",children:'DB::beginTransaction("mysql_test");\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"DB"})," facade's transaction methods control the transactions for both the ",(0,i.jsx)(n.a,{href:"/database/query-builder",children:"query builder"})," and ",(0,i.jsx)(n.a,{href:"/tinyorm/getting-started",children:"TinyORM"}),"."]})}),"\n",(0,i.jsx)(n.h2,{id:"multi-threading-support",children:"Multi-threading support"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"TinyORM"})," supports multi-threading for the ",(0,i.jsx)(n.code,{children:"MSVC"})," and ",(0,i.jsx)(n.code,{children:"GCC"})," on Linux compilers. Multi-threading is disabled for the ",(0,i.jsx)(n.code,{children:"Clang <14.0.3"})," compiler on MSYS2, ",(0,i.jsx)(n.code,{children:"Clang <14.0.4"})," on Linux and for the ",(0,i.jsx)(n.code,{children:"GCC"})," compiler on MSYS2. The reason are bugs in the ",(0,i.jsx)(n.code,{children:"TLS"})," wrapper that is generated by the ",(0,i.jsx)(n.a,{href:"https://en.cppreference.com/w/cpp/keyword/thread_local",children:(0,i.jsx)(n.code,{children:"thread_local"})})," keyword."]}),"\n",(0,i.jsx)(n.p,{children:"A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread where the connection was created is not supported."}),"\n",(0,i.jsxs)(n.p,{children:["In addition, the third party libraries used by the ",(0,i.jsx)(n.code,{children:"QSqlDrivers"})," can impose further restrictions on using the SQL Module in a multithreaded program."]}),"\n",(0,i.jsxs)(n.p,{children:["In short, if you create a ",(0,i.jsx)(n.code,{children:"DB::connection"})," in some thread then you have to use this connection only from this particular thread and of course all queries that will be executed on this connection."]}),"\n",(0,i.jsx)(n.p,{children:"If you want to execute some query from another thread for the same connection then you have to create a new connection first and if you have a new connection you can send a query from this new thread to the database."}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.a,{href:"/database/migrations#tables",children:(0,i.jsx)(n.code,{children:"schema builder"})})," and ",(0,i.jsx)(n.a,{href:"/database/migrations",children:(0,i.jsx)(n.code,{children:"migrations"})})," don't support multi-threading."]})})]})}function L(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(D,{...e})}):D(e)}},9365:(e,n,t)=>{t.d(n,{A:()=>s});t(6540);var i=t(4164);const r={tabItem:"tabItem_Ymn6"};var a=t(4848);function s(e){let{children:n,hidden:t,className:s}=e;return(0,a.jsx)("div",{role:"tabpanel",className:(0,i.A)(r.tabItem,s),hidden:t,children:n})}},1470:(e,n,t)=>{t.d(n,{A:()=>v});var i=t(6540),r=t(4164),a=t(3104),s=t(6347),o=t(205),l=t(7485),c=t(1682),d=t(9466);function h(e){return i.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,i.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 <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function u(e){const{values:n,children:t}=e;return(0,i.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:t,attributes:i,default:r}}=e;return{value:n,label:t,attributes:i,default:r}}))}(t);return function(e){const n=(0,c.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 <Tabs>. Every value needs to be unique.`)}(e),e}),[n,t])}function p(e){let{value:n,tabValues:t}=e;return t.some((e=>e.value===n))}function m(e){let{queryString:n=!1,groupId:t}=e;const r=(0,s.W6)(),a=function(e){let{queryString:n=!1,groupId:t}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!t)throw new Error('Docusaurus error: The <Tabs> 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 t??null}({queryString:n,groupId:t});return[(0,l.aZ)(a),(0,i.useCallback)((e=>{if(!a)return;const n=new URLSearchParams(r.location.search);n.set(a,e),r.replace({...r.location,search:n.toString()})}),[a,r])]}function g(e){const{defaultValue:n,queryString:t=!1,groupId:r}=e,a=u(e),[s,l]=(0,i.useState)((()=>function(e){let{defaultValue:n,tabValues:t}=e;if(0===t.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(n){if(!p({value:n,tabValues:t}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${t.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const i=t.find((e=>e.default))??t[0];if(!i)throw new Error("Unexpected error: 0 tabValues");return i.value}({defaultValue:n,tabValues:a}))),[c,h]=m({queryString:t,groupId:r}),[g,x]=function(e){let{groupId:n}=e;const t=function(e){return e?`docusaurus.tab.${e}`:null}(n),[r,a]=(0,d.Dv)(t);return[r,(0,i.useCallback)((e=>{t&&a.set(e)}),[t,a])]}({groupId:r}),f=(()=>{const e=c??g;return p({value:e,tabValues:a})?e:null})();(0,o.A)((()=>{f&&l(f)}),[f]);return{selectedValue:s,selectValue:(0,i.useCallback)((e=>{if(!p({value:e,tabValues:a}))throw new Error(`Can't select invalid tab value=${e}`);l(e),h(e),x(e)}),[h,x,a]),tabValues:a}}var x=t(2303);const f={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var b=t(4848);function j(e){let{className:n,block:t,selectedValue:i,selectValue:s,tabValues:o}=e;const l=[],{blockElementScrollPositionUntilNextRender:c}=(0,a.a_)(),d=e=>{const n=e.currentTarget,t=l.indexOf(n),r=o[t].value;r!==i&&(c(n),s(r))},h=e=>{let n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const t=l.indexOf(e.currentTarget)+1;n=l[t]??l[0];break}case"ArrowLeft":{const t=l.indexOf(e.currentTarget)-1;n=l[t]??l[l.length-1];break}}n?.focus()};return(0,b.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":t},n),children:o.map((e=>{let{value:n,label:t,attributes:a}=e;return(0,b.jsx)("li",{role:"tab",tabIndex:i===n?0:-1,"aria-selected":i===n,ref:e=>l.push(e),onKeyDown:h,onClick:d,...a,className:(0,r.A)("tabs__item",f.tabItem,a?.className,{"tabs__item--active":i===n}),children:t??n},n)}))})}function S(e){let{lazy:n,children:t,selectedValue:r}=e;const a=(Array.isArray(t)?t:[t]).filter(Boolean);if(n){const e=a.find((e=>e.props.value===r));return e?(0,i.cloneElement)(e,{className:"margin-top--md"}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:a.map(((e,n)=>(0,i.cloneElement)(e,{key:n,hidden:e.props.value!==r})))})}function y(e){const n=g(e);return(0,b.jsxs)("div",{className:(0,r.A)("tabs-container",f.tabList),children:[(0,b.jsx)(j,{...n,...e}),(0,b.jsx)(S,{...n,...e})]})}function v(e){const n=(0,x.A)();return(0,b.jsx)(y,{...e,children:h(e.children)},String(n))}},7324:(e,n,t)=>{t.d(n,{$E:()=>x,A3:()=>b,CW:()=>f,Dx:()=>d,F4:()=>u,Fi:()=>c,J_:()=>v,LQ:()=>j,Lf:()=>_,OO:()=>r,Q7:()=>S,b:()=>o,cy:()=>l,gg:()=>m,kl:()=>p,os:()=>h,pW:()=>a,ux:()=>g,vf:()=>i,xj:()=>s,xt:()=>y});const i="shell",r="database",a="application",s="bash",o="pwsh",l="zsh",c="maria",d="mysql",h="postgres",u="sqlite",p="application",m="bash",g="pwsh",x="zsh",f="MariaDB",b="MySQL",j="PostgreSQL",S="SQLite",y="tinyorm.org",v="$HOME/Code/c/",_="$env:USERPROFILE\\Code\\c\\"},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>o});var i=t(6540);const r={},a=i.createContext(r);function s(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ba3d4959.86bd32f7.js b/assets/js/ba3d4959.86bd32f7.js deleted file mode 100644 index 78bba1537..000000000 --- a/assets/js/ba3d4959.86bd32f7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[784],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),u=p(n),c=r,h=u["".concat(s,".").concat(c)]||u[c]||d[c]||i;return n?a.createElement(h,o(o({ref:t},m),{},{components:n})):a.createElement(h,o({ref:t},m))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=c;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},5162:(e,t,n)=>{n.d(t,{Z:()=>o});var a=n(7294),r=n(6010);const i={tabItem:"tabItem_Ymn6"};function o(e){let{children:t,hidden:n,className:o}=e;return a.createElement("div",{role:"tabpanel",className:(0,r.Z)(i.tabItem,o),hidden:n},t)}},4866:(e,t,n)=>{n.d(t,{Z:()=>v});var a=n(7462),r=n(7294),i=n(6010),o=n(2466),l=n(6550),s=n(1980),p=n(7392),m=n(12);function u(e){return function(e){return r.Children.map(e,(e=>{if(!e||(0,r.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(e).map((e=>{let{props:{value:t,label:n,attributes:a,default:r}}=e;return{value:t,label:n,attributes:a,default:r}}))}function d(e){const{values:t,children:n}=e;return(0,r.useMemo)((()=>{const e=t??u(n);return function(e){const t=(0,p.l)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e}),[t,n])}function c(e){let{value:t,tabValues:n}=e;return n.some((e=>e.value===t))}function h(e){let{queryString:t=!1,groupId:n}=e;const a=(0,l.k6)(),i=function(e){let{queryString:t=!1,groupId:n}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!n)throw new Error('Docusaurus error: The <Tabs> 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 n??null}({queryString:t,groupId:n});return[(0,s._X)(i),(0,r.useCallback)((e=>{if(!i)return;const t=new URLSearchParams(a.location.search);t.set(i,e),a.replace({...a.location,search:t.toString()})}),[i,a])]}function g(e){const{defaultValue:t,queryString:n=!1,groupId:a}=e,i=d(e),[o,l]=(0,r.useState)((()=>function(e){let{defaultValue:t,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(t){if(!c({value:t,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const a=n.find((e=>e.default))??n[0];if(!a)throw new Error("Unexpected error: 0 tabValues");return a.value}({defaultValue:t,tabValues:i}))),[s,p]=h({queryString:n,groupId:a}),[u,g]=function(e){let{groupId:t}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(t),[a,i]=(0,m.Nk)(n);return[a,(0,r.useCallback)((e=>{n&&i.set(e)}),[n,i])]}({groupId:a}),f=(()=>{const e=s??u;return c({value:e,tabValues:i})?e:null})();(0,r.useLayoutEffect)((()=>{f&&l(f)}),[f]);return{selectedValue:o,selectValue:(0,r.useCallback)((e=>{if(!c({value:e,tabValues:i}))throw new Error(`Can't select invalid tab value=${e}`);l(e),p(e),g(e)}),[p,g,i]),tabValues:i}}var f=n(2389);const k={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function b(e){let{className:t,block:n,selectedValue:l,selectValue:s,tabValues:p}=e;const m=[],{blockElementScrollPositionUntilNextRender:u}=(0,o.o5)(),d=e=>{const t=e.currentTarget,n=m.indexOf(t),a=p[n].value;a!==l&&(u(t),s(a))},c=e=>{let t=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const n=m.indexOf(e.currentTarget)+1;t=m[n]??m[0];break}case"ArrowLeft":{const n=m.indexOf(e.currentTarget)-1;t=m[n]??m[m.length-1];break}}t?.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},t)},p.map((e=>{let{value:t,label:n,attributes:o}=e;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:l===t?0:-1,"aria-selected":l===t,key:t,ref:e=>m.push(e),onKeyDown:c,onClick:d},o,{className:(0,i.Z)("tabs__item",k.tabItem,o?.className,{"tabs__item--active":l===t})}),n??t)})))}function y(e){let{lazy:t,children:n,selectedValue:a}=e;const i=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){const e=i.find((e=>e.props.value===a));return e?(0,r.cloneElement)(e,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},i.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a}))))}function S(e){const t=g(e);return r.createElement("div",{className:(0,i.Z)("tabs-container",k.tabList)},r.createElement(b,(0,a.Z)({},e,t)),r.createElement(y,(0,a.Z)({},e,t)))}function v(e){const t=(0,f.Z)();return r.createElement(S,(0,a.Z)({key:String(t)},e))}},2044:(e,t,n)=>{n.d(t,{$t:()=>u,Ae:()=>f,C:()=>h,DK:()=>k,Fo:()=>l,Fs:()=>r,IM:()=>g,IZ:()=>a,RS:()=>T,VE:()=>b,Wg:()=>S,_A:()=>p,al:()=>_,jk:()=>c,js:()=>s,of:()=>m,q5:()=>o,qb:()=>v,vk:()=>d,wU:()=>i,zg:()=>y});const a="shell",r="database",i="application",o="bash",l="pwsh",s="zsh",p="maria",m="mysql",u="postgres",d="sqlite",c="application",h="bash",g="pwsh",f="zsh",k="MariaDB",b="MySQL",y="PostgreSQL",S="SQLite",v="tinyorm.org",_="$HOME/Code/c/",T="$env:USERPROFILE\\Code\\c\\"},288:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>C,contentTitle:()=>_,default:()=>E,frontMatter:()=>v,metadata:()=>T,toc:()=>N});var a=n(7462),r=n(7294),i=n(3905),o=n(5162),l=n(4866);let s=null,p=null;function m(){const[e,t]=(0,r.useState)(!1),[n,a]=(0,r.useState)(!1);return(0,r.useEffect)((()=>(u(),()=>{u()})),[]),r.createElement("form",null,r.createElement("div",{className:"tinyorm-configuration-row"},r.createElement("label",{htmlFor:"tinyorm-toggle-full"},"Full configuration"),r.createElement("input",{id:"tinyorm-toggle-full",type:"checkbox",checked:e,onChange:()=>t(d),title:"Show full configuration example"})),r.createElement("div",{className:"tinyorm-configuration-row"},r.createElement("label",{htmlFor:"tinyorm-toggle-prefix"},"Prefix environment"),r.createElement("input",{id:"tinyorm-toggle-prefix",type:"checkbox",checked:n,onChange:()=>a(y),title:"Prefix all environment variables by the database type"})))}function u(){s=null,p=null}function d(e){const t=s||(s=document.getElementById("tinyorm-configuration")?.querySelectorAll(".tabs-container")),n=!e;if(!t)return e;if(2!==t.length)throw new Error(`Wrong number of .tabs-container (!== 2) found in the toggle configuration feature, found ${t.length}.`);return n?(t[0].style.display="none",t[1].style.display="block"):(t[0].style.display="block",t[1].style.display="none"),!e}const c='"DB_',h="MARIA",g="MYSQL",f="PGSQL",k="SQLITE",b=[g,f,k,h,g,f,k,h];function y(e){const t=function(){if(p)return p;const e=document.getElementById("tinyorm-configuration")?.querySelectorAll(".prism-code > code");if(!e)return e;if(8!==e.length)throw new Error(`Wrong number of .prism-code > code (!== 8) found in the prefix env. feature, found ${e.length}.`);return p=new Array(e.length),e.forEach(((e,t)=>{p[t]=Array.from(e.querySelectorAll(".token.string")).filter((e=>e?.textContent.startsWith(c)))})),p}(),n=!e;return t?(t.forEach(((e,t)=>{e.forEach((e=>{const a=e.textContent,r=`${c}${b[t]}_`;if(n)e.textContent=`${r}${a.substring(4)}`;else{if(!a.startsWith(r))throw new Error(`Token doesn't start with the '${r}' prefix.`);e.textContent=`${c}${a.substring(r.length)}`}}))})),!e):e}var S=n(2044);const v={sidebar_position:0,sidebar_label:"Getting Started",description:"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.",keywords:["c++ orm","database","getting started","tinyorm"]},_="Database: Getting Started",T={unversionedId:"database/getting-started",id:"database/getting-started",title:"Database: Getting Started",description:"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.",source:"@site/docs/database/getting-started.mdx",sourceDirName:"database",slug:"/database/getting-started",permalink:"/database/getting-started",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/database/getting-started.mdx",tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"Getting Started",description:"TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. It provides first-party support for four databases MySQL/MariaDB, PostgreSQL, and SQLite.",keywords:["c++ orm","database","getting started","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\ude80 Supported Compilers",permalink:"/supported-compilers"},next:{title:"Query Builder",permalink:"/database/query-builder"}},C={},N=[{value:"Introduction",id:"introduction",level:2},{value:"Configuration",id:"configuration",level:3},{value:"SQLite Configuration",id:"sqlite-configuration",level:4},{value:"SSL Connections",id:"ssl-connections",level:3},{value:"MySQL",id:"mysql",level:5},{value:"PostgreSQL",id:"postgresql",level:5},{value:"Running SQL Queries",id:"running-sql-queries",level:2},{value:"Running A Select Query",id:"running-a-select-query",level:4},{value:"Selecting Scalar Values",id:"selecting-scalar-values",level:4},{value:"Running An Insert Statement",id:"running-an-insert-statement",level:4},{value:"Running An Update Statement",id:"running-an-update-statement",level:4},{value:"Running A Delete Statement",id:"running-a-delete-statement",level:4},{value:"Running A General Statement",id:"running-a-general-statement",level:4},{value:"Running An Unprepared Statement",id:"running-an-unprepared-statement",level:4},{value:"Implicit Commits",id:"implicit-commits",level:4},{value:"Using Multiple Database Connections",id:"using-multiple-database-connections",level:3},{value:"Database Transactions",id:"database-transactions",level:2},{value:"Manually Using Transactions",id:"manually-using-transactions",level:4},{value:"Multi-threading support",id:"multi-threading-support",level:2}],Q={toc:N},D="wrapper";function E(e){let{components:t,...n}=e;return(0,i.kt)(D,(0,a.Z)({},Q,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"database-getting-started"},"Database: Getting Started"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#configuration"},"Configuration")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#ssl-connections"},"SSL Connections")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#running-sql-queries"},"Running SQL Queries"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#using-multiple-database-connections"},"Using Multiple Database Connections")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#database-transactions"},"Database Transactions")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#multi-threading-support"},"Multi-threading support"))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,"Almost every modern application interacts with a database. TinyORM makes interacting with a database extremely simple using raw SQL, a ",(0,i.kt)("a",{parentName:"p",href:"/database/query-builder"},"fluent query builder"),", and the ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/getting-started"},"TinyORM"),". Currently, TinyORM provides first-party support for four databases:"),(0,i.kt)("div",{id:"databases-supported-versions"},(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"MySQL ",(0,i.kt)("inlineCode",{parentName:"li"},">=5.7")," (",(0,i.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/MySQL#Release_history"},"Version Policy"),")"),(0,i.kt)("li",{parentName:"ul"},"MariaDB ",(0,i.kt)("inlineCode",{parentName:"li"},">=10.3")," (",(0,i.kt)("a",{parentName:"li",href:"https://mariadb.org/about/#maintenance-policy"},"Version Policy"),")"),(0,i.kt)("li",{parentName:"ul"},"PostgreSQL ",(0,i.kt)("inlineCode",{parentName:"li"},">=11")," (",(0,i.kt)("a",{parentName:"li",href:"https://www.postgresql.org/support/versioning/"},"Version Policy"),")"),(0,i.kt)("li",{parentName:"ul"},"SQLite ",(0,i.kt)("inlineCode",{parentName:"li"},">=3.8.8"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"native rename column ",(0,i.kt)("inlineCode",{parentName:"li"},">=3.25.0")," (",(0,i.kt)("a",{parentName:"li",href:"https://www.sqlite.org/lang_altertable.html#alter_table_rename_column"},"docs")," , ",(0,i.kt)("a",{parentName:"li",href:"https://www.sqlite.org/releaselog/3_25_0.html"},"release notes"),")"),(0,i.kt)("li",{parentName:"ul"},"native drop column ",(0,i.kt)("inlineCode",{parentName:"li"},">=3.35.0")," (",(0,i.kt)("a",{parentName:"li",href:"https://www.sqlite.org/lang_altertable.html#alter_table_drop_column"},"docs"),", ",(0,i.kt)("a",{parentName:"li",href:"https://www.sqlite.org/releaselog/3_35_0.html"},"release notes"),")"),(0,i.kt)("li",{parentName:"ul"},"generated columns ",(0,i.kt)("inlineCode",{parentName:"li"},">=3.31.0")," (",(0,i.kt)("a",{parentName:"li",href:"https://www.sqlite.org/gencol.html"},"docs"),", ",(0,i.kt)("a",{parentName:"li",href:"https://www.sqlite.org/releaselog/3_31_0.html"},"release notes"),")"))))),(0,i.kt)("p",null,"TinyORM internally uses ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql")," module, you can look for ",(0,i.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/sql-driver.html#supported-databases"},"supported databases"),"."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"TinyORM's code is ready and designed to simply add support for the SQL Server.")),(0,i.kt)("h3",{id:"configuration"},"Configuration"),(0,i.kt)("p",null,"You can create and configure a new database connection using the ",(0,i.kt)("inlineCode",{parentName:"p"},"create")," method provided by the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade:"),(0,i.kt)("div",{id:"tinyorm-configuration"},(0,i.kt)(m,{mdxType:"ConfigurationSettings"}),(0,i.kt)(l.Z,{className:"tinyorm-configuration-basic",groupId:S.Fs,mdxType:"Tabs"},(0,i.kt)(o.Z,{value:S.of,label:S.VE,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_PORT", "3306")},\n {"database", qEnvironmentVariable("DB_DATABASE", "")},\n {"username", qEnvironmentVariable("DB_USERNAME", "root")},\n {"password", qEnvironmentVariable("DB_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_CHARSET", "utf8mb4")},\n {"collation", qEnvironmentVariable("DB_COLLATION", "utf8mb4_0900_ai_ci")},\n {"timezone", "+00:00"},\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 {"prefix", ""},\n {"prefix_indexes", false},\n {"strict", true},\n {"engine", "InnoDB"},\n {"options", QVariantHash()},\n});\n'))),(0,i.kt)(o.Z,{value:S.$t,label:S.zg,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_PORT", "5432")},\n {"database", qEnvironmentVariable("DB_DATABASE", "")},\n {"search_path", qEnvironmentVariable("DB_SEARCHPATH", "public")},\n {"username", qEnvironmentVariable("DB_USERNAME", "postgres")},\n {"password", qEnvironmentVariable("DB_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_CHARSET", "utf8")},\n {"timezone", "UTC"},\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 {"prefix", ""},\n {"prefix_indexes", false},\n {"options", QVariantHash()},\n});\n'))),(0,i.kt)(o.Z,{value:S.vk,label:S.Wg,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("DB_DATABASE", "/example/example.sqlite3")},\n {"foreign_key_constraints", qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},\n {"check_database_exists", true},\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 /* Return a QDateTime/QDate with the correct time zone instead of the QString,\n only works when the qt_timezone isn\'t set to the DontConvert. */\n {"return_qdatetime", true},\n {"prefix", ""},\n {"prefix_indexes", false},\n});\n'))),(0,i.kt)(o.Z,{value:S._A,label:S.DK,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_PORT", "3306")},\n {"database", qEnvironmentVariable("DB_DATABASE", "")},\n {"username", qEnvironmentVariable("DB_USERNAME", "root")},\n {"password", qEnvironmentVariable("DB_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_CHARSET", "utf8mb4")},\n {"collation", qEnvironmentVariable("DB_COLLATION", "utf8mb4_unicode_520_ci")},\n {"timezone", "+00:00"},\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 {"prefix", ""},\n {"prefix_indexes", false},\n {"strict", true},\n {"engine", "InnoDB"},\n {"options", QVariantHash()},\n});\n')))),(0,i.kt)(l.Z,{className:"tinyorm-configuration-full",groupId:S.Fs,mdxType:"Tabs"},(0,i.kt)(o.Z,{value:S.of,label:S.VE,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QMYSQL},\n {host_, qEnvironmentVariable("DB_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_PORT", P3306)},\n {database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},\n {username_, qEnvironmentVariable("DB_USERNAME", ROOT)},\n {password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_CHARSET", UTF8MB4)},\n {collation_, qEnvironmentVariable("DB_COLLATION", UTF8MB40900aici)},\n // SSL-related\n {ssl_ca, QStringLiteral("C:/mysql/data/ca.pem")},\n {ssl_cert, QStringLiteral("C:/mysql/data/client-cert.pem")},\n {ssl_key, QStringLiteral("C:/mysql/data/client-key.pem")},\n {ssl_mode, VerifyCA},\n // Or\n// {options, ConfigUtils::mysqlSslOptions()},\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 {prefix_, EMPTY},\n {prefix_indexes, false},\n {strict_, true},\n// {isolation_level, QStringLiteral("REPEATABLE READ")}, // MySQL default is REPEATABLE READ for InnoDB\n {engine_, InnoDB},\n {Version, {}}, // Autodetect\n {options_, QVariantHash()},\n // Examples\n// {options_, QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT = 1 ; MYSQL_OPT_READ_TIMEOUT=1")},\n// {options_, QVariantHash {{QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT"), 1},\n// {QStringLiteral("MYSQL_OPT_READ_TIMEOUT"), 1}}},\n});\n'))),(0,i.kt)(o.Z,{value:S.$t,label:S.zg,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QPSQL},\n {application_name, QStringLiteral("Example application")},\n {host_, qEnvironmentVariable("DB_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_PORT", P5432)},\n {database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},\n {search_path, qEnvironmentVariable("DB_SEARCHPATH", PUBLIC)},\n {username_, qEnvironmentVariable("DB_USERNAME", postgres_)},\n {password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_CHARSET", UTF8)},\n // SSL-related\n {sslmode_, QStringLiteral("verify-full")},\n {sslcert, QStringLiteral("C:/example/postgres.crt")},\n {sslkey, QStringLiteral("C:/example/postgres.key")},\n {sslrootcert, QStringLiteral("C:/example/root.crt")},\n // Or\n// {options_, ConfigUtils::postgresSslOptions()},\n {timezone_, UTC},\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 {prefix_, EMPTY},\n {prefix_indexes, false},\n// {isolation_level, QStringLiteral("REPEATABLE READ")}, // Postgres default is READ COMMITTED\n// {synchronous_commit, QStringLiteral("off")}, // Postgres default is on\n // ConnectionFactory provides a default value for this, this is only for reference\n// {dont_drop, QStringList {spatial_ref_sys}},\n {options_, QVariantHash()},\n});\n'))),(0,i.kt)(o.Z,{value:S.vk,label:S.Wg,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QSQLITE},\n {database_, qEnvironmentVariable("DB_DATABASE", "C:/SQLite/example.sqlite3")},\n {foreign_key_constraints, qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},\n {check_database_exists, true},\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 /* Return a QDateTime/QDate with the correct time zone instead of the QString,\n only works when the qt_timezone isn\'t set to the DontConvert. */\n {return_qdatetime, true},\n {prefix_, EMPTY},\n {prefix_indexes, false},\n});\n'))),(0,i.kt)(o.Z,{value:S._A,label:S.DK,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\nusing namespace Orm::Constants; // NOLINT(google-build-using-namespace)\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {driver_, QMYSQL},\n {host_, qEnvironmentVariable("DB_HOST", H127001)},\n {port_, qEnvironmentVariable("DB_PORT", P3306)},\n {database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},\n {username_, qEnvironmentVariable("DB_USERNAME", ROOT)},\n {password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},\n {charset_, qEnvironmentVariable("DB_CHARSET", UTF8MB4)},\n {collation_, qEnvironmentVariable("DB_COLLATION", UTF8MB4Unicode520ci)},\n // SSL-related\n {ssl_ca, QStringLiteral("C:/maria/data/ca.pem")},\n {ssl_cert, QStringLiteral("C:/maria/data/client-cert.pem")},\n {ssl_key, QStringLiteral("C:/maria/data/client-key.pem")},\n // Or\n// {options, ConfigUtils::mariaSslOptions()},\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 {prefix_, EMPTY},\n {prefix_indexes, false},\n {strict_, true},\n// {isolation_level, QStringLiteral("REPEATABLE READ")}, // MariaDB default is REPEATABLE READ for InnoDB\n {engine_, InnoDB},\n {Version, {}}, // Autodetect\n {options_, QVariantHash()},\n // Examples\n// {options_, QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT = 1 ; MYSQL_OPT_READ_TIMEOUT=1")},\n// {options_, QVariantHash {{QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT"), 1},\n// {QStringLiteral("MYSQL_OPT_READ_TIMEOUT"), 1}}},\n});\n'))))),(0,i.kt)("p",null,"The first argument is configuration hash which is of type ",(0,i.kt)("inlineCode",{parentName:"p"},"QVariantHash")," and the second argument specifies the name of the ",(0,i.kt)("em",{parentName:"p"},"connection"),", this connection will also be a ",(0,i.kt)("em",{parentName:"p"},"default connection"),". You can configure multiple database connections at once and choose the needed one before executing SQL query, section ",(0,i.kt)("a",{parentName:"p",href:"#using-multiple-database-connections"},"Using Multiple Database Connections")," describes how to create and use multiple database connections."),(0,i.kt)("p",null,"You may also configure connection options by ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," key as ",(0,i.kt)("inlineCode",{parentName:"p"},"QVariantHash")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"QString"),", you can pass any ",(0,i.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qsqldatabase.html#setConnectOptions"},"connection options")," supported by ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlDatabase"),"."),(0,i.kt)("p",null,"You can also configure ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/refman/8.3/en/innodb-transaction-isolation-levels.html"},"Transaction Isolation Levels")," for MySQL connection with the ",(0,i.kt)("inlineCode",{parentName:"p"},"isolation_level")," configuration option."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"version")," option is relevant only for the MySQL connections and you can save/avoid one database query (select version()) if you provide it manually. On the base of this version will be decided which ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/src/orm/connectors/mysqlconnector.cpp#L154"},"session variables")," will be set if strict mode is enabled and whether to use an ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/src/orm/query/grammars/mysqlgrammar.cpp#L36"},"alias")," during the ",(0,i.kt)("inlineCode",{parentName:"p"},"upsert")," method call."),(0,i.kt)("p",null,"Breaking values are as follows; use an upsert alias on the MySQL >=8.0.19 and remove the ",(0,i.kt)("inlineCode",{parentName:"p"},"NO_AUTO_CREATE_USER")," sql mode on the MySQL >=8.0.11 if the strict mode is enabled."),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"A database connection is resolved lazily, which means that the connection configuration is only saved after the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB::create")," method call. The connection will be resolved after you run some query or you can create it using the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB::connection")," method.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can also use predefined string constants to avoid unnecessary ",(0,i.kt)("inlineCode",{parentName:"p"},"QString")," instantiations, as used in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tom")," migrations ",(0,i.kt)("a",{parentName:"p",href:"/building/migrations#string-constants-example"},"example"),".")),(0,i.kt)("h4",{id:"sqlite-configuration"},"SQLite Configuration"),(0,i.kt)("p",null,"SQLite databases are contained within a single file on your filesystem. You can create a new SQLite database using the ",(0,i.kt)("inlineCode",{parentName:"p"},"touch")," command in your terminal: ",(0,i.kt)("inlineCode",{parentName:"p"},"touch database.sqlite3"),". After the database has been created, you may configure SQLite database connection:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("DB_DATABASE", "/absolute/path/to/database.sqlite3")},\n {"foreign_key_constraints", qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},\n {"check_database_exists", true},\n {"prefix", ""},\n});\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"database")," configuration value is the absolute path to the database. To enable foreign key constraints for SQLite connections, you should set the ",(0,i.kt)("inlineCode",{parentName:"p"},"foreign_key_constraints")," configuration value to ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),", if this configuration value is not set, then the default of the SQLite driver will be used (currently the default is ",(0,i.kt)("strong",{parentName:"p"},"disabled"),")."),(0,i.kt)("p",null,"If the ",(0,i.kt)("inlineCode",{parentName:"p"},"check_database_exists")," configuration value is set to the ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," value, then the database connection throws an ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::InvalidArgumentError")," exception, when the SQLite database file doesn't exist. If it is set to the ",(0,i.kt)("inlineCode",{parentName:"p"},"false")," value and the SQLite database file doesn't exist, then it will be created for you by SQLite driver. The default value is ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),"."),(0,i.kt)("h3",{id:"ssl-connections"},"SSL Connections"),(0,i.kt)("p",null,"SSL connections are supported for the ",(0,i.kt)("inlineCode",{parentName:"p"},"MySQL")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"PostgreSQL")," databases. They can be set using the ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," configuration option."),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"This feature is heavily dependent on the underlying ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlDatabase")," module. What means that you can pass the same ",(0,i.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qsqldatabase.html#setConnectOptions"},"connection options")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," that the ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlDatabase")," accepts.")),(0,i.kt)("h5",{id:"mysql"},"MySQL"),(0,i.kt)("p",null,"You have to pass the ",(0,i.kt)("inlineCode",{parentName:"p"},"SSL_CA"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"SSL_CERT"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"SSL_KEY"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"MYSQL_OPT_SSL_MODE")," options."),(0,i.kt)(l.Z,{groupId:S.IZ,mdxType:"Tabs"},(0,i.kt)(o.Z,{value:S.Fo,label:S.IM,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"options", QVariantHash({{"SSL_CA", "C:/mysql/data/ca.pem"},\n {"SSL_CERT", "C:/mysql/data/client-cert.pem"},\n {"SSL_KEY", "C:/mysql/data/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"}})},\n // highlight-end\n});\n'))),(0,i.kt)(o.Z,{value:S.q5,label:S.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"options", QVariantHash({{"SSL_CA", "~/.local/share/TinyORM/ssl/ca.pem"},\n {"SSL_CERT", "~/.local/share/TinyORM/ssl/client-cert.pem"},\n {"SSL_KEY", "~/.local/share/TinyORM/ssl/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"}})},\n // highlight-end\n});\n')))),(0,i.kt)("p",null,"You may also use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConfigUtils::mysqlSslOptions()")," or the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConfigUtils::insertMySqlSslOptions()")," methods to insert these options for you and define them using the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_MYSQL_SSL_CA"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_MYSQL_SSL_CERT"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_MYSQL_SSL_KEY"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_MYSQL_SSL_MODE")," environment variables."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", ConfigUtils::mysqlSslOptions()},\n});\n')),(0,i.kt)("p",null,"You can define these SSL-related options in the top-level configuration, they will be copied to the ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," option hash during configuration parsing. The top-level configuration takes precedence and overwrites the options in the ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," hash."),(0,i.kt)(l.Z,{groupId:S.IZ,mdxType:"Tabs"},(0,i.kt)(o.Z,{value:S.Fo,label:S.IM,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"SSL_CA", "C:/mysql/data/ca.pem"},\n {"SSL_CERT", "C:/mysql/data/client-cert.pem"},\n {"SSL_KEY", "C:/mysql/data/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"},\n // highlight-end\n});\n'))),(0,i.kt)(o.Z,{value:S.q5,label:S.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"SSL_CA", "~/.local/share/TinyORM/ssl/ca.pem"},\n {"SSL_CERT", "~/.local/share/TinyORM/ssl/client-cert.pem"},\n {"SSL_KEY", "~/.local/share/TinyORM/ssl/client-key.pem"},\n {"MYSQL_OPT_SSL_MODE", "VERIFY_CA"},\n // highlight-end\n});\n')))),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can take a look at the GitHub actions how the ",(0,i.kt)("inlineCode",{parentName:"p"},"MySQL")," certificates are generated in the CI pipeline for ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/msvc2022-qt6.yml"},"Windows")," and ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/linux-qt6.yml"},"Linux"),".")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can also pass the ",(0,i.kt)("inlineCode",{parentName:"p"},"QString")," to the ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," configuration separated by the ",(0,i.kt)("inlineCode",{parentName:"p"},";")," semicolon character and use the ",(0,i.kt)("inlineCode",{parentName:"p"},"=")," to assign values.")),(0,i.kt)("h5",{id:"postgresql"},"PostgreSQL"),(0,i.kt)("p",null,"You have to pass the ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS"},(0,i.kt)("inlineCode",{parentName:"a"},"sslmode"))," or the deprecated ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-REQUIRESSL"},(0,i.kt)("inlineCode",{parentName:"a"},"requiressl"))," options."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", QVariantHash({{"sslmode", "verify-full"}})},\n});\n')),(0,i.kt)("p",null,"And place your ",(0,i.kt)("strong",{parentName:"p"},"client")," certificates to the ",(0,i.kt)("inlineCode",{parentName:"p"},"~/.postgres/")," on ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-FILE-USAGE"},"Linux")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"$env:APPDATA/postgres/")," on Windows. Everything is described in the PostgreSQL's ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-ssl.html"},"libpq client")," and ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/15/ssl-tcp.html#SSL-FILE-USAGE"},"server")," documentation."),(0,i.kt)("p",null,"If you want to keep your ",(0,i.kt)("strong",{parentName:"p"},"client")," certificates in your own location, you can set the ",(0,i.kt)("inlineCode",{parentName:"p"},"sslcert"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"sslkey"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"sslrootcert")," options."),(0,i.kt)(l.Z,{groupId:S.IZ,mdxType:"Tabs"},(0,i.kt)(o.Z,{value:S.Fo,label:S.IM,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", QVariantHash({{"sslmode", "verify-full"},\n // highlight-start\n {"sslcert", "C:/example/postgres.crt"},\n {"sslkey", "C:/example/postgres.key"},\n {"sslrootcert", "C:/example/root.crt"}})},\n // highlight-end\n});\n'))),(0,i.kt)(o.Z,{value:S.q5,label:S.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", QVariantHash({{"sslmode", "verify-full"},\n // highlight-start\n {"sslcert", "/example/postgres.crt"},\n {"sslkey", "/example/postgres.key"},\n {"sslrootcert", "/example/root.crt"}})},\n // highlight-end\n});\n')))),(0,i.kt)("p",null,"You can define these SSL-related options in the top-level configuration, they will be copied to the ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," option hash during a configuration parsing. The top-level configuration takes precedence and overwrites the options in the ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," hash."),(0,i.kt)(l.Z,{groupId:S.IZ,mdxType:"Tabs"},(0,i.kt)(o.Z,{value:S.Fo,label:S.IM,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"sslmode", "verify-full"},\n {"sslcert", "C:/example/postgres.crt"},\n {"sslkey", "C:/example/postgres.key"},\n {"sslrootcert", "C:/example/root.crt"},\n // highlight-end\n});\n'))),(0,i.kt)(o.Z,{value:S.q5,label:S.C,mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nusing Orm::DB;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-start\n {"sslmode", "verify-full"},\n {"sslcert", "/example/postgres.crt"},\n {"sslkey", "/example/postgres.key"},\n {"sslrootcert", "/example/root.crt"},\n // highlight-end\n});\n')))),(0,i.kt)("p",null,"You may also use the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConfigUtils::postgresSslOptions()")," or the ",(0,i.kt)("inlineCode",{parentName:"p"},"ConfigUtils::insertPostgresSslOptions()")," methods to insert the ",(0,i.kt)("inlineCode",{parentName:"p"},"sslmode"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"sslcert"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"sslkey"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"sslrootcert")," options for you and define them using the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_PGSQL_SSLMODE"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_PGSQL_SSLCERT"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_PGSQL_SSLKEY"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"DB_PGSQL_SSLROOTCERT")," environment variable."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n#include <orm/utils/configuration.hpp>\n\nusing Orm::DB;\n\nusing ConfigUtils = Orm::Utils::Configuration;\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"driver", "QPSQL"},\n {"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},\n ...\n // highlight-next-line\n {"options", ConfigUtils::postgresSslOptions()},\n});\n')),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"The PostgreSQL's libpq client library provides the ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.13.1.1"},(0,i.kt)("inlineCode",{parentName:"a"},"PGSSLMODE")),", ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.16.1.1"},(0,i.kt)("inlineCode",{parentName:"a"},"PGSSLCERT")),", ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.17.1.1"},(0,i.kt)("inlineCode",{parentName:"a"},"PGSSLKEY")),", and ",(0,i.kt)("a",{parentName:"p",href:"https://www.postgresql.org/docs/current/libpq-envars.html#id-1.7.3.22.3.4.18.1.1"},(0,i.kt)("inlineCode",{parentName:"a"},"PGSSLROOTCERT"))," environment variables, so you don't have to use TinyORM's ",(0,i.kt)("inlineCode",{parentName:"p"},"options")," configuration and may use these environment variables instead.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can take a look at the GitHub actions how the ",(0,i.kt)("inlineCode",{parentName:"p"},"PostgreSQL")," certificates are generated in the CI pipeline for ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/msvc2022-qt6.yml"},"Windows")," and ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/blob/main/.github/workflows/linux-qt6.yml"},"Linux"),".")),(0,i.kt)("h2",{id:"running-sql-queries"},"Running SQL Queries"),(0,i.kt)("p",null,"Once you have configured your database connection, you may run queries using the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade. The ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade provides methods for each type of query: ",(0,i.kt)("inlineCode",{parentName:"p"},"select"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"update"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"insert"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"delete"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"statement"),"."),(0,i.kt)("h4",{id:"running-a-select-query"},"Running A Select Query"),(0,i.kt)("p",null,"To run a basic SELECT query, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"select")," method on the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'auto users = DB::select("select * from users where active = ?", {1});\n')),(0,i.kt)("p",null,"The first argument passed to the ",(0,i.kt)("inlineCode",{parentName:"p"},"select")," method is the SQL query, while the second argument is any parameter bindings that need to be bound to the query. Typically, these are the values of the ",(0,i.kt)("inlineCode",{parentName:"p"},"where")," clause constraints. Parameter binding provides protection against SQL injection."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"select")," method returns a ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery")," containing the results of the query, where each result can be accessed by ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery::next")," method. Look into the ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery"),' documentation on how to obtain results from the "query". You may access each column\'s value by ',(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery::value")," method. The first ",(0,i.kt)("inlineCode",{parentName:"p"},"bool")," return value is the value returned from ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery::exec")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include <orm/db.hpp>\n\nauto users = DB::select("select * from users");\n\nwhile(users.next())\n qDebug() << users.value("name").toString();\n')),(0,i.kt)("h4",{id:"selecting-scalar-values"},"Selecting Scalar Values"),(0,i.kt)("p",null,"Sometimes your database query may result in a single, scalar value. Instead of being required to retrieve the query's scalar result from a record instance, TinyORM allows you to retrieve this value directly using the ",(0,i.kt)("inlineCode",{parentName:"p"},"scalar")," shortcut method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nauto states = DB::scalar(\n "select count(case when state = \'pending\' then 1 end) as states "\n "from comments"\n);\n\n// With binding\nauto states = DB::scalar(\n "select count(case when state = ? then 1 end) as states from comments",\n {"pending"}\n);\n')),(0,i.kt)("h4",{id:"running-an-insert-statement"},"Running An Insert Statement"),(0,i.kt)("p",null,"To execute an ",(0,i.kt)("inlineCode",{parentName:"p"},"insert")," statement, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"insert")," method on the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade. Like ",(0,i.kt)("inlineCode",{parentName:"p"},"select"),", this method accepts the SQL query as its first argument and bindings as its second argument and returns ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nDB::insert("insert into users (id, name) values (?, ?)", {1, "Marc"});\n')),(0,i.kt)("h4",{id:"running-an-update-statement"},"Running An Update Statement"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"update")," method should be used to update existing records in the database. The number of rows affected by the statement and ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery")," is returned by the method as ",(0,i.kt)("inlineCode",{parentName:"p"},"std::tuple<int, QSqlQuery>"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <QDateTime>\n\n#include <orm/db.hpp>\n\nauto [affected, query] = DB::update(\n "update users set updated_at = ? where name = ?",\n {QDateTime::currentDateTimeUtc(), "Anita"}\n);\n\nif (!affected)\n qDebug() << "Any record was updated.";\n')),(0,i.kt)("h4",{id:"running-a-delete-statement"},"Running A Delete Statement"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"remove")," method should be used to delete records from the database. Like ",(0,i.kt)("inlineCode",{parentName:"p"},"update"),", the number of affected rows and ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery")," will be returned by the method as ",(0,i.kt)("inlineCode",{parentName:"p"},"std::tuple<int, QSqlQuery>"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nauto [affected, query] = DB::remove("delete from users");\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"delete")," can not be used as the method name because it is the reserved word.")),(0,i.kt)("h4",{id:"running-a-general-statement"},"Running A General Statement"),(0,i.kt)("p",null,"Some database statements do not return any value. For these types of operations, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"statement")," method on the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'DB::statement("drop table users");\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"DB::statement")," method should be used for ",(0,i.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Data_definition_language"},"DDL"),' queries, don\'t use it for "select" queries because it internally calls ',(0,i.kt)("inlineCode",{parentName:"p"},"recordsHaveBeenModified")," method.")),(0,i.kt)("h4",{id:"running-an-unprepared-statement"},"Running An Unprepared Statement"),(0,i.kt)("p",null,"Sometimes you may want to execute an SQL statement without binding any values. You may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade's ",(0,i.kt)("inlineCode",{parentName:"p"},"unprepared")," method to accomplish this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"DB::unprepared(\"update users set votes = 100 where name = 'Dries'\");\n")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Since unprepared statements do not bind parameters, they may be vulnerable to SQL injection. You should never allow user controlled values within an unprepared statement.")),(0,i.kt)("h4",{id:"implicit-commits"},"Implicit Commits"),(0,i.kt)("p",null,"When using the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade's ",(0,i.kt)("inlineCode",{parentName:"p"},"statement")," methods within transactions, you must be careful to avoid statements that cause ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/refman/8.3/en/implicit-commit.html"},"implicit commits"),". These statements will cause the database engine to indirectly commit the entire transaction, leaving TinyORM unaware of the database's transaction level. An example of such a statement is creating a database table:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'DB::statement("create table users (name varchar(255) null)");\n')),(0,i.kt)("p",null,"Please refer to the MySQL manual for ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/refman/8.3/en/implicit-commit.html"},"a list of all statements")," that trigger implicit commits."),(0,i.kt)("h3",{id:"using-multiple-database-connections"},"Using Multiple Database Connections"),(0,i.kt)("p",null,"You can configure multiple database connections at once during ",(0,i.kt)("inlineCode",{parentName:"p"},"DatabaseManager")," instantiation using the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB::create")," overload, where the first argument is a hash of multiple connections and is of type ",(0,i.kt)("inlineCode",{parentName:"p"},"QHash<QString, QVariantHash>")," and the second argument is the name of the default connection:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\n// Ownership of a shared_ptr()\nauto manager = DB::create({\n {"mysql", {\n {"driver", "QMYSQL"},\n {"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},\n {"port", qEnvironmentVariable("DB_MYSQL_PORT", "3306")},\n {"database", qEnvironmentVariable("DB_MYSQL_DATABASE", "")},\n {"username", qEnvironmentVariable("DB_MYSQL_USERNAME", "root")},\n {"password", qEnvironmentVariable("DB_MYSQL_PASSWORD", "")},\n {"charset", qEnvironmentVariable("DB_MYSQL_CHARSET", "utf8mb4")},\n {"collation", qEnvironmentVariable("DB_MYSQL_COLLATION", "utf8mb4_0900_ai_ci")},\n {"strict", true},\n {"options", QVariantHash()},\n }},\n {"sqlite", {\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("DB_SQLITE_DATABASE", "")},\n {"foreign_key_constraints", qEnvironmentVariable("DB_SQLITE_FOREIGN_KEYS", "true")},\n {"check_database_exists", true},\n {"prefix", ""},\n }},\n}, "mysql");\n')),(0,i.kt)("p",null,"If your application needs to use multiple connections, you may access each connection via the ",(0,i.kt)("inlineCode",{parentName:"p"},"connection")," method provided by the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade. The connection name passed to the ",(0,i.kt)("inlineCode",{parentName:"p"},"connection")," method should correspond to one of the connections key listed in your configuration:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nauto query = DB::connection("mysql_test").select(...);\n')),(0,i.kt)("p",null,"You may access the raw underlying ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlQuery")," instance of a connection using the ",(0,i.kt)("inlineCode",{parentName:"p"},"getQtQuery")," method on a connection instance:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"auto query = DB::connection().getQtQuery();\n")),(0,i.kt)("p",null,"Or you can use the shortcut method ",(0,i.kt)("inlineCode",{parentName:"p"},"qtQuery")," provided by the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"auto query = DB::qtQuery();\n")),(0,i.kt)("h2",{id:"database-transactions"},"Database Transactions"),(0,i.kt)("h4",{id:"manually-using-transactions"},"Manually Using Transactions"),(0,i.kt)("p",null,"If you would like to begin a transaction manually and have complete control over rollbacks and commits, you may use the ",(0,i.kt)("inlineCode",{parentName:"p"},"beginTransaction")," method provided by the ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"#include <orm/db.hpp>\n\nDB::beginTransaction();\n")),(0,i.kt)("p",null,"You can rollback the transaction via the ",(0,i.kt)("inlineCode",{parentName:"p"},"rollBack")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"DB::rollBack();\n")),(0,i.kt)("p",null,"Lastly, you can commit a transaction via the ",(0,i.kt)("inlineCode",{parentName:"p"},"commit")," method:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"DB::commit();\n")),(0,i.kt)("p",null,"All transaction methods accept a connection name as the optional argument:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'DB::beginTransaction("mysql_test");\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"DB")," facade's transaction methods control the transactions for both the ",(0,i.kt)("a",{parentName:"p",href:"/database/query-builder"},"query builder")," and ",(0,i.kt)("a",{parentName:"p",href:"/tinyorm/getting-started"},"TinyORM"),".")),(0,i.kt)("h2",{id:"multi-threading-support"},"Multi-threading support"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM")," supports multi-threading for the ",(0,i.kt)("inlineCode",{parentName:"p"},"MSVC")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"GCC")," on Linux compilers. Multi-threading is disabled for the ",(0,i.kt)("inlineCode",{parentName:"p"},"Clang <14.0.3")," compiler on MSYS2, ",(0,i.kt)("inlineCode",{parentName:"p"},"Clang <14.0.4")," on Linux and for the ",(0,i.kt)("inlineCode",{parentName:"p"},"GCC")," compiler on MSYS2. The reason are bugs in the ",(0,i.kt)("inlineCode",{parentName:"p"},"TLS")," wrapper that is generated by the ",(0,i.kt)("a",{parentName:"p",href:"https://en.cppreference.com/w/cpp/keyword/thread_local"},(0,i.kt)("inlineCode",{parentName:"a"},"thread_local"))," keyword."),(0,i.kt)("p",null,"A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread where the connection was created is not supported."),(0,i.kt)("p",null,"In addition, the third party libraries used by the ",(0,i.kt)("inlineCode",{parentName:"p"},"QSqlDrivers")," can impose further restrictions on using the SQL Module in a multithreaded program."),(0,i.kt)("p",null,"In short, if you create a ",(0,i.kt)("inlineCode",{parentName:"p"},"DB::connection")," in some thread then you have to use this connection only from this particular thread and of course all queries that will be executed on this connection."),(0,i.kt)("p",null,"If you want to execute some query from another thread for the same connection then you have to create a new connection first and if you have a new connection you can send a query from this new thread to the database."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations#tables"},(0,i.kt)("inlineCode",{parentName:"a"},"schema builder"))," and ",(0,i.kt)("a",{parentName:"p",href:"/database/migrations"},(0,i.kt)("inlineCode",{parentName:"a"},"migrations"))," don't support multi-threading.")))}E.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c141421f.2356f0d5.js b/assets/js/c141421f.2356f0d5.js new file mode 100644 index 000000000..2b0bd382a --- /dev/null +++ b/assets/js/c141421f.2356f0d5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[957],{936:e=>{e.exports=JSON.parse('{"name":"docusaurus-theme-search-algolia","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/cb1e72f9.0ad8566f.js b/assets/js/cb1e72f9.0ad8566f.js new file mode 100644 index 000000000..2735d8149 --- /dev/null +++ b/assets/js/cb1e72f9.0ad8566f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[258],{4028:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>a,contentTitle:()=>t,default:()=>h,frontMatter:()=>d,metadata:()=>l,toc:()=>c});var r=n(4848),s=n(8453);const d={sidebar_position:0,sidebar_label:"Getting Started",description:"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.",keywords:["c++ orm","database","getting started","tinydrivers","sql drivers"]},t="TinyDrivers: Getting Started",l={id:"tinydrivers/getting-started",title:"TinyDrivers: Getting Started",description:"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.",source:"@site/docs/tinydrivers/getting-started.mdx",sourceDirName:"tinydrivers",slug:"/tinydrivers/getting-started",permalink:"/tinydrivers/getting-started",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"Getting Started",description:"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.",keywords:["c++ orm","database","getting started","tinydrivers","sql drivers"]},sidebar:"tinyormSidebar",previous:{title:"Serialization",permalink:"/tinyorm/serialization"},next:{title:"TinyORM",permalink:"/building/tinyorm"}},a={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Features summary",id:"features-summary",level:5},{value:"Differences from QtSql",id:"differences-from-qtsql",level:2},{value:"Naming conventions",id:"naming-conventions",level:5},{value:"MySQL driver",id:"mysql-driver",level:5},{value:"Removed features",id:"removed-features",level:5},{value:"Missing features",id:"missing-features",level:5},{value:"Build system",id:"build-system",level:3},{value:"The <code>Shared</code> library build",id:"the-shared-library-build",level:5},{value:"The <code>Static</code> build",id:"the-static-build",level:5},{value:"The <code>Loadable</code> SQL drivers build",id:"the-loadable-sql-drivers-build",level:5},{value:"<code>CMake</code>/<code>qmake</code> build options",id:"cmakeqmake-build-options",level:4},{value:"For <code>CMake</code>",id:"for-cmake",level:5},{value:"For <code>qmake</code>",id:"for-qmake",level:5},{value:"Performance",id:"performance",level:3},{value:"Internals",id:"internals",level:2},{value:"SqlDatabase",id:"sqldatabase",level:5},{value:"Namespaces",id:"namespaces",level:5},{value:"Documentation",id:"documentation",level:5}];function o(e){const i={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",p:"p",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(i.h1,{id:"tinydrivers-getting-started",children:"TinyDrivers: Getting Started"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.a,{href:"#differences-from-qtsql",children:"Differences from QtSql"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#build-system",children:"Build system"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#performance",children:"Performance"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"#internals",children:"Internals"})}),"\n"]}),"\n",(0,r.jsx)(i.h2,{id:"introduction",children:"Introduction"}),"\n",(0,r.jsxs)(i.p,{children:["The ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," library is an underlying SQL database layer for ",(0,r.jsx)(i.code,{children:"TinyORM"}),". It can be used instead of the ",(0,r.jsx)(i.code,{children:"QtSql"})," module, can be ",(0,r.jsx)("u",{children:(0,r.jsx)(i.strong,{children:"swapped"})})," at compile time, and has ",(0,r.jsx)(i.strong,{children:"1:1"})," API as the ",(0,r.jsx)(i.code,{children:"QtSql"})," module. \ud83d\ude2e Swapping is controlled by the ",(0,r.jsx)(i.code,{children:"qmake"})," and ",(0,r.jsx)(i.code,{children:"CMake"})," build system options."]}),"\n",(0,r.jsxs)(i.p,{children:["It was designed to drop the ",(0,r.jsx)(i.code,{children:"QtSql"})," dependency while maintaining backward compatibility and without the need for any code changes after the swap."]}),"\n",(0,r.jsx)(i.h5,{id:"features-summary",children:"Features summary"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"both, normal and prepared statements are supported"}),"\n",(0,r.jsxs)(i.li,{children:["TLS/SSL connections using ",(0,r.jsx)(i.a,{href:"https://dev.mysql.com/doc/c-api/en/mysql-options.html",children:(0,r.jsx)(i.code,{children:"MYSQL_OPT_SSL_MODE"})})," (verify_ca, verify_identity) \ud83d\udd25"]}),"\n",(0,r.jsxs)(i.li,{children:["setting many other connection options (see ",(0,r.jsx)(i.a,{href:"https://github.com/silverqx/TinyORM/blob/main/drivers/mysql/src/orm/drivers/mysql/mysqldriver_p.cpp",children:(0,r.jsx)(i.code,{children:"mysqldriver_p.cpp"})}),")"]}),"\n",(0,r.jsxs)(i.li,{children:["building and linking against the ",(0,r.jsx)(i.a,{href:"https://mariadb.com/kb/en/mariadb-connector-c/",children:(0,r.jsx)(i.code,{children:"MariaDB Connector/C"})})]}),"\n",(0,r.jsx)(i.li,{children:"transactions"}),"\n",(0,r.jsxs)(i.li,{children:["re-using the current ",(0,r.jsx)(i.code,{children:"SqlQuery"})," instance to re-execute the same or another query"]}),"\n",(0,r.jsx)(i.li,{children:"detaching from the result set (associated to release memory)"}),"\n",(0,r.jsxs)(i.li,{children:["query size, number of affected rows, last inserted ID, testing ",(0,r.jsx)(i.code,{children:"isNull()"}),", ..."]}),"\n",(0,r.jsxs)(i.li,{children:["all ",(0,r.jsx)(i.strong,{children:"3366 unit tests"})," passed \ud83d\ude2e"]}),"\n"]}),"\n",(0,r.jsx)(i.admonition,{type:"info",children:(0,r.jsxs)(i.p,{children:["Currently, only the ",(0,r.jsx)(i.code,{children:"MySQL"})," database driver is supported and finished."]})}),"\n",(0,r.jsx)(i.admonition,{type:"info",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TinyDrivers"})," can only be built with ",(0,r.jsx)(i.code,{children:"Qt v6"}),", ",(0,r.jsx)(i.code,{children:"Qt v5.15"})," isn't supported."]})}),"\n",(0,r.jsx)(i.admonition,{type:"note",children:(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TinyDrivers"})," library supports both build systems ",(0,r.jsx)(i.code,{children:"qmake"})," and also ",(0,r.jsx)(i.code,{children:"CMake"}),"."]})}),"\n",(0,r.jsx)(i.h2,{id:"differences-from-qtsql",children:"Differences from QtSql"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TinyDrivers"})," doesn't return errors the the same way as the ",(0,r.jsx)(i.code,{children:"QtSql"})," module, which means return a ",(0,r.jsx)(i.code,{children:"bool"})," and if it's the result ",(0,r.jsx)(i.code,{children:"false"})," then obtain the ",(0,r.jsx)(i.code,{children:"SqlError"})," instance using the ",(0,r.jsx)(i.code,{children:"lastError()"})," method from ",(0,r.jsx)(i.code,{children:"SqlDatabase"})," or ",(0,r.jsx)(i.code,{children:"SqlQuery"})," instances. Instead, it throws exceptions, and methods returning a ",(0,r.jsx)(i.code,{children:"bool"})," type to report an error state always return ",(0,r.jsx)(i.code,{children:"true"}),"."]}),"\n",(0,r.jsx)(i.h5,{id:"naming-conventions",children:"Naming conventions"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"QtSql"})," ",(0,r.jsx)("small",{children:"module"})," -> ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," ",(0,r.jsx)("small",{children:"library"})]}),"\n",(0,r.jsxs)(i.li,{children:[(0,r.jsx)(i.code,{children:"QMYSQL"})," ",(0,r.jsx)("small",{children:"driver"})," -> ",(0,r.jsx)(i.code,{children:"TinyMySql"})," ",(0,r.jsx)("small",{children:"driver"})]}),"\n"]}),"\n",(0,r.jsx)(i.h5,{id:"mysql-driver",children:"MySQL driver"}),"\n",(0,r.jsxs)(i.p,{children:["The following describes the differences between ",(0,r.jsx)(i.code,{children:"QMYSQL"})," and ",(0,r.jsx)(i.code,{children:"TinyMySql"})," drivers."]}),"\n",(0,r.jsxs)(i.p,{children:["The ",(0,r.jsx)(i.code,{children:"QMYSQL"})," driver doesn't support setting ",(0,r.jsx)(i.code,{children:"MySQL"})," non-flag ",(0,r.jsx)(i.a,{href:"https://dev.mysql.com/doc/c-api/en/mysql-options.html",children:"connection options"})," like ",(0,r.jsx)(i.code,{children:"MYSQL_OPT_RECONNECT"})," without the value, it needs to be defined with value like ",(0,r.jsx)(i.code,{children:"=1"})," or ",(0,r.jsx)(i.code,{children:"=TRUE"})," (case-sensitive), only real flag options like ",(0,r.jsx)(i.code,{children:"CLIENT_INTERACTIVE"})," can be set without the value and ",(0,r.jsx)(i.code,{children:"="})," character."]}),"\n",(0,r.jsxs)(i.p,{children:["On the other hand, the ",(0,r.jsx)(i.code,{children:"TinyMySql"})," driver allows setting non-flag ",(0,r.jsx)(i.a,{href:"https://dev.mysql.com/doc/c-api/en/mysql-options.html",children:"connection options"})," options without the value and ",(0,r.jsx)(i.code,{children:"="})," character, which are considered enabled (ON or TRUE)."]}),"\n",(0,r.jsx)(i.h5,{id:"removed-features",children:"Removed features"}),"\n",(0,r.jsxs)(i.p,{children:["Simulation of prepared statements while calling ",(0,r.jsx)(i.code,{children:"SqlQuery::exec(QString)"}),", this functionality is useless because you can call regular prepared statements using ",(0,r.jsx)(i.code,{children:"SqlQuery::prepare(QString)"})," and then ",(0,r.jsx)(i.code,{children:"SqlQuery::exec()"}),"."]}),"\n",(0,r.jsx)(i.h5,{id:"missing-features",children:"Missing features"}),"\n",(0,r.jsxs)(i.p,{children:["Fetching multiple result sets using ",(0,r.jsx)(i.code,{children:"SqlQuery::nextResult()"}),". Multiple statement queries are supported they will be executed correctly (they can return multiple result sets), but only the first result set can be fetched currently. However, destroying multiple result sets is handled correctly."]}),"\n",(0,r.jsx)(i.h3,{id:"build-system",children:"Build system"}),"\n",(0,r.jsxs)(i.p,{children:["Another difference is that you can build the ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," and its SQL drivers (",(0,r.jsx)(i.code,{children:"TinyMySql"}),") in 3 different ways; ",(0,r.jsx)(i.code,{children:"Shared"}),", ",(0,r.jsx)(i.code,{children:"Static"}),", and as a ",(0,r.jsx)(i.code,{children:"Loadable"})," library at runtime using ",(0,r.jsx)(i.code,{children:"LoadLibrary()"})," on Windows or ",(0,r.jsx)(i.code,{children:"dlopen()"})," on Linux."]}),"\n",(0,r.jsxs)(i.h5,{id:"the-shared-library-build",children:["The ",(0,r.jsx)(i.code,{children:"Shared"})," library build"]}),"\n",(0,r.jsxs)(i.p,{children:["It builds two shared libraries, the ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," shared library that contains the core/common code and the ",(0,r.jsx)(i.code,{children:"TinyMySql"})," shared library that contains ",(0,r.jsx)(i.code,{children:"MySQL"})," implementation. The ",(0,r.jsx)(i.code,{children:"TinyOrm"})," links only against the ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," shared library and ",(0,r.jsx)(i.code,{children:"TinyMySql"})," is a private implementation."]}),"\n",(0,r.jsxs)(i.h5,{id:"the-static-build",children:["The ",(0,r.jsx)(i.code,{children:"Static"})," build"]}),"\n",(0,r.jsxs)(i.p,{children:["It builds one ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," static archive that contains the core/common code and SQL drivers (",(0,r.jsx)(i.code,{children:"TinyMySql"}),"). This static library is linked or merged into the ",(0,r.jsx)(i.code,{children:"TinyOrm"})," shared or static library (both variants are supported)."]}),"\n",(0,r.jsxs)(i.h5,{id:"the-loadable-sql-drivers-build",children:["The ",(0,r.jsx)(i.code,{children:"Loadable"})," SQL drivers build"]}),"\n",(0,r.jsxs)(i.p,{children:["It builds two shared libraries, the ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," shared library that contains the core/common code and ",(0,r.jsx)(i.code,{children:"TinyMySql"})," shared library (module) that contains ",(0,r.jsx)(i.code,{children:"MySQL"})," implementation that is loaded at runtime using ",(0,r.jsx)(i.code,{children:"LoadLibrary()"})," on Windows or ",(0,r.jsx)(i.code,{children:"dlopen()"})," on Linux. The SQL driver library loader throws an exception if it cannot find this library at runtime."]}),"\n",(0,r.jsx)(i.admonition,{type:"info",children:(0,r.jsxs)(i.p,{children:["The ",(0,r.jsx)(i.code,{children:"TinyMySql"})," links directly against the ",(0,r.jsx)(i.code,{children:"MySQL C connector"})," (",(0,r.jsx)(i.code,{children:"libmysql"})," or ",(0,r.jsx)(i.code,{children:"mysqlclient"})," library)."]})}),"\n",(0,r.jsxs)(i.h4,{id:"cmakeqmake-build-options",children:[(0,r.jsx)(i.code,{children:"CMake"}),"/",(0,r.jsx)(i.code,{children:"qmake"})," build options"]}),"\n",(0,r.jsxs)(i.h5,{id:"for-cmake",children:["For ",(0,r.jsx)(i.code,{children:"CMake"})]}),"\n",(0,r.jsxs)(i.p,{children:["See ",(0,r.jsx)(i.a,{href:"/building/tinyorm#cmake-build-options",children:"CMake build options"}),", related ",(0,r.jsx)(i.code,{children:"CMake"})," build options are:",(0,r.jsx)("br",{}),(0,r.jsx)(i.a,{href:"/building/tinyorm#BUILD_DRIVERS",children:(0,r.jsx)(i.code,{children:"BUILD_DRIVERS"})}),", ",(0,r.jsx)(i.a,{href:"/building/tinyorm#BUILD_MYSQL_DRIVER",children:(0,r.jsx)(i.code,{children:"BUILD_MYSQL_DRIVER"})}),", and ",(0,r.jsx)(i.a,{href:"/building/tinyorm#DRIVERS_TYPE",children:(0,r.jsx)(i.code,{children:"DRIVERS_TYPE"})})]}),"\n",(0,r.jsxs)(i.p,{children:["To control shared and static build use ",(0,r.jsx)(i.a,{href:"https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html",children:(0,r.jsx)(i.code,{children:"BUILD_SHARED_LIBS"})})," ",(0,r.jsx)(i.code,{children:"CMake"})," configuration option."]}),"\n",(0,r.jsxs)(i.h5,{id:"for-qmake",children:["For ",(0,r.jsx)(i.code,{children:"qmake"})]}),"\n",(0,r.jsxs)(i.p,{children:["See ",(0,r.jsx)(i.a,{href:"/building/tinyorm#qmake-build-options",children:"qmake build options"}),", related ",(0,r.jsx)(i.code,{children:"qmake"})," configuration options are:",(0,r.jsx)("br",{}),(0,r.jsx)(i.a,{href:"/building/tinyorm#build_loadable_drivers",children:(0,r.jsx)(i.code,{children:"build_loadable_drivers"})}),", ",(0,r.jsx)(i.a,{href:"/building/tinyorm#build_mysql_driver",children:(0,r.jsx)(i.code,{children:"build_mysql_driver"})}),", ",(0,r.jsx)(i.a,{href:"/building/tinyorm#build_shared_drivers",children:(0,r.jsx)(i.code,{children:"build_shared_drivers"})}),", and ",(0,r.jsx)(i.a,{href:"/building/tinyorm#build_static_drivers",children:(0,r.jsx)(i.code,{children:"build_static_drivers"})})]}),"\n",(0,r.jsxs)(i.p,{children:["To control shared and static build use ",(0,r.jsx)(i.a,{href:"/building/tinyorm#static",children:(0,r.jsx)(i.code,{children:"static"})})," ",(0,r.jsx)(i.code,{children:"qmake"})," ",(0,r.jsx)(i.a,{href:"https://doc.qt.io/qt/qmake-variable-reference.html#config",children:"configuration option"}),"."]}),"\n",(0,r.jsx)(i.h3,{id:"performance",children:"Performance"}),"\n",(0,r.jsxs)(i.p,{children:["Performance is several milliseconds faster compared to ",(0,r.jsx)(i.code,{children:"QtSql"})," with the ",(0,r.jsx)(i.code,{children:"QMYSQL"})," driver. It was tuned using the ",(0,r.jsx)(i.code,{children:"KCacheGrind"})," to be so. It's ~40ms faster on ",(0,r.jsx)(i.a,{href:"https://github.com/silverqx/TinyOrmPlayground",children:(0,r.jsx)(i.code,{children:"TinyOrmPlayground"})})," project with ",(0,r.jsx)(i.strong,{children:"620"})," database queries compiled using ",(0,r.jsx)(i.code,{children:"GCC v13.2.1"})," Debug build on Linux. Similar results can be expected on other platforms but it's not guaranteed."]}),"\n",(0,r.jsxs)(i.p,{children:["This means performance is very similar to ",(0,r.jsx)(i.code,{children:"QtSql"}),". There is not much to speed up because ",(0,r.jsx)(i.code,{children:"TinyDrivers"})," code is swift and 90% of the time is spent inside the ",(0,r.jsx)(i.a,{href:"https://dev.mysql.com/doc/c-api/en/",children:(0,r.jsx)(i.code,{children:"MySQL C API"})})," because we always have to wait for the database server, especially when creating database connections using eg. ",(0,r.jsx)(i.a,{href:"https://dev.mysql.com/doc/c-api/en/mysql-real-connect.html",children:(0,r.jsx)(i.code,{children:"mysql_real_connect()"})})," (this function is king among the slowest functions \ud83d\ude0e, which is understandable of course)."]}),"\n",(0,r.jsx)(i.h2,{id:"internals",children:"Internals"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TinyDrivers"})," internal design can be divided into 3 different layers:"]}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:"Driver layer"}),"\n",(0,r.jsx)(i.li,{children:"SQL API layer"}),"\n",(0,r.jsx)(i.li,{children:"Public API layer"}),"\n"]}),"\n",(0,r.jsxs)(i.p,{children:["The Driver layer is eg. ",(0,r.jsx)(i.code,{children:"TinyMySql"})," library which is responsible for communicating with the underlying database driver (eg. ",(0,r.jsx)(i.a,{href:"https://dev.mysql.com/doc/c-api/en/",children:(0,r.jsx)(i.code,{children:"MySQL C API"})}),")."]}),"\n",(0,r.jsx)(i.p,{children:"The SQL API layer is a semi-layer that glues everything up and sits between the Public interface API and the Driver layer."}),"\n",(0,r.jsxs)(i.p,{children:["The Public interface API layer are the end classes like ",(0,r.jsx)(i.code,{children:"SqlDatabase"})," and ",(0,r.jsx)(i.code,{children:"SqlQuery"})," which are exposed to the end user."]}),"\n",(0,r.jsx)(i.h5,{id:"sqldatabase",children:"SqlDatabase"}),"\n",(0,r.jsxs)(i.p,{children:["One more thing worth mentioning is the ",(0,r.jsx)(i.code,{children:"SqlDatabase"})," API. It's one class that has two responsibilities! All static methods act as the database connection manager and an instance of the ",(0,r.jsx)(i.code,{children:"SqlDatabase"})," represents a physical database connection. It's not a good design because it breaks the ",(0,r.jsx)(i.a,{href:"https://en.wikipedia.org/wiki/Single_responsibility_principle",children:"Single Responsibility principle"}),", but it's what it is."]}),"\n",(0,r.jsx)(i.h5,{id:"namespaces",children:"Namespaces"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.code,{children:"TinyDrivers"})," classes are defined in the ",(0,r.jsx)(i.code,{children:"Orm::Drivers"})," namespace and ",(0,r.jsx)(i.code,{children:"TinyMySql"})," classes in the ",(0,r.jsx)(i.code,{children:"Orm::Drivers::MySql"})," namespace."]}),"\n",(0,r.jsx)(i.h5,{id:"documentation",children:"Documentation"}),"\n",(0,r.jsxs)(i.p,{children:["For all other APIs you can follow the ",(0,r.jsx)(i.a,{href:"https://doc.qt.io/qt/qtsql-index.html",children:"QtSql documentation"})," as the API is 1:1. The exception is of course the build system, ",(0,r.jsx)(i.code,{children:"TinyOrm"})," has its own build system that doesn't follow the ",(0,r.jsx)(i.code,{children:"QtSql"})," module."]})]})}function h(e={}){const{wrapper:i}={...(0,s.R)(),...e.components};return i?(0,r.jsx)(i,{...e,children:(0,r.jsx)(o,{...e})}):o(e)}},8453:(e,i,n)=>{n.d(i,{R:()=>t,x:()=>l});var r=n(6540);const s={},d=r.createContext(s);function t(e){const i=r.useContext(d);return r.useMemo((function(){return"function"==typeof e?e(i):{...i,...e}}),[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:t(e.components),r.createElement(d.Provider,{value:i},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cb1e72f9.ebe13fc2.js b/assets/js/cb1e72f9.ebe13fc2.js deleted file mode 100644 index ef8ee5f45..000000000 --- a/assets/js/cb1e72f9.ebe13fc2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[684],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?r(Object(n),!0).forEach((function(t){i(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):r(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,a,i=function(e,t){if(null==e)return{};var n,a,i={},r=Object.keys(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a<r.length;a++)n=r[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var d=a.createContext({}),s=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(d.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,d=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),m=s(n),c=i,h=m["".concat(d,".").concat(c)]||m[c]||u[c]||r;return n?a.createElement(h,l(l({ref:t},p),{},{components:n})):a.createElement(h,l({ref:t},p))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=c;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[m]="string"==typeof e?e:i,l[1]=o;for(var s=2;s<r;s++)l[s]=n[s];return a.createElement.apply(null,l)}return a.createElement.apply(null,n)}c.displayName="MDXCreateElement"},5955:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var a=n(7462),i=(n(7294),n(3905));const r={sidebar_position:0,sidebar_label:"Getting Started",description:"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.",keywords:["c++ orm","database","getting started","tinydrivers","sql drivers"]},l="TinyDrivers: Getting Started",o={unversionedId:"tinydrivers/getting-started",id:"tinydrivers/getting-started",title:"TinyDrivers: Getting Started",description:"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.",source:"@site/docs/tinydrivers/getting-started.mdx",sourceDirName:"tinydrivers",slug:"/tinydrivers/getting-started",permalink:"/tinydrivers/getting-started",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/tinydrivers/getting-started.mdx",tags:[],version:"current",sidebarPosition:0,frontMatter:{sidebar_position:0,sidebar_label:"Getting Started",description:"The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. Swapping is controlled by the qmake and CMake build system options. It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.",keywords:["c++ orm","database","getting started","tinydrivers","sql drivers"]},sidebar:"tinyormSidebar",previous:{title:"Serialization",permalink:"/tinyorm/serialization"},next:{title:"TinyORM",permalink:"/building/tinyorm"}},d={},s=[{value:"Introduction",id:"introduction",level:2},{value:"Features summary",id:"features-summary",level:5},{value:"Differences from QtSql",id:"differences-from-qtsql",level:2},{value:"Naming conventions",id:"naming-conventions",level:5},{value:"MySQL driver",id:"mysql-driver",level:5},{value:"Removed features",id:"removed-features",level:5},{value:"Missing features",id:"missing-features",level:5},{value:"Build system",id:"build-system",level:3},{value:"The <code>Shared</code> library build",id:"the-shared-library-build",level:5},{value:"The <code>Static</code> build",id:"the-static-build",level:5},{value:"The <code>Loadable</code> SQL drivers build",id:"the-loadable-sql-drivers-build",level:5},{value:"<code>CMake</code>/<code>qmake</code> build options",id:"cmakeqmake-build-options",level:4},{value:"For <code>CMake</code>",id:"for-cmake",level:5},{value:"For <code>qmake</code>",id:"for-qmake",level:5},{value:"Performance",id:"performance",level:3},{value:"Internals",id:"internals",level:2},{value:"SqlDatabase",id:"sqldatabase",level:5},{value:"Namespaces",id:"namespaces",level:5},{value:"Documentation",id:"documentation",level:5}],p={toc:s},m="wrapper";function u(e){let{components:t,...n}=e;return(0,i.kt)(m,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"tinydrivers-getting-started"},"TinyDrivers: Getting Started"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#differences-from-qtsql"},"Differences from QtSql"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#build-system"},"Build system")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#performance"},"Performance")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#internals"},"Internals"))),(0,i.kt)("h2",{id:"introduction"},"Introduction"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," library is an underlying SQL database layer for ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyORM"),". It can be used instead of the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql")," module, can be ",(0,i.kt)("u",null,(0,i.kt)("strong",{parentName:"p"},"swapped"))," at compile time, and has ",(0,i.kt)("strong",{parentName:"p"},"1:1")," API as the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql")," module. \ud83d\ude2e Swapping is controlled by the ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," build system options."),(0,i.kt)("p",null,"It was designed to drop the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql")," dependency while maintaining backward compatibility and without the need for any code changes after the swap."),(0,i.kt)("h5",{id:"features-summary"},"Features summary"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"both, normal and prepared statements are supported"),(0,i.kt)("li",{parentName:"ul"},"TLS/SSL connections using ",(0,i.kt)("a",{parentName:"li",href:"https://dev.mysql.com/doc/c-api/en/mysql-options.html"},(0,i.kt)("inlineCode",{parentName:"a"},"MYSQL_OPT_SSL_MODE"))," (verify_ca, verify_identity) \ud83d\udd25"),(0,i.kt)("li",{parentName:"ul"},"setting many other connection options (see ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/silverqx/TinyORM/blob/main/drivers/mysql/src/orm/drivers/mysql/mysqldriver_p.cpp"},(0,i.kt)("inlineCode",{parentName:"a"},"mysqldriver_p.cpp")),")"),(0,i.kt)("li",{parentName:"ul"},"building and linking against the ",(0,i.kt)("a",{parentName:"li",href:"https://mariadb.com/kb/en/mariadb-connector-c/"},(0,i.kt)("inlineCode",{parentName:"a"},"MariaDB Connector/C"))),(0,i.kt)("li",{parentName:"ul"},"transactions"),(0,i.kt)("li",{parentName:"ul"},"re-using the current ",(0,i.kt)("inlineCode",{parentName:"li"},"SqlQuery")," instance to re-execute the same or another query"),(0,i.kt)("li",{parentName:"ul"},"detaching from the result set (associated to release memory)"),(0,i.kt)("li",{parentName:"ul"},"query size, number of affected rows, last inserted ID, testing ",(0,i.kt)("inlineCode",{parentName:"li"},"isNull()"),", ..."),(0,i.kt)("li",{parentName:"ul"},"all ",(0,i.kt)("strong",{parentName:"li"},"3366 unit tests")," passed \ud83d\ude2e")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Currently, only the ",(0,i.kt)("inlineCode",{parentName:"p"},"MySQL")," database driver is supported and finished.")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," can only be built with ",(0,i.kt)("inlineCode",{parentName:"p"},"Qt v6"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"Qt v5.15")," isn't supported.")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," library supports both build systems ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," and also ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake"),".")),(0,i.kt)("h2",{id:"differences-from-qtsql"},"Differences from QtSql"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," doesn't return errors the the same way as the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql")," module, which means return a ",(0,i.kt)("inlineCode",{parentName:"p"},"bool")," and if it's the result ",(0,i.kt)("inlineCode",{parentName:"p"},"false")," then obtain the ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlError")," instance using the ",(0,i.kt)("inlineCode",{parentName:"p"},"lastError()")," method from ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlDatabase")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlQuery")," instances. Instead, it throws exceptions, and methods returning a ",(0,i.kt)("inlineCode",{parentName:"p"},"bool")," type to report an error state always return ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),"."),(0,i.kt)("h5",{id:"naming-conventions"},"Naming conventions"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"QtSql")," ",(0,i.kt)("small",null,"module")," -> ",(0,i.kt)("inlineCode",{parentName:"li"},"TinyDrivers")," ",(0,i.kt)("small",null,"library")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"QMYSQL")," ",(0,i.kt)("small",null,"driver")," -> ",(0,i.kt)("inlineCode",{parentName:"li"},"TinyMySql")," ",(0,i.kt)("small",null,"driver"))),(0,i.kt)("h5",{id:"mysql-driver"},"MySQL driver"),(0,i.kt)("p",null,"The following describes the differences between ",(0,i.kt)("inlineCode",{parentName:"p"},"QMYSQL")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," drivers."),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"QMYSQL")," driver doesn't support setting ",(0,i.kt)("inlineCode",{parentName:"p"},"MySQL")," non-flag ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/c-api/en/mysql-options.html"},"connection options")," like ",(0,i.kt)("inlineCode",{parentName:"p"},"MYSQL_OPT_RECONNECT")," without the value, it needs to be defined with value like ",(0,i.kt)("inlineCode",{parentName:"p"},"=1")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"=TRUE")," (case-sensitive), only real flag options like ",(0,i.kt)("inlineCode",{parentName:"p"},"CLIENT_INTERACTIVE")," can be set without the value and ",(0,i.kt)("inlineCode",{parentName:"p"},"=")," character."),(0,i.kt)("p",null,"On the other hand, the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," driver allows setting non-flag ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/c-api/en/mysql-options.html"},"connection options")," options without the value and ",(0,i.kt)("inlineCode",{parentName:"p"},"=")," character, which are considered enabled (ON or TRUE)."),(0,i.kt)("h5",{id:"removed-features"},"Removed features"),(0,i.kt)("p",null,"Simulation of prepared statements while calling ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlQuery::exec(QString)"),", this functionality is useless because you can call regular prepared statements using ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlQuery::prepare(QString)")," and then ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlQuery::exec()"),"."),(0,i.kt)("h5",{id:"missing-features"},"Missing features"),(0,i.kt)("p",null,"Fetching multiple result sets using ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlQuery::nextResult()"),". Multiple statement queries are supported they will be executed correctly (they can return multiple result sets), but only the first result set can be fetched currently. However, destroying multiple result sets is handled correctly."),(0,i.kt)("h3",{id:"build-system"},"Build system"),(0,i.kt)("p",null,"Another difference is that you can build the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," and its SQL drivers (",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql"),") in 3 different ways; ",(0,i.kt)("inlineCode",{parentName:"p"},"Shared"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"Static"),", and as a ",(0,i.kt)("inlineCode",{parentName:"p"},"Loadable")," library at runtime using ",(0,i.kt)("inlineCode",{parentName:"p"},"LoadLibrary()")," on Windows or ",(0,i.kt)("inlineCode",{parentName:"p"},"dlopen()")," on Linux."),(0,i.kt)("h5",{id:"the-shared-library-build"},"The ",(0,i.kt)("inlineCode",{parentName:"h5"},"Shared")," library build"),(0,i.kt)("p",null,"It builds two shared libraries, the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," shared library that contains the core/common code and the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," shared library that contains ",(0,i.kt)("inlineCode",{parentName:"p"},"MySQL")," implementation. The ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyOrm")," links only against the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," shared library and ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," is a private implementation."),(0,i.kt)("h5",{id:"the-static-build"},"The ",(0,i.kt)("inlineCode",{parentName:"h5"},"Static")," build"),(0,i.kt)("p",null,"It builds one ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," static archive that contains the core/common code and SQL drivers (",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql"),"). This static library is linked or merged into the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyOrm")," shared or static library (both variants are supported)."),(0,i.kt)("h5",{id:"the-loadable-sql-drivers-build"},"The ",(0,i.kt)("inlineCode",{parentName:"h5"},"Loadable")," SQL drivers build"),(0,i.kt)("p",null,"It builds two shared libraries, the ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," shared library that contains the core/common code and ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," shared library (module) that contains ",(0,i.kt)("inlineCode",{parentName:"p"},"MySQL")," implementation that is loaded at runtime using ",(0,i.kt)("inlineCode",{parentName:"p"},"LoadLibrary()")," on Windows or ",(0,i.kt)("inlineCode",{parentName:"p"},"dlopen()")," on Linux. The SQL driver library loader throws an exception if it cannot find this library at runtime."),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," links directly against the ",(0,i.kt)("inlineCode",{parentName:"p"},"MySQL C connector")," (",(0,i.kt)("inlineCode",{parentName:"p"},"libmysql")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"mysqlclient")," library).")),(0,i.kt)("h4",{id:"cmakeqmake-build-options"},(0,i.kt)("inlineCode",{parentName:"h4"},"CMake"),"/",(0,i.kt)("inlineCode",{parentName:"h4"},"qmake")," build options"),(0,i.kt)("h5",{id:"for-cmake"},"For ",(0,i.kt)("inlineCode",{parentName:"h5"},"CMake")),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#cmake-build-options"},"CMake build options"),", related ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," build options are:",(0,i.kt)("br",null),(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#BUILD_DRIVERS"},(0,i.kt)("inlineCode",{parentName:"a"},"BUILD_DRIVERS")),", ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#BUILD_MYSQL_DRIVER"},(0,i.kt)("inlineCode",{parentName:"a"},"BUILD_MYSQL_DRIVER")),", and ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#DRIVERS_TYPE"},(0,i.kt)("inlineCode",{parentName:"a"},"DRIVERS_TYPE"))),(0,i.kt)("p",null,"To control shared and static build use ",(0,i.kt)("a",{parentName:"p",href:"https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html"},(0,i.kt)("inlineCode",{parentName:"a"},"BUILD_SHARED_LIBS"))," ",(0,i.kt)("inlineCode",{parentName:"p"},"CMake")," configuration option."),(0,i.kt)("h5",{id:"for-qmake"},"For ",(0,i.kt)("inlineCode",{parentName:"h5"},"qmake")),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#qmake-build-options"},"qmake build options"),", related ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," configuration options are:",(0,i.kt)("br",null),(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#build_loadable_drivers"},(0,i.kt)("inlineCode",{parentName:"a"},"build_loadable_drivers")),", ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#build_mysql_driver"},(0,i.kt)("inlineCode",{parentName:"a"},"build_mysql_driver")),", ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#build_shared_drivers"},(0,i.kt)("inlineCode",{parentName:"a"},"build_shared_drivers")),", and ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#build_static_drivers"},(0,i.kt)("inlineCode",{parentName:"a"},"build_static_drivers"))),(0,i.kt)("p",null,"To control shared and static build use ",(0,i.kt)("a",{parentName:"p",href:"/building/tinyorm#static"},(0,i.kt)("inlineCode",{parentName:"a"},"static"))," ",(0,i.kt)("inlineCode",{parentName:"p"},"qmake")," ",(0,i.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qmake-variable-reference.html#config"},"configuration option"),"."),(0,i.kt)("h3",{id:"performance"},"Performance"),(0,i.kt)("p",null,"Performance is several milliseconds faster compared to ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql")," with the ",(0,i.kt)("inlineCode",{parentName:"p"},"QMYSQL")," driver. It was tuned using the ",(0,i.kt)("inlineCode",{parentName:"p"},"KCacheGrind")," to be so. It's ~40ms faster on ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyOrmPlayground"},(0,i.kt)("inlineCode",{parentName:"a"},"TinyOrmPlayground"))," project with ",(0,i.kt)("strong",{parentName:"p"},"620")," database queries compiled using ",(0,i.kt)("inlineCode",{parentName:"p"},"GCC v13.2.1")," Debug build on Linux. Similar results can be expected on other platforms but it's not guaranteed."),(0,i.kt)("p",null,"This means performance is very similar to ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql"),". There is not much to speed up because ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," code is swift and 90% of the time is spent inside the ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/c-api/en/"},(0,i.kt)("inlineCode",{parentName:"a"},"MySQL C API"))," because we always have to wait for the database server, especially when creating database connections using eg. ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/c-api/en/mysql-real-connect.html"},(0,i.kt)("inlineCode",{parentName:"a"},"mysql_real_connect()"))," (this function is king among the slowest functions \ud83d\ude0e, which is understandable of course)."),(0,i.kt)("h2",{id:"internals"},"Internals"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," internal design can be divided into 3 different layers:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Driver layer"),(0,i.kt)("li",{parentName:"ul"},"SQL API layer"),(0,i.kt)("li",{parentName:"ul"},"Public API layer")),(0,i.kt)("p",null,"The Driver layer is eg. ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," library which is responsible for communicating with the underlying database driver (eg. ",(0,i.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/c-api/en/"},(0,i.kt)("inlineCode",{parentName:"a"},"MySQL C API")),")."),(0,i.kt)("p",null,"The SQL API layer is a semi-layer that glues everything up and sits between the Public interface API and the Driver layer."),(0,i.kt)("p",null,"The Public interface API layer are the end classes like ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlDatabase")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlQuery")," which are exposed to the end user."),(0,i.kt)("h5",{id:"sqldatabase"},"SqlDatabase"),(0,i.kt)("p",null,"One more thing worth mentioning is the ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlDatabase")," API. It's one class that has two responsibilities! All static methods act as the database connection manager and an instance of the ",(0,i.kt)("inlineCode",{parentName:"p"},"SqlDatabase")," represents a physical database connection. It's not a good design because it breaks the ",(0,i.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Single_responsibility_principle"},"Single Responsibility principle"),", but it's what it is."),(0,i.kt)("h5",{id:"namespaces"},"Namespaces"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," classes are defined in the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Drivers")," namespace and ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyMySql")," classes in the ",(0,i.kt)("inlineCode",{parentName:"p"},"Orm::Drivers::MySql")," namespace."),(0,i.kt)("h5",{id:"documentation"},"Documentation"),(0,i.kt)("p",null,"For all other APIs you can follow the ",(0,i.kt)("a",{parentName:"p",href:"https://doc.qt.io/qt/qtsql-index.html"},"QtSql documentation")," as the API is 1:1. The exception is of course the build system, ",(0,i.kt)("inlineCode",{parentName:"p"},"TinyOrm")," has its own build system that doesn't follow the ",(0,i.kt)("inlineCode",{parentName:"p"},"QtSql")," module."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cbe663fe.3147a933.js b/assets/js/cbe663fe.3147a933.js new file mode 100644 index 000000000..0fc2fe8c8 --- /dev/null +++ b/assets/js/cbe663fe.3147a933.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[995],{4380:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});var r=s(4848),t=s(8453);const a={sidebar_position:1,sidebar_label:"Query Builder",description:"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.",keywords:["c++ orm","sql","c++ sql","c++ query builder","database","query builder","tinyorm"]},i="Database: Query Builder",o={id:"database/query-builder",title:"Database: Query Builder",description:"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.",source:"@site/docs/database/query-builder.mdx",sourceDirName:"database",slug:"/database/query-builder",permalink:"/database/query-builder",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,sidebar_label:"Query Builder",description:"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.",keywords:["c++ orm","sql","c++ sql","c++ query builder","database","query builder","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Getting Started",permalink:"/database/getting-started"},next:{title:"Migrations",permalink:"/database/migrations"}},d={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Running Database Queries",id:"running-database-queries",level:2},{value:"Retrieving All Rows From A Table",id:"retrieving-all-rows-from-a-table",level:4},{value:"Retrieving A Single Row / Column From A Table",id:"retrieving-a-single-row--column-from-a-table",level:4},{value:"Retrieving A List Of Column Values",id:"retrieving-a-list-of-column-values",level:4},{value:"Concatenate column values",id:"concatenate-column-values",level:4},{value:"Chunking Results",id:"chunking-results",level:3},{value:"Aggregates",id:"aggregates",level:3},{value:"Determining If Records Exist",id:"determining-if-records-exist",level:4},{value:"Select Statements",id:"select-statements",level:2},{value:"Specifying A Select Clause",id:"specifying-a-select-clause",level:4},{value:"Raw Expressions",id:"raw-expressions",level:2},{value:"Raw Methods",id:"raw-methods",level:3},{value:"<code>selectRaw</code>",id:"selectraw",level:4},{value:"<code>fromRaw</code>",id:"fromraw",level:4},{value:"<code>whereRaw / orWhereRaw</code>",id:"whereraw--orwhereraw",level:4},{value:"<code>groupByRaw</code>",id:"groupbyraw",level:3},{value:"<code>havingRaw / orHavingRaw</code>",id:"havingraw--orhavingraw",level:4},{value:"<code>orderByRaw</code>",id:"orderbyraw",level:4},{value:"Joins",id:"joins",level:2},{value:"Inner Join Clause",id:"inner-join-clause",level:4},{value:"Left Join / Right Join Clause",id:"left-join--right-join-clause",level:4},{value:"Cross Join Clause",id:"cross-join-clause",level:4},{value:"Advanced Join Clauses",id:"advanced-join-clauses",level:4},{value:"Subquery Joins",id:"subquery-joins",level:4},{value:"Basic Where Clauses",id:"basic-where-clauses",level:2},{value:"Where Clauses",id:"where-clauses",level:3},{value:"Or Where Clauses",id:"or-where-clauses",level:3},{value:"Condition Operator Overriding",id:"condition-operator-overriding",level:3},{value:"Where Not Clauses",id:"where-not-clauses",level:3},{value:"Additional Where Clauses",id:"additional-where-clauses",level:3},{value:"Logical Grouping",id:"logical-grouping",level:3},{value:"Advanced Where Clauses",id:"advanced-where-clauses",level:2},{value:"Where Exists Clauses",id:"where-exists-clauses",level:3},{value:"Subquery Where Clauses",id:"subquery-where-clauses",level:3},{value:"Ordering, Grouping, Limit & Offset",id:"ordering-grouping-limit-and-offset",level:2},{value:"Ordering",id:"ordering",level:3},{value:"The <code>orderBy</code> Method",id:"the-orderby-method",level:4},{value:"The <code>latest</code> & <code>oldest</code> Methods",id:"the-latest--oldest-methods",level:4},{value:"Random Ordering",id:"random-ordering",level:4},{value:"Removing Existing Orderings",id:"removing-existing-orderings",level:4},{value:"Grouping",id:"grouping",level:3},{value:"The <code>groupBy</code> & <code>having</code> Methods",id:"the-groupby--having-methods",level:4},{value:"Limit & Offset",id:"limit-and-offset",level:3},{value:"The <code>skip</code> & <code>take</code> Methods",id:"the-skip--take-methods",level:4},{value:"Insert Statements",id:"insert-statements",level:2},{value:"Auto-Incrementing IDs",id:"auto-incrementing-ids",level:4},{value:"Upserts",id:"upserts",level:3},{value:"Update Statements",id:"update-statements",level:2},{value:"Update Or Insert",id:"update-or-insert",level:4},{value:"Increment & Decrement",id:"increment-and-decrement",level:3},{value:"Delete Statements",id:"delete-statements",level:2},{value:"Truncate Statement",id:"truncate-statement",level:3},{value:"Table Truncation & PostgreSQL",id:"table-truncation--postgresql",level:4},{value:"Pessimistic Locking",id:"pessimistic-locking",level:2},{value:"Debugging",id:"debugging",level:2}];function c(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,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"database-query-builder",children:"Database: Query Builder"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#introduction",children:"Introduction"})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"#running-database-queries",children:"Running Database Queries"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#chunking-results",children:"Chunking Results"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#aggregates",children:"Aggregates"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#select-statements",children:"Select Statements"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#raw-expressions",children:"Raw Expressions"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#joins",children:"Joins"})}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"#basic-where-clauses",children:"Basic Where Clauses"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#where-clauses",children:"Where Clauses"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#or-where-clauses",children:"Or Where Clauses"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#where-not-clauses",children:"Where Not Clauses"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#additional-where-clauses",children:"Additional Where Clauses"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#condition-operator-overriding",children:"Condition Operator Overriding"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#logical-grouping",children:"Logical Grouping"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"#advanced-where-clauses",children:"Advanced Where Clauses"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#where-exists-clauses",children:"Where Exists Clauses"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#subquery-where-clauses",children:"Subquery Where Clauses"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"#ordering-grouping-limit-and-offset",children:"Ordering, Grouping, Limit & Offset"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#ordering",children:"Ordering"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#grouping",children:"Grouping"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#limit-and-offset",children:"Limit & Offset"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"#insert-statements",children:"Insert Statements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#upserts",children:"Upserts"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"#update-statements",children:"Update Statements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#increment-and-decrement",children:"Increment & Decrement"})}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"#delete-statements",children:"Delete Statements"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#truncate-statement",children:"Truncate Statement"})}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#pessimistic-locking",children:"Pessimistic Locking"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"#debugging",children:"Debugging"})}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,r.jsx)(n.p,{children:"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application."}),"\n",(0,r.jsxs)(n.p,{children:["The TinyORM query builder uses ",(0,r.jsx)(n.code,{children:"QSqlQuery"})," parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings."]}),"\n",(0,r.jsx)(n.admonition,{type:"danger",children:(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"QSqlQuery"}),' does not support binding column names. Therefore, you should never allow user input to dictate the column names referenced by your queries, including "order by" columns.']})}),"\n",(0,r.jsx)(n.admonition,{type:"danger",children:(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"QMYSQL"})," Qt driver contains a bug, if your table contains a ",(0,r.jsx)(n.code,{children:"json"})," column type, then you must explicitly name columns other than ",(0,r.jsx)(n.code,{children:"json"})," columns instead of the ",(0,r.jsx)(n.code,{children:"*"})," shorthand, otherwise, you will get an empty result, or all column values will be invalid QVariant-s, or it may even return half of the columns. The ",(0,r.jsx)(n.code,{children:"QPSQL"})," driver returns correct results and doesn't have problem with ",(0,r.jsx)(n.code,{children:"json"})," columns. It was fixed in the Qt 5.15.12, 6.2.7, 6.5.0 ",(0,r.jsx)(n.a,{href:"https://bugreports.qt.io/browse/QTBUG-101680",children:"QTBUG-101680"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"running-database-queries",children:"Running Database Queries"}),"\n",(0,r.jsx)(n.h4,{id:"retrieving-all-rows-from-a-table",children:"Retrieving All Rows From A Table"}),"\n",(0,r.jsxs)(n.p,{children:["You may use the ",(0,r.jsx)(n.code,{children:"table"})," method provided by the ",(0,r.jsx)(n.code,{children:"DB"})," facade to begin a query. The ",(0,r.jsx)(n.code,{children:"table"})," method returns a fluent query builder instance for the given table, allowing you to chain more constraints onto the query and then finally retrieve the results of the query using the ",(0,r.jsx)(n.code,{children:"get"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\n// Log a list of all of the application\'s users\nauto query = DB::table("users")->get();\n\nwhile (query.next())\n qDebug() << "id :" << query.value("id").toULongLong() << ";"\n << "name :" << query.value("name").toString();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"get"})," method returns a ",(0,r.jsx)(n.code,{children:"QSqlQuery"})," containing the results of the query where each result can be accessed by ",(0,r.jsx)(n.code,{children:"QSqlQuery::next"})," method, look into the ",(0,r.jsx)(n.code,{children:"QSqlQuery"}),' documentation how to obtain results from the "query". You may access each column\'s value by ',(0,r.jsx)(n.code,{children:"QSqlQuery::value"})," method. The first ",(0,r.jsx)(n.code,{children:"bool"})," return value is the value returned from ",(0,r.jsx)(n.code,{children:"QSqlQuery::exec"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include <orm/db.hpp>\n\nauto users = DB::table("users")->get();\n\nwhile(users.next())\n qDebug() << users.value("name").toString();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"retrieving-a-single-row--column-from-a-table",children:"Retrieving A Single Row / Column From A Table"}),"\n",(0,r.jsxs)(n.p,{children:["If you just need to retrieve a single row from a database table, you may use the ",(0,r.jsx)(n.code,{children:"QueryBuilder::first"})," method. This method will return a ",(0,r.jsx)(n.code,{children:"QSqlQuery"})," object, on which was internally called ",(0,r.jsx)(n.code,{children:"QSqlQuery::first"})," method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto user = DB::table("users")->whereEq("name", "John").first();\n\nuser.value("email").toString();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["If you don't need an entire row, you may extract a single value from a record using the ",(0,r.jsx)(n.code,{children:"value"})," method. This method will return the value of the column directly as ",(0,r.jsx)(n.code,{children:"QVariant"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto email = DB::table("users")->whereEq("name", "John").value("email").toString();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["To retrieve a single row by its ",(0,r.jsx)(n.code,{children:"id"})," column value, use the ",(0,r.jsx)(n.code,{children:"find"})," method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto user = DB::table("users")->find(3);\n\nuser.value("email").toString();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"retrieving-a-list-of-column-values",children:"Retrieving A List Of Column Values"}),"\n",(0,r.jsxs)(n.p,{children:["If you would like to retrieve the ",(0,r.jsx)(n.code,{children:"QVector<QVariant>"})," instance containing the values of a single column, you may use the ",(0,r.jsx)(n.code,{children:"pluck"})," method. In this example, we'll retrieve a collection of user titles:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <QDebug>\n\n#include <orm/db.hpp>\n\nconst auto titles = DB::table("users")->pluck("title");\n\nfor (const auto &title : titles)\n qDebug() << title.value<QString>();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may specify the column that the resulting collection should use as its keys by providing a second argument to the ",(0,r.jsx)(n.code,{children:"pluck"})," method, following example returns the ",(0,r.jsx)(n.code,{children:"std::map<QString, QVariant>"}),' of "titles" keyed by "names":']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nauto titles = DB::table("users")->pluck<QString>("title", "name");\n\nfor (auto &&[name, title] : titles)\n qDebug() << name << ":" << title.value<QString>();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may also use ",(0,r.jsx)(n.code,{children:'pluck<quint64>("name", "id")'}),", it returns the ",(0,r.jsx)(n.code,{children:"std::map<quint64, QVariant>"}),' of "names" keyed by its "ids".']}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["This second ",(0,r.jsx)(n.code,{children:"pluck"})," overload returns ",(0,r.jsx)(n.code,{children:"std::map<T, QVariant>"})," so you have to provide a template argument for the key type."]})}),"\n",(0,r.jsx)(n.h4,{id:"concatenate-column-values",children:"Concatenate column values"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"implode"})," method can be used to join column values. For example, you may use this method to concatenate prices with the ",(0,r.jsx)(n.code,{children:", "})," character as the glue:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("orders")->where("price", ">", 100).implode("price", ", ");\n'})}),"\n",(0,r.jsx)(n.h3,{id:"chunking-results",children:"Chunking Results"}),"\n",(0,r.jsxs)(n.p,{children:["If you need to work with thousands of database records, consider using the ",(0,r.jsx)(n.code,{children:"chunk"})," method provided by the ",(0,r.jsx)(n.code,{children:"DB"})," facade. This method retrieves a small chunk of results at a time and feeds each chunk into a lambda expression for processing. For example, let's retrieve the entire ",(0,r.jsx)(n.code,{children:"users"})," table in chunks of 100 records at a time:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)\n{\n while (users.next()) {\n //\n }\n\n return true;\n});\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may stop further chunks from being processed by returning ",(0,r.jsx)(n.code,{children:"false"})," from the closure:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)\n{\n // Process the records...\n\n return false;\n});\n'})}),"\n",(0,r.jsxs)(n.p,{children:["If you are updating database records while chunking results, your chunk results could change in unexpected ways. If you plan to update the retrieved records while chunking, it is always best to use the ",(0,r.jsx)(n.code,{children:"chunkById"})," method instead. This method will automatically paginate the results based on the record's primary key:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")\n ->whereEq("active", false)\n .orderBy("id")\n .chunkById(100, [](QSqlQuery &users, const int /*unused*/)\n {\n while (users.next())\n DB::table("users")\n ->whereEq("id", users.value("id"))\n .update({{"active", true}});\n\n return true;\n });\n'})}),"\n",(0,r.jsx)(n.admonition,{type:"caution",children:(0,r.jsxs)(n.p,{children:["When updating or deleting records inside the chunk lambda expression, any changes to the primary key or foreign keys could affect the chunk query. This could potentially result in records not being included in the chunked results, it can be avoided using the ",(0,r.jsx)(n.code,{children:"chunkById"})," method."]})}),"\n",(0,r.jsx)(n.h3,{id:"aggregates",children:"Aggregates"}),"\n",(0,r.jsxs)(n.p,{children:["The query builder also provides a variety of methods for retrieving aggregate values like ",(0,r.jsx)(n.code,{children:"count"}),", ",(0,r.jsx)(n.code,{children:"max"}),", ",(0,r.jsx)(n.code,{children:"min"}),", ",(0,r.jsx)(n.code,{children:"avg"}),", and ",(0,r.jsx)(n.code,{children:"sum"}),". You may call any of these methods after constructing your query:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nauto users = DB::table("users")->count();\n\nauto price = DB::table("orders")->max("price");\n'})}),"\n",(0,r.jsx)(n.p,{children:"Of course, you may combine these methods with other clauses to fine-tune how your aggregate value is calculated:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto price = DB::table("orders")\n ->whereEq("finalized", 1)\n .avg("price");\n'})}),"\n",(0,r.jsx)(n.h4,{id:"determining-if-records-exist",children:"Determining If Records Exist"}),"\n",(0,r.jsxs)(n.p,{children:["Instead of using the ",(0,r.jsx)(n.code,{children:"count"})," method to determine if any records exist that match your query's constraints, you may use the ",(0,r.jsx)(n.code,{children:"exists"})," and ",(0,r.jsx)(n.code,{children:"doesntExist"})," methods:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'if (DB::table("orders")->whereEq("finalized", 1).exists()) {\n // ...\n}\n\nif (DB::table("orders")->whereEq("finalized", 1).doesntExist()) {\n // ...\n}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"select-statements",children:"Select Statements"}),"\n",(0,r.jsx)(n.h4,{id:"specifying-a-select-clause",children:"Specifying A Select Clause"}),"\n",(0,r.jsxs)(n.p,{children:["You may not always want to select all columns from a database table. Using the ",(0,r.jsx)(n.code,{children:"select"}),' method, you can specify a custom "select" clause for the query:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nauto users = DB::table("users")\n ->select({"name", "email as user_email"})\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"distinct"})," method allows you to force the query to return distinct results:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")->distinct().get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["If you already have a query builder instance and you wish to add a column to its existing select clause, you may use the ",(0,r.jsx)(n.code,{children:"addSelect"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto query = DB::table("users")->select("name");\n\nauto users = query.addSelect("age").get();\n'})}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["You can also pass subqueries to the ",(0,r.jsx)(n.code,{children:"select"})," and ",(0,r.jsx)(n.code,{children:"addSelect"})," methods. A subquery can be a lambda expression, raw string, or the ",(0,r.jsx)(n.code,{children:"QueryBuilder"})," instance."]})}),"\n",(0,r.jsx)(n.h2,{id:"raw-expressions",children:"Raw Expressions"}),"\n",(0,r.jsxs)(n.p,{children:["Sometimes you may need to insert an arbitrary string into a query. To create a raw string expression, you may use the ",(0,r.jsx)(n.code,{children:"raw"})," method provided by the ",(0,r.jsx)(n.code,{children:"DB"})," facade:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->select(DB::raw("count(*) as user_count, status"))\n .where("status", "<>", 1)\n .groupBy("status")\n .get();\n'})}),"\n",(0,r.jsx)(n.admonition,{type:"danger",children:(0,r.jsx)(n.p,{children:"Raw statements will be injected into the query as strings, so you should be extremely careful to avoid creating SQL injection vulnerabilities."})}),"\n",(0,r.jsx)(n.h3,{id:"raw-methods",children:"Raw Methods"}),"\n",(0,r.jsxs)(n.p,{children:["Instead of using the ",(0,r.jsx)(n.code,{children:"DB::raw"})," method, you may also use the following methods to insert a raw expression into various parts of your query. ",(0,r.jsx)(n.strong,{children:"Remember, TinyORM can not guarantee that any query using raw expressions is protected against SQL injection vulnerabilities."})]}),"\n",(0,r.jsx)(n.h4,{id:"selectraw",children:(0,r.jsx)(n.code,{children:"selectRaw"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"selectRaw"})," method can be used in place of ",(0,r.jsx)(n.code,{children:"addSelect(DB::raw(...))"}),". This method accepts an optional vector of bindings as its second argument:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto orders = DB::table("orders")\n ->selectRaw("price * ? as price_with_tax", {1.0825})\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"fromraw",children:(0,r.jsx)(n.code,{children:"fromRaw"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"fromRaw"}),' method may be used to provide a raw string as the value of the "from" clause:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::connection("postgres").query()\n ->fromRaw("(select id, name from users where id < ?) as u", {5})\n .where("id", "<", 3)\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"whereraw--orwhereraw",children:(0,r.jsx)(n.code,{children:"whereRaw / orWhereRaw"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereRaw"})," and ",(0,r.jsx)(n.code,{children:"orWhereRaw"}),' methods can be used to inject a raw "where" clause into your query. These methods accept an optional vector of bindings as their second argument:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto orders = DB::table("orders")\n ->whereRaw("price > IF(state = \\"TX\\", ?, 100)", {200})\n .get();\n'})}),"\n",(0,r.jsx)(n.h3,{id:"groupbyraw",children:(0,r.jsx)(n.code,{children:"groupByRaw"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"groupByRaw"})," method may be used to provide a raw string as the value of the ",(0,r.jsx)(n.code,{children:"group by"})," clause:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto orders = DB::table("orders")\n ->select({"city", "state"})\n .groupByRaw("city, state")\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"havingraw--orhavingraw",children:(0,r.jsx)(n.code,{children:"havingRaw / orHavingRaw"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"havingRaw"})," and ",(0,r.jsx)(n.code,{children:"orHavingRaw"}),' methods may be used to provide a raw string as the value of the "having" clause. These methods accept an optional vector of bindings as their second argument:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto orders = DB::table("orders")\n ->select({"department", DB::raw("SUM(price) as total_sales")})\n .groupBy("department")\n .havingRaw("SUM(price) > ?", {2500})\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"orderbyraw",children:(0,r.jsx)(n.code,{children:"orderByRaw"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"orderByRaw"}),' method may be used to provide a raw string as the value of the "order by" clause:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto orders = DB::table("orders")\n ->orderByRaw("updated_at - created_at DESC")\n .get();\n'})}),"\n",(0,r.jsx)(n.h2,{id:"joins",children:"Joins"}),"\n",(0,r.jsx)(n.h4,{id:"inner-join-clause",children:"Inner Join Clause"}),"\n",(0,r.jsxs)(n.p,{children:['The query builder may also be used to add join clauses to your queries. To perform a basic "inner join", you may use the ',(0,r.jsx)(n.code,{children:"join"})," method on a query builder instance. The first argument passed to the ",(0,r.jsx)(n.code,{children:"join"})," method is the name of the table you need to join to, while the remaining arguments specify the column constraints for the join. You may even join multiple tables in a single query:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n\nauto users = DB::table("users")\n ->join("contacts", "users.id", "=", "contacts.user_id")\n .join("orders", "users.id", "=", "orders.user_id")\n .select({"users.*", "contacts.phone", "orders.price"})\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"left-join--right-join-clause",children:"Left Join / Right Join Clause"}),"\n",(0,r.jsxs)(n.p,{children:['If you would like to perform a "left join" or "right join" instead of an "inner join", use the ',(0,r.jsx)(n.code,{children:"leftJoin"})," or ",(0,r.jsx)(n.code,{children:"rightJoin"})," methods. These methods have the same signature as the ",(0,r.jsx)(n.code,{children:"join"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->leftJoin("posts", "users.id", "=", "posts.user_id")\n .get();\n\nauto users = DB::table("users")\n ->rightJoin("posts", "users.id", "=", "posts.user_id")\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"cross-join-clause",children:"Cross Join Clause"}),"\n",(0,r.jsxs)(n.p,{children:["You may use the ",(0,r.jsx)(n.code,{children:"crossJoin"}),' method to perform a "cross join". Cross joins generate a cartesian product between the first table and the joined table:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto sizes = DB::table("sizes")\n ->crossJoin("colors")\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"advanced-join-clauses",children:"Advanced Join Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["You may also specify more advanced join clauses. To get started, pass a lambda expression as the second argument to the ",(0,r.jsx)(n.code,{children:"join"})," method. The lambda expression will receive a ",(0,r.jsx)(n.code,{children:"Orm::Query::JoinClause"}),' instance which allows you to specify constraints on the "join" clause:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include <orm/db.hpp>\n#include <orm/query/joinclause.hpp>\n\nDB::table("users")\n ->join("contacts", [](auto &join)\n {\n join.on("users.id", "=", "contacts.user_id")\n .orOn(...);\n })\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:['If you would like to use a "where" clause on your joins, you may use the ',(0,r.jsx)(n.code,{children:"where"})," and ",(0,r.jsx)(n.code,{children:"orWhere"})," methods provided by the ",(0,r.jsx)(n.code,{children:"Orm::Query::JoinClause"})," instance. Instead of comparing two columns, these methods will compare the column against a value:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")\n ->join("contacts", [](auto &join)\n {\n join.on("users.id", "=", "contacts.user_id")\n .where("contacts.user_id", ">", 5);\n })\n .get();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"subquery-joins",children:"Subquery Joins"}),"\n",(0,r.jsxs)(n.p,{children:["You may use the ",(0,r.jsx)(n.code,{children:"joinSub"}),", ",(0,r.jsx)(n.code,{children:"leftJoinSub"}),", and ",(0,r.jsx)(n.code,{children:"rightJoinSub"})," methods to join a query to a subquery. Each of these methods receives three arguments: the subquery, its table alias, and a lambda expression that defines the related columns. In this example, we will retrieve a collection of users where each user record also contains the ",(0,r.jsx)(n.code,{children:"created_at"})," timestamp of the user's most recently published blog post:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto latestPosts = DB::table("posts")\n ->select({"user_id", DB::raw("MAX(created_at) as last_post_created_at")})\n .whereEq("is_published", true)\n .groupBy("user_id");\n\nauto users = DB::table("users")\n ->joinSub(latestPosts, "latest_posts", [](auto &join)\n {\n join.on("users.id", "=", "latest_posts.user_id");\n }).get();\n'})}),"\n",(0,r.jsx)(n.h2,{id:"basic-where-clauses",children:"Basic Where Clauses"}),"\n",(0,r.jsx)(n.h3,{id:"where-clauses",children:"Where Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["You may use the query builder's ",(0,r.jsx)(n.code,{children:"where"}),' method to add "where" clauses to the query. The most basic call to the ',(0,r.jsx)(n.code,{children:"where"})," method requires three arguments. The first argument is the name of the column. The second argument is an operator, which can be any of the database's supported operators. The third argument is the value to compare against the column's value."]}),"\n",(0,r.jsxs)(n.p,{children:["For example, the following query retrieves users where the value of the ",(0,r.jsx)(n.code,{children:"votes"})," column is equal to ",(0,r.jsx)(n.code,{children:"100"})," and the value of the ",(0,r.jsx)(n.code,{children:"age"})," column is greater than ",(0,r.jsx)(n.code,{children:"35"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where("votes", "=", 100)\n .where("age", ">", 35)\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["For convenience, if you want to verify that a column is ",(0,r.jsx)(n.code,{children:"="})," to a given value, you may call ",(0,r.jsx)(n.code,{children:"whereEq"})," method. Similar ",(0,r.jsx)(n.code,{children:"XxxEq"})," methods are also defined for other commands:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")->whereEq("votes", 100).get();\n'})}),"\n",(0,r.jsx)(n.p,{children:"As previously mentioned, you may use any operator that is supported by your database system:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where("votes", ">=", 100)\n .get();\n\nauto users = DB::table("users")\n ->where("votes", "<>", 100)\n .get();\n\nauto users = DB::table("users")\n ->where("name", "like", "T%")\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may also pass a ",(0,r.jsx)(n.code,{children:"QVector<Orm::WhereItem>"})," of conditions to the ",(0,r.jsx)(n.code,{children:"where"})," function. Each ",(0,r.jsx)(n.code,{children:"Orm::WhereItem"})," structure should contain the four arguments typically passed to the ",(0,r.jsx)(n.code,{children:"where"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where({\n {"status", 1}, // "=" by default\n {"subscribed", 1, "<>"},\n }).get();\n'})}),"\n",(0,r.jsx)(n.h3,{id:"or-where-clauses",children:"Or Where Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["When chaining together calls to the query builder's ",(0,r.jsx)(n.code,{children:"where"}),' method, the "where" clauses will be joined together using the ',(0,r.jsx)(n.code,{children:"and"})," operator. However, you may use the ",(0,r.jsx)(n.code,{children:"orWhere"})," or ",(0,r.jsx)(n.code,{children:"orWhereEq"})," method to join a clause to the query using the ",(0,r.jsx)(n.code,{children:"or"})," operator. The ",(0,r.jsx)(n.code,{children:"orWhere"})," method accepts the same arguments as the ",(0,r.jsx)(n.code,{children:"where"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where("votes", ">", 100)\n .orWhere("name", "=", "John")\n .orWhereEq("name", "Jack")\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:['If you need to group an "or" condition within parentheses, you may pass a lambda expression as the first argument to the ',(0,r.jsx)(n.code,{children:"orWhere"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where("votes", ">", 100)\n .orWhere([](auto &query)\n {\n query.whereEq("name", "Abigail")\n .where("votes", ">", 50);\n })\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:"The example above will produce the following SQL:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:'select * from users where votes > 100 or (name = "Abigail" and votes > 50)\n'})}),"\n",(0,r.jsx)(n.h3,{id:"condition-operator-overriding",children:"Condition Operator Overriding"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"where"})," method overload with a ",(0,r.jsx)(n.code,{children:"QVector<Orm::WhereItem>"})," as the first argument joins conditions using the ",(0,r.jsx)(n.code,{children:"and"})," operator by default:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where({\n {"first_name", "John"},\n {"votes", 50, ">"},\n }).get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Conditions operator can be overridden by the fourth argument in the ",(0,r.jsx)(n.code,{children:"Orm::WhereItem"})," structure:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where({\n {"first_name", "John"},\n {"votes", 50, ">", "or"},\n }).get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Or by the second ",(0,r.jsx)(n.code,{children:"where"})," argument, in this case all conditions will be joined by this condition, but it is still possible to override them by the fourth argument in the ",(0,r.jsx)(n.code,{children:"Orm::WhereItem"})," structure:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where({\n {"first_name", "John"},\n {"last_name", "Smith"},\n {"votes", 50, ">", "and"},\n }, "or")\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:"The example above will produce the following SQL:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:'select * from users where (first_name = "John" or last_name = "Smith" and votes > 50)\n'})}),"\n",(0,r.jsx)(n.admonition,{type:"tip",children:(0,r.jsxs)(n.p,{children:["Still, it is a better idea to use ",(0,r.jsx)(n.a,{href:"#logical-grouping",children:"Logical Grouping"})," described few lines below, which allows better control of the parentheses."]})}),"\n",(0,r.jsx)(n.h3,{id:"where-not-clauses",children:"Where Not Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereNot"})," and ",(0,r.jsx)(n.code,{children:"orWhereNot"})," methods may be used to negate a given group of query constraints. For example, the following query excludes products that are on clearance or which have a price that is less than ten:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto products = DB::table("products")\n ->whereNot([](auto &query) {\n query.whereEq("clearance", true)\n .orWhere("price", "<", 10);\n })\n .get();\n'})}),"\n",(0,r.jsx)(n.h3,{id:"additional-where-clauses",children:"Additional Where Clauses"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereBetween / orWhereBetween"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereBetween"})," method verifies that a column's value is between two values:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereBetween("votes", {1, 100})\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereNotBetween / orWhereNotBetween"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereNotBetween"})," method verifies that a column's value lies outside of two values:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereNotBetween("votes", {1, 100})\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereBetweenColumns / orWhereBetweenColumns"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereBetweenColumns"})," method verifies that a column's value is between two values in given columns:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto files = DB::table("files")\n ->whereBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereNotBetweenColumns / orWhereNotBetweenColumns"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereNotBetweenColumns"})," method verifies that a column's value lies outside of two values in given columns:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto files = DB::table("files")\n ->whereNotBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereIn / whereNotIn / orWhereIn / orWhereNotIn"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereIn"})," method verifies that a given column's value is contained within the given ",(0,r.jsx)(n.code,{children:"QVector<QVariant>"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereIn("id", {1, 2, 3})\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereNotIn"})," method verifies that the given column's value is not contained in the given ",(0,r.jsx)(n.code,{children:"QVector<QVariant>"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereNotIn("id", {1, 2, 3})\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereNull / whereNotNull / orWhereNull / orWhereNotNull"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereNull"})," method verifies that the value of the given column is ",(0,r.jsx)(n.code,{children:"NULL"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereNull("updated_at")\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereNotNull"})," method verifies that the column's value is not ",(0,r.jsx)(n.code,{children:"NULL"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereNotNull("updated_at")\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereDate / whereTime / whereDay / whereMonth / whereYear"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereDate"})," method may be used to compare a column's value against a date:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereDate("created_at", EQ, QDate(2022, 11, 18))\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereTime"})," method may be used to compare a column's value against a specific time:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereTime("created_at", "=", QTime(11, 14, 23))\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereDay"})," method may be used to compare a column's value against a specific day of the month:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereDay("created_at", "<=", 15)\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereMonth"})," method may be used to compare a column's value against a specific month:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereEqMonth("created_at", 12)\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereYear"})," method may be used to compare a column's value against a specific year:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereEqYear("created_at", 2016)\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereDate"})," and ",(0,r.jsx)(n.code,{children:"whereTime"})," methods also accept a ",(0,r.jsx)(n.code,{children:"QDateTime"})," instance or you can pass values as a ",(0,r.jsx)(n.code,{children:"QString"})," in ",(0,r.jsx)(n.code,{children:"2022-12-31"})," or ",(0,r.jsx)(n.code,{children:"09:15:11"})," formats."]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereDay"}),", ",(0,r.jsx)(n.code,{children:"whereMoth"}),", and ",(0,r.jsx)(n.code,{children:"whereYear"})," accept ",(0,r.jsx)(n.code,{children:"QDate"})," or ",(0,r.jsx)(n.code,{children:"QDateTime"})," instances, an integral number or a ",(0,r.jsx)(n.code,{children:"QString"})," that contains an integral number."]}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsxs)(n.p,{children:["All the above methods offer ",(0,r.jsx)(n.code,{children:"whereEqXyz"})," and ",(0,r.jsx)(n.code,{children:"orWhereXyz"})," shortcut methods."]})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"whereColumn / orWhereColumn"})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereColumnEq"})," method may be used to verify that two columns are equal:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereColumnEq("first_name", "last_name")\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may also pass a comparison operator to the ",(0,r.jsx)(n.code,{children:"whereColumn"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereColumn("updated_at", ">", "created_at")\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may also pass a ",(0,r.jsx)(n.code,{children:"QVector<Orm::WhereColumnItem>"})," of column comparisons to the ",(0,r.jsx)(n.code,{children:"whereColumn"})," method. These conditions will be joined using the ",(0,r.jsx)(n.code,{children:"and"})," operator:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereColumn({\n {"first_name", "last_name"},\n {"updated_at", "created_at", ">"},\n }).get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Conditions operator can also be overridden by the fourth argument in the ",(0,r.jsx)(n.code,{children:"Orm::WhereColumnItem"})," structure:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereColumn({\n {"first_name", "last_name"},\n {"updated_at", "created_at", ">", "or"},\n }).get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Or by the second ",(0,r.jsx)(n.code,{children:"whereColumn"})," argument:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereColumn({\n {"first_name", "last_name"},\n {"updated_at", "created_at", ">"},\n }, "or")\n .get();\n'})}),"\n",(0,r.jsx)(n.h3,{id:"logical-grouping",children:"Logical Grouping"}),"\n",(0,r.jsxs)(n.p,{children:['Sometimes you may need to group several "where" clauses within parentheses in order to achieve your query\'s desired logical grouping. In fact, you should generally always group calls to the ',(0,r.jsx)(n.code,{children:"orWhere"})," method in parentheses in order to avoid unexpected query behavior. To accomplish this, you may pass a lambda expression to the ",(0,r.jsx)(n.code,{children:"where"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->where("name", "=", "John")\n .where([](auto &query)\n {\n query.where("votes", ">", 100)\n .orWhere("title", "=", "Admin");\n })\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["As you can see, passing a lambda expression into the ",(0,r.jsx)(n.code,{children:"where"})," method instructs the query builder to begin a constraint group. The lambda expression will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:'select * from users where name = "John" and (votes > 100 or title = "Admin")\n'})}),"\n",(0,r.jsx)(n.h2,{id:"advanced-where-clauses",children:"Advanced Where Clauses"}),"\n",(0,r.jsx)(n.h3,{id:"where-exists-clauses",children:"Where Exists Clauses"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"whereExists"}),' method allows you to write "where exists" SQL clauses. The ',(0,r.jsx)(n.code,{children:"whereExists"}),' method accepts a lambda expression which will receive a query builder instance, allowing you to define the query that should be placed inside of the "exists" clause:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereExists([](auto &query)\n {\n query.select(DB::raw(1))\n .from("orders")\n .whereColumnEq("orders.user_id", "users.id");\n })\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Alternatively, you may provide a query object to the ",(0,r.jsx)(n.code,{children:"whereExists"})," method instead of a lambda expression:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'// Ownership of the std::shared_ptr<QueryBuilder>\nauto builder = DB::table("orders");\nauto orders = builder->select(DB::raw(1))\n .whereColumnEq("orders.user_id", "users.id");\n\nauto users = DB::table("users")\n ->whereExists(orders)\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:"Or directly:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->whereExists(DB::table("orders")\n ->select(DB::raw(1))\n .whereColumnEq("orders.user_id", "users.id"))\n .get();\n'})}),"\n",(0,r.jsx)(n.p,{children:"All of the examples above will produce the following SQL:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-sql",children:"select * from users\nwhere exists (\n select 1\n from orders\n where orders.user_id = users.id\n)\n"})}),"\n",(0,r.jsx)(n.h3,{id:"subquery-where-clauses",children:"Subquery Where Clauses"}),"\n",(0,r.jsxs)(n.p,{children:['Sometimes you may need to construct a "where" clause that compares the results of a subquery to a given value. You may accomplish this by passing a lambda expression and a value to the ',(0,r.jsx)(n.code,{children:"where"}),' method. For example, the following query will retrieve all users who have a recent "membership" of a given type:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include "models/user.hpp"\n\nauto users = User::whereEq([](auto &query)\n{\n query.select("type")\n .from("membership")\n .whereColumnEq("membership.user_id", "users.id")\n .orderByDesc("membership.start_date")\n .limit(1);\n}, "Pro")->get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:['Or, you may need to construct a "where" clause that compares a column to the results of a subquery. You may accomplish this by passing a column, operator, and lambda expression to the ',(0,r.jsx)(n.code,{children:"where"})," method. For example, the following query will retrieve all income records where the amount is less than average;"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'#include "models/income.hpp"\n\nauto incomes = Income::where("amount", "<", [](auto &query)\n{\n query.selectRaw("avg(i.amount)").from("incomes as i");\n})->get();\n'})}),"\n",(0,r.jsx)(n.h2,{id:"ordering-grouping-limit-and-offset",children:"Ordering, Grouping, Limit & Offset"}),"\n",(0,r.jsx)(n.h3,{id:"ordering",children:"Ordering"}),"\n",(0,r.jsxs)(n.h4,{id:"the-orderby-method",children:["The ",(0,r.jsx)(n.code,{children:"orderBy"})," Method"]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"orderBy"})," method allows you to sort the results of the query by a given column. The first argument accepted by the ",(0,r.jsx)(n.code,{children:"orderBy"})," method should be the column you wish to sort by, while the second argument determines the direction of the sort and may be either ",(0,r.jsx)(n.code,{children:"asc"})," or ",(0,r.jsx)(n.code,{children:"desc"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->orderBy("name", "desc")\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["To sort by multiple columns, you may simply invoke ",(0,r.jsx)(n.code,{children:"orderBy"})," as many times as necessary:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->orderBy("name", "desc")\n .orderBy("email", "asc")\n .get();\n'})}),"\n",(0,r.jsxs)(n.h4,{id:"the-latest--oldest-methods",children:["The ",(0,r.jsx)(n.code,{children:"latest"})," & ",(0,r.jsx)(n.code,{children:"oldest"})," Methods"]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"latest"})," and ",(0,r.jsx)(n.code,{children:"oldest"})," methods allow you to easily order results by date. By default, the result will be ordered by the table's ",(0,r.jsx)(n.code,{children:"created_at"})," column. Or, you may pass the column name that you wish to sort by:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto user = DB::table("users")\n ->latest()\n .first();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"random-ordering",children:"Random Ordering"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"inRandomOrder"})," method may be used to sort the query results randomly. For example, you may use this method to fetch a random user:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto randomUser = DB::table("users")\n ->inRandomOrder()\n .first();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"removing-existing-orderings",children:"Removing Existing Orderings"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"reorder"}),' method removes all of the "order by" clauses that have previously been applied to the query:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto &query = DB::table("users")->orderBy("name");\n\nauto unorderedUsers = query.reorder().get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may pass a column and direction when calling the ",(0,r.jsx)(n.code,{children:"reorder"}),' method in order to remove all existing "order by" clauses and apply an entirely new order to the query:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto &query = DB::table("users")->orderBy("name");\n\nauto usersOrderedByEmail = query.reorder("email", "desc").get();\n'})}),"\n",(0,r.jsx)(n.h3,{id:"grouping",children:"Grouping"}),"\n",(0,r.jsxs)(n.h4,{id:"the-groupby--having-methods",children:["The ",(0,r.jsx)(n.code,{children:"groupBy"})," & ",(0,r.jsx)(n.code,{children:"having"})," Methods"]}),"\n",(0,r.jsxs)(n.p,{children:["As you might expect, the ",(0,r.jsx)(n.code,{children:"groupBy"})," and ",(0,r.jsx)(n.code,{children:"having"})," methods may be used to group the query results. The ",(0,r.jsx)(n.code,{children:"having"})," method's signature is similar to that of the ",(0,r.jsx)(n.code,{children:"where"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->groupBy("account_id")\n .having("account_id", ">", 100)\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may pass multiple items to the ",(0,r.jsx)(n.code,{children:"groupBy"})," method to group by multiple columns:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->groupBy({"first_name", "status"})\n .having("account_id", ">", 100)\n .get();\n'})}),"\n",(0,r.jsx)(n.h3,{id:"limit-and-offset",children:"Limit & Offset"}),"\n",(0,r.jsxs)(n.h4,{id:"the-skip--take-methods",children:["The ",(0,r.jsx)(n.code,{children:"skip"})," & ",(0,r.jsx)(n.code,{children:"take"})," Methods"]}),"\n",(0,r.jsxs)(n.p,{children:["You may use the ",(0,r.jsx)(n.code,{children:"skip"})," and ",(0,r.jsx)(n.code,{children:"take"})," methods to limit the number of results returned from the query or to skip a given number of results in the query:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")->skip(10).take(5).get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Alternatively, you may use the ",(0,r.jsx)(n.code,{children:"limit"})," and ",(0,r.jsx)(n.code,{children:"offset"})," methods. These methods are functionally equivalent to the ",(0,r.jsx)(n.code,{children:"take"})," and ",(0,r.jsx)(n.code,{children:"skip"})," methods, respectively:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto users = DB::table("users")\n ->offset(10)\n .limit(5)\n .get();\n'})}),"\n",(0,r.jsx)(n.h2,{id:"insert-statements",children:"Insert Statements"}),"\n",(0,r.jsxs)(n.p,{children:["The query builder also provides an ",(0,r.jsx)(n.code,{children:"insert"})," method that may be used to insert records into the database table. The ",(0,r.jsx)(n.code,{children:"insert"})," method accepts the ",(0,r.jsx)(n.code,{children:"QVariantMap"})," of column names and values:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->insert({\n {"email", "kayla@example.com"},\n {"votes", 0},\n});\n'})}),"\n",(0,r.jsx)("a",{id:"multi-insert-overload"}),"\n",(0,r.jsxs)(n.p,{children:["You may insert several records at once by passing a ",(0,r.jsx)(n.code,{children:"QVector<QString>"})," for column names as the first argument and ",(0,r.jsx)(n.code,{children:"QVector<QVector<QVariant>>"})," for values as the second argument. Each ",(0,r.jsx)(n.code,{children:"QVector<QVariant>"})," represents a record that should be inserted into the table. This overload is useful for multi-insert and allows to specify column names only once:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->insert({"email", "votes"},\n{\n {"picard@example.com", 0},\n {"janeway@example.com", 0},\n});\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may also insert several records at once by passing a ",(0,r.jsx)(n.code,{children:"QVector<QVariantMap>"}),". Each ",(0,r.jsx)(n.code,{children:"QVariantMap"})," represents a record that should be inserted into the table:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->insert({\n {{"email", "picard@example.com"}, {"votes", 0}},\n {{"email", "janeway@example.com"}, {"votes", 0}},\n});\n'})}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"insertOrIgnore"})," method will ignore duplicate record errors while inserting records into the database and also provides the same overloads like the ",(0,r.jsx)(n.code,{children:"insert"})," method. When using this method, you should be aware that duplicate record errors will be ignored and other types of errors may also be ignored depending on the database engine. For example, ",(0,r.jsx)(n.code,{children:"insertOrIgnore"})," will ",(0,r.jsx)(n.a,{href:"https://dev.mysql.com/doc/refman/en/sql-mode.html#ignore-effect-on-execution",children:"bypass MySQL's strict mode"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->insertOrIgnore({"id", "email"},\n{\n {1, "sisko@example.com"},\n {2, "archer@example.com"},\n});\n\nDB::table("users")->insertOrIgnore({\n {{"id", 1}, {"email", "sisko@example.com"}},\n {{"id", 2}, {"email", "archer@example.com"}},\n});\n'})}),"\n",(0,r.jsx)(n.h4,{id:"auto-incrementing-ids",children:"Auto-Incrementing IDs"}),"\n",(0,r.jsxs)(n.p,{children:["If the table has an auto-incrementing id, use the ",(0,r.jsx)(n.code,{children:"insertGetId"})," method to insert a record and then retrieve the ID:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto id = DB::table("users")->insertGetId({\n {"email", "john@example.com"},\n {"votes", 0},\n});\n'})}),"\n",(0,r.jsx)(n.h3,{id:"upserts",children:"Upserts"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"upsert"})," method will insert records that do not exist and update the records that already exist with new values that you may specify. 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 a vector of columns that should be updated if a matching record already exists in the database:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("flights")->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,r.jsxs)(n.p,{children:["In the example above, TinyORM will attempt to insert two records. If a record already exists with the same ",(0,r.jsx)(n.code,{children:"departure"})," and ",(0,r.jsx)(n.code,{children:"destination"})," column values, TinyORM will update that record's ",(0,r.jsx)(n.code,{children:"price"})," column."]}),"\n",(0,r.jsx)(n.admonition,{type:"caution",children:(0,r.jsxs)(n.p,{children:["All databases except SQL Server require the columns in the second argument of the ",(0,r.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,r.jsx)(n.code,{children:"upsert"}),' method and always uses the "primary" and "unique" indexes of the table to detect existing records.']})}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.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,r.jsx)(n.a,{href:"https://dev.mysql.com/doc/refman/8.3/en/insert-on-duplicate.html",children:"documentation"}),". The MySQL server version is auto-detected and can be overridden in the ",(0,r.jsx)(n.a,{href:"/database/getting-started#configuration",children:"configuration"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"update-statements",children:"Update Statements"}),"\n",(0,r.jsxs)(n.p,{children:["In addition to inserting records into the database, the query builder can also update existing records using the ",(0,r.jsx)(n.code,{children:"update"})," method. The ",(0,r.jsx)(n.code,{children:"update"})," method, accepts a ",(0,r.jsx)(n.code,{children:"QVector<Orm::UpdateItem>"})," of column and value pairs, indicating the columns to be updated and returns a ",(0,r.jsx)(n.code,{children:"std::tuple<int, QSqlQuery>"})," . You may constrain the ",(0,r.jsx)(n.code,{children:"update"})," query using ",(0,r.jsx)(n.code,{children:"where"})," clauses:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'auto [affected, query] = DB::table("users")\n ->whereEq("id", 1)\n .update({{"votes", 1}});\n'})}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["An ",(0,r.jsx)(n.code,{children:"update"})," and ",(0,r.jsx)(n.code,{children:"delete"})," are affecting statements, so they return ",(0,r.jsx)(n.code,{children:"std::tuple<int, QSqlQuery>"}),"."]})}),"\n",(0,r.jsx)(n.h4,{id:"update-or-insert",children:"Update Or Insert"}),"\n",(0,r.jsxs)(n.p,{children:["Sometimes you may want to update an existing record in the database or create it if no matching record exists. In this scenario, the ",(0,r.jsx)(n.code,{children:"updateOrInsert"})," method may be used. The ",(0,r.jsx)(n.code,{children:"updateOrInsert"})," method accepts two arguments: a vector of conditions by which to find the record, and a vector of column and value pairs indicating the columns to be updated."]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"updateOrInsert"})," method will attempt to locate a matching database record using the first argument's column and value pairs. If the record exists, it will be updated with the values in the second argument. If the record can not be found, a new record will be inserted with the merged attributes of both arguments:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")\n ->updateOrInsert(\n {{"email", "john@example.com"}, {"name", "John"}},\n {{"votes", 2}}\n );\n'})}),"\n",(0,r.jsx)(n.h3,{id:"increment-and-decrement",children:"Increment & Decrement"}),"\n",(0,r.jsx)(n.p,{children:"The query builder also provides convenient methods for incrementing or decrementing the value of a given column. Both of these methods accept at least one argument: the column to modify. A second argument may be provided to specify the amount by which the column should be incremented or decremented:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->increment<int>("votes");\n\nDB::table("users")->increment("votes", 5);\n\nDB::table("users")->decrement<int>("votes");\n\nDB::table("users")->decrement("votes", 5.2); // float or double type\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You may also specify additional columns to update during the operation as a ",(0,r.jsx)(n.code,{children:"QVector<Orm::UpdateItem>"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->increment("votes", 1, {{"name", "John"}});\n'})}),"\n",(0,r.jsxs)(n.p,{children:["You should constrain ",(0,r.jsx)(n.code,{children:"increment"}),", ",(0,r.jsx)(n.code,{children:"decrement"})," by ",(0,r.jsx)(n.code,{children:"where"})," to update only specific record in the database, otherwise a column in all records will be modified."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->whereEq("id", 1).increment("votes", 5);\n'})}),"\n",(0,r.jsx)(n.h2,{id:"delete-statements",children:"Delete Statements"}),"\n",(0,r.jsxs)(n.p,{children:["The query builder's ",(0,r.jsx)(n.code,{children:"remove"}),", or an alias ",(0,r.jsx)(n.code,{children:"deleteRow"})," method may be used to delete records from the table. You may constrain ",(0,r.jsx)(n.code,{children:"delete"}),' statements by adding "where" clauses before calling the ',(0,r.jsx)(n.code,{children:"delete"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->remove();\n\nDB::table("users")->where("votes", ">", 100).remove();\n'})}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"delete"})," can not be used as the method name because it is the reserved word."]})}),"\n",(0,r.jsxs)(n.p,{children:["You may also pass record ",(0,r.jsx)(n.code,{children:"id"})," to the ",(0,r.jsx)(n.code,{children:"remove"})," method as the first argument, it is the shortcut method, which internally calls ",(0,r.jsx)(n.code,{children:"where"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->remove(2);\n'})}),"\n",(0,r.jsx)(n.h3,{id:"truncate-statement",children:"Truncate Statement"}),"\n",(0,r.jsxs)(n.p,{children:["If you wish to truncate an entire table, which will remove all records from the table and reset the auto-incrementing ID to zero, you may use the ",(0,r.jsx)(n.code,{children:"truncate"})," method:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->truncate();\n'})}),"\n",(0,r.jsx)(n.h4,{id:"table-truncation--postgresql",children:"Table Truncation & PostgreSQL"}),"\n",(0,r.jsxs)(n.p,{children:["When truncating a PostgreSQL database, the ",(0,r.jsx)(n.code,{children:"CASCADE"})," behavior will be applied. This means that all foreign key related records in other tables will be deleted as well."]}),"\n",(0,r.jsx)(n.h2,{id:"pessimistic-locking",children:"Pessimistic Locking"}),"\n",(0,r.jsxs)(n.p,{children:['The query builder also includes a few functions to help you achieve "pessimistic locking" when executing your ',(0,r.jsx)(n.code,{children:"select"}),' statements. To execute a statement with a "shared lock", you may call the ',(0,r.jsx)(n.code,{children:"sharedLock"})," method. A shared lock prevents the selected rows from being modified until your transaction is committed:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")\n ->where("votes", ">", 100)\n .sharedLock()\n .get();\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Alternatively, you may use the ",(0,r.jsx)(n.code,{children:"lockForUpdate"}),' method. A "for update" lock prevents the selected records from being modified or from being selected with another shared lock:']}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")\n ->where("votes", ">", 100)\n .lockForUpdate()\n .get();\n'})}),"\n",(0,r.jsx)(n.h2,{id:"debugging",children:"Debugging"}),"\n",(0,r.jsxs)(n.p,{children:["You may use the ",(0,r.jsx)(n.code,{children:"dd"})," and ",(0,r.jsx)(n.code,{children:"dump"})," methods while building a query to dump the current query bindings and SQL. The ",(0,r.jsx)(n.code,{children:"dd"})," method will display the debug information and then stop executing using the ",(0,r.jsx)(n.code,{children:"exit(1)"}),". The ",(0,r.jsx)(n.code,{children:"dump"})," method will display the debug information and continue executing:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-cpp",children:'DB::table("users")->where("votes", ">", 100).dd();\n\nDB::table("users")->where("votes", ">", 100).dump();\n'})})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>i,x:()=>o});var r=s(6540);const t={},a=r.createContext(t);function i(e){const n=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:i(e.components),r.createElement(a.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/cbe663fe.8fc7d46f.js b/assets/js/cbe663fe.8fc7d46f.js deleted file mode 100644 index cf7290542..000000000 --- a/assets/js/cbe663fe.8fc7d46f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[594],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>c});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=u(n),h=r,c=p["".concat(s,".").concat(h)]||p[h]||m[h]||o;return n?a.createElement(c,i(i({ref:t},d),{},{components:n})):a.createElement(c,i({ref:t},d))}));function c(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,i[1]=l;for(var u=2;u<o;u++)i[u]=n[u];return a.createElement.apply(null,i)}return a.createElement.apply(null,n)}h.displayName="MDXCreateElement"},9542:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>l,toc:()=>u});var a=n(7462),r=(n(7294),n(3905));const o={sidebar_position:1,sidebar_label:"Query Builder",description:"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.",keywords:["c++ orm","sql","c++ sql","c++ query builder","database","query builder","tinyorm"]},i="Database: Query Builder",l={unversionedId:"database/query-builder",id:"database/query-builder",title:"Database: Query Builder",description:"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.",source:"@site/docs/database/query-builder.mdx",sourceDirName:"database",slug:"/database/query-builder",permalink:"/database/query-builder",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/database/query-builder.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,sidebar_label:"Query Builder",description:"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application. The query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.",keywords:["c++ orm","sql","c++ sql","c++ query builder","database","query builder","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"Getting Started",permalink:"/database/getting-started"},next:{title:"Migrations",permalink:"/database/migrations"}},s={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Running Database Queries",id:"running-database-queries",level:2},{value:"Retrieving All Rows From A Table",id:"retrieving-all-rows-from-a-table",level:4},{value:"Retrieving A Single Row / Column From A Table",id:"retrieving-a-single-row--column-from-a-table",level:4},{value:"Retrieving A List Of Column Values",id:"retrieving-a-list-of-column-values",level:4},{value:"Concatenate column values",id:"concatenate-column-values",level:4},{value:"Chunking Results",id:"chunking-results",level:3},{value:"Aggregates",id:"aggregates",level:3},{value:"Determining If Records Exist",id:"determining-if-records-exist",level:4},{value:"Select Statements",id:"select-statements",level:2},{value:"Specifying A Select Clause",id:"specifying-a-select-clause",level:4},{value:"Raw Expressions",id:"raw-expressions",level:2},{value:"Raw Methods",id:"raw-methods",level:3},{value:"<code>selectRaw</code>",id:"selectraw",level:4},{value:"<code>fromRaw</code>",id:"fromraw",level:4},{value:"<code>whereRaw / orWhereRaw</code>",id:"whereraw--orwhereraw",level:4},{value:"<code>groupByRaw</code>",id:"groupbyraw",level:3},{value:"<code>havingRaw / orHavingRaw</code>",id:"havingraw--orhavingraw",level:4},{value:"<code>orderByRaw</code>",id:"orderbyraw",level:4},{value:"Joins",id:"joins",level:2},{value:"Inner Join Clause",id:"inner-join-clause",level:4},{value:"Left Join / Right Join Clause",id:"left-join--right-join-clause",level:4},{value:"Cross Join Clause",id:"cross-join-clause",level:4},{value:"Advanced Join Clauses",id:"advanced-join-clauses",level:4},{value:"Subquery Joins",id:"subquery-joins",level:4},{value:"Basic Where Clauses",id:"basic-where-clauses",level:2},{value:"Where Clauses",id:"where-clauses",level:3},{value:"Or Where Clauses",id:"or-where-clauses",level:3},{value:"Condition Operator Overriding",id:"condition-operator-overriding",level:3},{value:"Where Not Clauses",id:"where-not-clauses",level:3},{value:"Additional Where Clauses",id:"additional-where-clauses",level:3},{value:"Logical Grouping",id:"logical-grouping",level:3},{value:"Advanced Where Clauses",id:"advanced-where-clauses",level:2},{value:"Where Exists Clauses",id:"where-exists-clauses",level:3},{value:"Subquery Where Clauses",id:"subquery-where-clauses",level:3},{value:"Ordering, Grouping, Limit & Offset",id:"ordering-grouping-limit-and-offset",level:2},{value:"Ordering",id:"ordering",level:3},{value:"The <code>orderBy</code> Method",id:"the-orderby-method",level:4},{value:"The <code>latest</code> & <code>oldest</code> Methods",id:"the-latest--oldest-methods",level:4},{value:"Random Ordering",id:"random-ordering",level:4},{value:"Removing Existing Orderings",id:"removing-existing-orderings",level:4},{value:"Grouping",id:"grouping",level:3},{value:"The <code>groupBy</code> & <code>having</code> Methods",id:"the-groupby--having-methods",level:4},{value:"Limit & Offset",id:"limit-and-offset",level:3},{value:"The <code>skip</code> & <code>take</code> Methods",id:"the-skip--take-methods",level:4},{value:"Insert Statements",id:"insert-statements",level:2},{value:"Auto-Incrementing IDs",id:"auto-incrementing-ids",level:4},{value:"Upserts",id:"upserts",level:3},{value:"Update Statements",id:"update-statements",level:2},{value:"Update Or Insert",id:"update-or-insert",level:4},{value:"Increment & Decrement",id:"increment-and-decrement",level:3},{value:"Delete Statements",id:"delete-statements",level:2},{value:"Truncate Statement",id:"truncate-statement",level:3},{value:"Table Truncation & PostgreSQL",id:"table-truncation--postgresql",level:4},{value:"Pessimistic Locking",id:"pessimistic-locking",level:2},{value:"Debugging",id:"debugging",level:2}],d={toc:u},p="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(p,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"database-query-builder"},"Database: Query Builder"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#running-database-queries"},"Running Database Queries"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#chunking-results"},"Chunking Results")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#aggregates"},"Aggregates")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#select-statements"},"Select Statements")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#raw-expressions"},"Raw Expressions")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#joins"},"Joins")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#basic-where-clauses"},"Basic Where Clauses"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#where-clauses"},"Where Clauses")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#or-where-clauses"},"Or Where Clauses")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#where-not-clauses"},"Where Not Clauses")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#additional-where-clauses"},"Additional Where Clauses")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#condition-operator-overriding"},"Condition Operator Overriding")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#logical-grouping"},"Logical Grouping")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#advanced-where-clauses"},"Advanced Where Clauses"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#where-exists-clauses"},"Where Exists Clauses")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#subquery-where-clauses"},"Subquery Where Clauses")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#ordering-grouping-limit-and-offset"},"Ordering, Grouping, Limit & Offset"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#ordering"},"Ordering")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#grouping"},"Grouping")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#limit-and-offset"},"Limit & Offset")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#insert-statements"},"Insert Statements"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#upserts"},"Upserts")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#update-statements"},"Update Statements"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#increment-and-decrement"},"Increment & Decrement")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#delete-statements"},"Delete Statements"),(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#truncate-statement"},"Truncate Statement")))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#pessimistic-locking"},"Pessimistic Locking")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#debugging"},"Debugging"))),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application."),(0,r.kt)("p",null,"The TinyORM query builder uses ",(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery")," parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings."),(0,r.kt)("admonition",{type:"danger"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery"),' does not support binding column names. Therefore, you should never allow user input to dictate the column names referenced by your queries, including "order by" columns.')),(0,r.kt)("admonition",{type:"danger"},(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"QMYSQL")," Qt driver contains a bug, if your table contains a ",(0,r.kt)("inlineCode",{parentName:"p"},"json")," column type, then you must explicitly name columns other than ",(0,r.kt)("inlineCode",{parentName:"p"},"json")," columns instead of the ",(0,r.kt)("inlineCode",{parentName:"p"},"*")," shorthand, otherwise, you will get an empty result, or all column values will be invalid QVariant-s, or it may even return half of the columns. The ",(0,r.kt)("inlineCode",{parentName:"p"},"QPSQL")," driver returns correct results and doesn't have problem with ",(0,r.kt)("inlineCode",{parentName:"p"},"json")," columns. It was fixed in the Qt 5.15.12, 6.2.7, 6.5.0 ",(0,r.kt)("a",{parentName:"p",href:"https://bugreports.qt.io/browse/QTBUG-101680"},"QTBUG-101680"),".")),(0,r.kt)("h2",{id:"running-database-queries"},"Running Database Queries"),(0,r.kt)("h4",{id:"retrieving-all-rows-from-a-table"},"Retrieving All Rows From A Table"),(0,r.kt)("p",null,"You may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"table")," method provided by the ",(0,r.kt)("inlineCode",{parentName:"p"},"DB")," facade to begin a query. The ",(0,r.kt)("inlineCode",{parentName:"p"},"table")," method returns a fluent query builder instance for the given table, allowing you to chain more constraints onto the query and then finally retrieve the results of the query using the ",(0,r.kt)("inlineCode",{parentName:"p"},"get")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\n// Log a list of all of the application\'s users\nauto query = DB::table("users")->get();\n\nwhile (query.next())\n qDebug() << "id :" << query.value("id").toULongLong() << ";"\n << "name :" << query.value("name").toString();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"get")," method returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery")," containing the results of the query where each result can be accessed by ",(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery::next")," method, look into the ",(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery"),' documentation how to obtain results from the "query". You may access each column\'s value by ',(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery::value")," method. The first ",(0,r.kt)("inlineCode",{parentName:"p"},"bool")," return value is the value returned from ",(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery::exec")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include <orm/db.hpp>\n\nauto users = DB::table("users")->get();\n\nwhile(users.next())\n qDebug() << users.value("name").toString();\n')),(0,r.kt)("h4",{id:"retrieving-a-single-row--column-from-a-table"},"Retrieving A Single Row / Column From A Table"),(0,r.kt)("p",null,"If you just need to retrieve a single row from a database table, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"QueryBuilder::first")," method. This method will return a ",(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery")," object, on which was internally called ",(0,r.kt)("inlineCode",{parentName:"p"},"QSqlQuery::first")," method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto user = DB::table("users")->whereEq("name", "John").first();\n\nuser.value("email").toString();\n')),(0,r.kt)("p",null,"If you don't need an entire row, you may extract a single value from a record using the ",(0,r.kt)("inlineCode",{parentName:"p"},"value")," method. This method will return the value of the column directly as ",(0,r.kt)("inlineCode",{parentName:"p"},"QVariant"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto email = DB::table("users")->whereEq("name", "John").value("email").toString();\n')),(0,r.kt)("p",null,"To retrieve a single row by its ",(0,r.kt)("inlineCode",{parentName:"p"},"id")," column value, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"find")," method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto user = DB::table("users")->find(3);\n\nuser.value("email").toString();\n')),(0,r.kt)("h4",{id:"retrieving-a-list-of-column-values"},"Retrieving A List Of Column Values"),(0,r.kt)("p",null,"If you would like to retrieve the ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<QVariant>")," instance containing the values of a single column, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"pluck")," method. In this example, we'll retrieve a collection of user titles:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <QDebug>\n\n#include <orm/db.hpp>\n\nconst auto titles = DB::table("users")->pluck("title");\n\nfor (const auto &title : titles)\n qDebug() << title.value<QString>();\n')),(0,r.kt)("p",null," You may specify the column that the resulting collection should use as its keys by providing a second argument to the ",(0,r.kt)("inlineCode",{parentName:"p"},"pluck")," method, following example returns the ",(0,r.kt)("inlineCode",{parentName:"p"},"std::map<QString, QVariant>"),' of "titles" keyed by "names":'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nauto titles = DB::table("users")->pluck<QString>("title", "name");\n\nfor (auto &&[name, title] : titles)\n qDebug() << name << ":" << title.value<QString>();\n')),(0,r.kt)("p",null,"You may also use ",(0,r.kt)("inlineCode",{parentName:"p"},'pluck<quint64>("name", "id")'),", it returns the ",(0,r.kt)("inlineCode",{parentName:"p"},"std::map<quint64, QVariant>"),' of "names" keyed by its "ids".'),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"This second ",(0,r.kt)("inlineCode",{parentName:"p"},"pluck")," overload returns ",(0,r.kt)("inlineCode",{parentName:"p"},"std::map<T, QVariant>")," so you have to provide a template argument for the key type.")),(0,r.kt)("h4",{id:"concatenate-column-values"},"Concatenate column values"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"implode")," method can be used to join column values. For example, you may use this method to concatenate prices with the ",(0,r.kt)("inlineCode",{parentName:"p"},", ")," character as the glue:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("orders")->where("price", ">", 100).implode("price", ", ");\n')),(0,r.kt)("h3",{id:"chunking-results"},"Chunking Results"),(0,r.kt)("p",null,"If you need to work with thousands of database records, consider using the ",(0,r.kt)("inlineCode",{parentName:"p"},"chunk")," method provided by the ",(0,r.kt)("inlineCode",{parentName:"p"},"DB")," facade. This method retrieves a small chunk of results at a time and feeds each chunk into a lambda expression for processing. For example, let's retrieve the entire ",(0,r.kt)("inlineCode",{parentName:"p"},"users")," table in chunks of 100 records at a time:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)\n{\n while (users.next()) {\n //\n }\n\n return true;\n});\n')),(0,r.kt)("p",null,"You may stop further chunks from being processed by returning ",(0,r.kt)("inlineCode",{parentName:"p"},"false")," from the closure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)\n{\n // Process the records...\n\n return false;\n});\n')),(0,r.kt)("p",null,"If you are updating database records while chunking results, your chunk results could change in unexpected ways. If you plan to update the retrieved records while chunking, it is always best to use the ",(0,r.kt)("inlineCode",{parentName:"p"},"chunkById")," method instead. This method will automatically paginate the results based on the record's primary key:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")\n ->whereEq("active", false)\n .orderBy("id")\n .chunkById(100, [](QSqlQuery &users, const int /*unused*/)\n {\n while (users.next())\n DB::table("users")\n ->whereEq("id", users.value("id"))\n .update({{"active", true}});\n\n return true;\n });\n')),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"When updating or deleting records inside the chunk lambda expression, any changes to the primary key or foreign keys could affect the chunk query. This could potentially result in records not being included in the chunked results, it can be avoided using the ",(0,r.kt)("inlineCode",{parentName:"p"},"chunkById")," method.")),(0,r.kt)("h3",{id:"aggregates"},"Aggregates"),(0,r.kt)("p",null,"The query builder also provides a variety of methods for retrieving aggregate values like ",(0,r.kt)("inlineCode",{parentName:"p"},"count"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"max"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"min"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"avg"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"sum"),". You may call any of these methods after constructing your query:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nauto users = DB::table("users")->count();\n\nauto price = DB::table("orders")->max("price");\n')),(0,r.kt)("p",null,"Of course, you may combine these methods with other clauses to fine-tune how your aggregate value is calculated:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto price = DB::table("orders")\n ->whereEq("finalized", 1)\n .avg("price");\n')),(0,r.kt)("h4",{id:"determining-if-records-exist"},"Determining If Records Exist"),(0,r.kt)("p",null,"Instead of using the ",(0,r.kt)("inlineCode",{parentName:"p"},"count")," method to determine if any records exist that match your query's constraints, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"exists")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"doesntExist")," methods:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'if (DB::table("orders")->whereEq("finalized", 1).exists()) {\n // ...\n}\n\nif (DB::table("orders")->whereEq("finalized", 1).doesntExist()) {\n // ...\n}\n')),(0,r.kt)("h2",{id:"select-statements"},"Select Statements"),(0,r.kt)("h4",{id:"specifying-a-select-clause"},"Specifying A Select Clause"),(0,r.kt)("p",null,"You may not always want to select all columns from a database table. Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"select"),' method, you can specify a custom "select" clause for the query:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nauto users = DB::table("users")\n ->select({"name", "email as user_email"})\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"distinct")," method allows you to force the query to return distinct results:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")->distinct().get();\n')),(0,r.kt)("p",null,"If you already have a query builder instance and you wish to add a column to its existing select clause, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"addSelect")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto query = DB::table("users")->select("name");\n\nauto users = query.addSelect("age").get();\n')),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"You can also pass subqueries to the ",(0,r.kt)("inlineCode",{parentName:"p"},"select")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"addSelect")," methods. A subquery can be a lambda expression, raw string, or the ",(0,r.kt)("inlineCode",{parentName:"p"},"QueryBuilder")," instance.")),(0,r.kt)("h2",{id:"raw-expressions"},"Raw Expressions"),(0,r.kt)("p",null,"Sometimes you may need to insert an arbitrary string into a query. To create a raw string expression, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"raw")," method provided by the ",(0,r.kt)("inlineCode",{parentName:"p"},"DB")," facade:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->select(DB::raw("count(*) as user_count, status"))\n .where("status", "<>", 1)\n .groupBy("status")\n .get();\n')),(0,r.kt)("admonition",{type:"danger"},(0,r.kt)("p",{parentName:"admonition"},"Raw statements will be injected into the query as strings, so you should be extremely careful to avoid creating SQL injection vulnerabilities.")),(0,r.kt)("h3",{id:"raw-methods"},"Raw Methods"),(0,r.kt)("p",null,"Instead of using the ",(0,r.kt)("inlineCode",{parentName:"p"},"DB::raw")," method, you may also use the following methods to insert a raw expression into various parts of your query. ",(0,r.kt)("strong",{parentName:"p"},"Remember, TinyORM can not guarantee that any query using raw expressions is protected against SQL injection vulnerabilities.")),(0,r.kt)("h4",{id:"selectraw"},(0,r.kt)("inlineCode",{parentName:"h4"},"selectRaw")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"selectRaw")," method can be used in place of ",(0,r.kt)("inlineCode",{parentName:"p"},"addSelect(DB::raw(...))"),". This method accepts an optional vector of bindings as its second argument:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto orders = DB::table("orders")\n ->selectRaw("price * ? as price_with_tax", {1.0825})\n .get();\n')),(0,r.kt)("h4",{id:"fromraw"},(0,r.kt)("inlineCode",{parentName:"h4"},"fromRaw")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"fromRaw"),' method may be used to provide a raw string as the value of the "from" clause:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::connection("postgres").query()\n ->fromRaw("(select id, name from users where id < ?) as u", {5})\n .where("id", "<", 3)\n .get();\n')),(0,r.kt)("h4",{id:"whereraw--orwhereraw"},(0,r.kt)("inlineCode",{parentName:"h4"},"whereRaw / orWhereRaw")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereRaw")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"orWhereRaw"),' methods can be used to inject a raw "where" clause into your query. These methods accept an optional vector of bindings as their second argument:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto orders = DB::table("orders")\n ->whereRaw("price > IF(state = \\"TX\\", ?, 100)", {200})\n .get();\n')),(0,r.kt)("h3",{id:"groupbyraw"},(0,r.kt)("inlineCode",{parentName:"h3"},"groupByRaw")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"groupByRaw")," method may be used to provide a raw string as the value of the ",(0,r.kt)("inlineCode",{parentName:"p"},"group by")," clause:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto orders = DB::table("orders")\n ->select({"city", "state"})\n .groupByRaw("city, state")\n .get();\n')),(0,r.kt)("h4",{id:"havingraw--orhavingraw"},(0,r.kt)("inlineCode",{parentName:"h4"},"havingRaw / orHavingRaw")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"havingRaw")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"orHavingRaw"),' methods may be used to provide a raw string as the value of the "having" clause. These methods accept an optional vector of bindings as their second argument:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto orders = DB::table("orders")\n ->select({"department", DB::raw("SUM(price) as total_sales")})\n .groupBy("department")\n .havingRaw("SUM(price) > ?", {2500})\n .get();\n')),(0,r.kt)("h4",{id:"orderbyraw"},(0,r.kt)("inlineCode",{parentName:"h4"},"orderByRaw")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"orderByRaw"),' method may be used to provide a raw string as the value of the "order by" clause:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto orders = DB::table("orders")\n ->orderByRaw("updated_at - created_at DESC")\n .get();\n')),(0,r.kt)("h2",{id:"joins"},"Joins"),(0,r.kt)("h4",{id:"inner-join-clause"},"Inner Join Clause"),(0,r.kt)("p",null,'The query builder may also be used to add join clauses to your queries. To perform a basic "inner join", you may use the ',(0,r.kt)("inlineCode",{parentName:"p"},"join")," method on a query builder instance. The first argument passed to the ",(0,r.kt)("inlineCode",{parentName:"p"},"join")," method is the name of the table you need to join to, while the remaining arguments specify the column constraints for the join. You may even join multiple tables in a single query:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n\nauto users = DB::table("users")\n ->join("contacts", "users.id", "=", "contacts.user_id")\n .join("orders", "users.id", "=", "orders.user_id")\n .select({"users.*", "contacts.phone", "orders.price"})\n .get();\n')),(0,r.kt)("h4",{id:"left-join--right-join-clause"},"Left Join / Right Join Clause"),(0,r.kt)("p",null,'If you would like to perform a "left join" or "right join" instead of an "inner join", use the ',(0,r.kt)("inlineCode",{parentName:"p"},"leftJoin")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"rightJoin")," methods. These methods have the same signature as the ",(0,r.kt)("inlineCode",{parentName:"p"},"join")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->leftJoin("posts", "users.id", "=", "posts.user_id")\n .get();\n\nauto users = DB::table("users")\n ->rightJoin("posts", "users.id", "=", "posts.user_id")\n .get();\n')),(0,r.kt)("h4",{id:"cross-join-clause"},"Cross Join Clause"),(0,r.kt)("p",null,"You may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"crossJoin"),' method to perform a "cross join". Cross joins generate a cartesian product between the first table and the joined table:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto sizes = DB::table("sizes")\n ->crossJoin("colors")\n .get();\n')),(0,r.kt)("h4",{id:"advanced-join-clauses"},"Advanced Join Clauses"),(0,r.kt)("p",null,"You may also specify more advanced join clauses. To get started, pass a lambda expression as the second argument to the ",(0,r.kt)("inlineCode",{parentName:"p"},"join")," method. The lambda expression will receive a ",(0,r.kt)("inlineCode",{parentName:"p"},"Orm::Query::JoinClause"),' instance which allows you to specify constraints on the "join" clause:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include <orm/db.hpp>\n#include <orm/query/joinclause.hpp>\n\nDB::table("users")\n ->join("contacts", [](auto &join)\n {\n join.on("users.id", "=", "contacts.user_id")\n .orOn(...);\n })\n .get();\n')),(0,r.kt)("p",null,'If you would like to use a "where" clause on your joins, you may use the ',(0,r.kt)("inlineCode",{parentName:"p"},"where")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"orWhere")," methods provided by the ",(0,r.kt)("inlineCode",{parentName:"p"},"Orm::Query::JoinClause")," instance. Instead of comparing two columns, these methods will compare the column against a value:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")\n ->join("contacts", [](auto &join)\n {\n join.on("users.id", "=", "contacts.user_id")\n .where("contacts.user_id", ">", 5);\n })\n .get();\n')),(0,r.kt)("h4",{id:"subquery-joins"},"Subquery Joins"),(0,r.kt)("p",null,"You may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"joinSub"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"leftJoinSub"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"rightJoinSub")," methods to join a query to a subquery. Each of these methods receives three arguments: the subquery, its table alias, and a lambda expression that defines the related columns. In this example, we will retrieve a collection of users where each user record also contains the ",(0,r.kt)("inlineCode",{parentName:"p"},"created_at")," timestamp of the user's most recently published blog post:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto latestPosts = DB::table("posts")\n ->select({"user_id", DB::raw("MAX(created_at) as last_post_created_at")})\n .whereEq("is_published", true)\n .groupBy("user_id");\n\nauto users = DB::table("users")\n ->joinSub(latestPosts, "latest_posts", [](auto &join)\n {\n join.on("users.id", "=", "latest_posts.user_id");\n }).get();\n')),(0,r.kt)("h2",{id:"basic-where-clauses"},"Basic Where Clauses"),(0,r.kt)("h3",{id:"where-clauses"},"Where Clauses"),(0,r.kt)("p",null,"You may use the query builder's ",(0,r.kt)("inlineCode",{parentName:"p"},"where"),' method to add "where" clauses to the query. The most basic call to the ',(0,r.kt)("inlineCode",{parentName:"p"},"where")," method requires three arguments. The first argument is the name of the column. The second argument is an operator, which can be any of the database's supported operators. The third argument is the value to compare against the column's value."),(0,r.kt)("p",null,"For example, the following query retrieves users where the value of the ",(0,r.kt)("inlineCode",{parentName:"p"},"votes")," column is equal to ",(0,r.kt)("inlineCode",{parentName:"p"},"100")," and the value of the ",(0,r.kt)("inlineCode",{parentName:"p"},"age")," column is greater than ",(0,r.kt)("inlineCode",{parentName:"p"},"35"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where("votes", "=", 100)\n .where("age", ">", 35)\n .get();\n')),(0,r.kt)("p",null,"For convenience, if you want to verify that a column is ",(0,r.kt)("inlineCode",{parentName:"p"},"=")," to a given value, you may call ",(0,r.kt)("inlineCode",{parentName:"p"},"whereEq")," method. Similar ",(0,r.kt)("inlineCode",{parentName:"p"},"XxxEq")," methods are also defined for other commands:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")->whereEq("votes", 100).get();\n')),(0,r.kt)("p",null,"As previously mentioned, you may use any operator that is supported by your database system:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where("votes", ">=", 100)\n .get();\n\nauto users = DB::table("users")\n ->where("votes", "<>", 100)\n .get();\n\nauto users = DB::table("users")\n ->where("name", "like", "T%")\n .get();\n')),(0,r.kt)("p",null,"You may also pass a ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WhereItem>")," of conditions to the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," function. Each ",(0,r.kt)("inlineCode",{parentName:"p"},"Orm::WhereItem")," structure should contain the four arguments typically passed to the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where({\n {"status", 1}, // "=" by default\n {"subscribed", 1, "<>"},\n }).get();\n')),(0,r.kt)("h3",{id:"or-where-clauses"},"Or Where Clauses"),(0,r.kt)("p",null,"When chaining together calls to the query builder's ",(0,r.kt)("inlineCode",{parentName:"p"},"where"),' method, the "where" clauses will be joined together using the ',(0,r.kt)("inlineCode",{parentName:"p"},"and")," operator. However, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"orWhere")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"orWhereEq")," method to join a clause to the query using the ",(0,r.kt)("inlineCode",{parentName:"p"},"or")," operator. The ",(0,r.kt)("inlineCode",{parentName:"p"},"orWhere")," method accepts the same arguments as the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where("votes", ">", 100)\n .orWhere("name", "=", "John")\n .orWhereEq("name", "Jack")\n .get();\n')),(0,r.kt)("p",null,'If you need to group an "or" condition within parentheses, you may pass a lambda expression as the first argument to the ',(0,r.kt)("inlineCode",{parentName:"p"},"orWhere")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where("votes", ">", 100)\n .orWhere([](auto &query)\n {\n query.whereEq("name", "Abigail")\n .where("votes", ">", 50);\n })\n .get();\n')),(0,r.kt)("p",null,"The example above will produce the following SQL:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sql"},'select * from users where votes > 100 or (name = "Abigail" and votes > 50)\n')),(0,r.kt)("h3",{id:"condition-operator-overriding"},"Condition Operator Overriding"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," method overload with a ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WhereItem>")," as the first argument joins conditions using the ",(0,r.kt)("inlineCode",{parentName:"p"},"and")," operator by default:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where({\n {"first_name", "John"},\n {"votes", 50, ">"},\n }).get();\n')),(0,r.kt)("p",null,"Conditions operator can be overridden by the fourth argument in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Orm::WhereItem")," structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where({\n {"first_name", "John"},\n {"votes", 50, ">", "or"},\n }).get();\n')),(0,r.kt)("p",null,"Or by the second ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," argument, in this case all conditions will be joined by this condition, but it is still possible to override them by the fourth argument in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Orm::WhereItem")," structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where({\n {"first_name", "John"},\n {"last_name", "Smith"},\n {"votes", 50, ">", "and"},\n }, "or")\n .get();\n')),(0,r.kt)("p",null,"The example above will produce the following SQL:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sql"},'select * from users where (first_name = "John" or last_name = "Smith" and votes > 50)\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Still, it is a better idea to use ",(0,r.kt)("a",{parentName:"p",href:"#logical-grouping"},"Logical Grouping")," described few lines below, which allows better control of the parentheses.")),(0,r.kt)("h3",{id:"where-not-clauses"},"Where Not Clauses"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereNot")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"orWhereNot")," methods may be used to negate a given group of query constraints. For example, the following query excludes products that are on clearance or which have a price that is less than ten:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto products = DB::table("products")\n ->whereNot([](auto &query) {\n query.whereEq("clearance", true)\n .orWhere("price", "<", 10);\n })\n .get();\n')),(0,r.kt)("h3",{id:"additional-where-clauses"},"Additional Where Clauses"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereBetween / orWhereBetween")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereBetween")," method verifies that a column's value is between two values:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereBetween("votes", {1, 100})\n .get();\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereNotBetween / orWhereNotBetween")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereNotBetween")," method verifies that a column's value lies outside of two values:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereNotBetween("votes", {1, 100})\n .get();\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereBetweenColumns / orWhereBetweenColumns")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereBetweenColumns")," method verifies that a column's value is between two values in given columns:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto files = DB::table("files")\n ->whereBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})\n .get();\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereNotBetweenColumns / orWhereNotBetweenColumns")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereNotBetweenColumns")," method verifies that a column's value lies outside of two values in given columns:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto files = DB::table("files")\n ->whereNotBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})\n .get();\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereIn / whereNotIn / orWhereIn / orWhereNotIn")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereIn")," method verifies that a given column's value is contained within the given ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<QVariant>"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereIn("id", {1, 2, 3})\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereNotIn")," method verifies that the given column's value is not contained in the given ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<QVariant>"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereNotIn("id", {1, 2, 3})\n .get();\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereNull / whereNotNull / orWhereNull / orWhereNotNull")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereNull")," method verifies that the value of the given column is ",(0,r.kt)("inlineCode",{parentName:"p"},"NULL"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereNull("updated_at")\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereNotNull")," method verifies that the column's value is not ",(0,r.kt)("inlineCode",{parentName:"p"},"NULL"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereNotNull("updated_at")\n .get();\n')),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereDate / whereTime / whereDay / whereMonth / whereYear")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereDate")," method may be used to compare a column's value against a date:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereDate("created_at", EQ, QDate(2022, 11, 18))\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereTime")," method may be used to compare a column's value against a specific time:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereTime("created_at", "=", QTime(11, 14, 23))\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereDay")," method may be used to compare a column's value against a specific day of the month:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereDay("created_at", "<=", 15)\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereMonth")," method may be used to compare a column's value against a specific month:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereEqMonth("created_at", 12)\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereYear")," method may be used to compare a column's value against a specific year:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereEqYear("created_at", 2016)\n .get();\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereDate")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"whereTime")," methods also accept a ",(0,r.kt)("inlineCode",{parentName:"p"},"QDateTime")," instance or you can pass values as a ",(0,r.kt)("inlineCode",{parentName:"p"},"QString")," in ",(0,r.kt)("inlineCode",{parentName:"p"},"2022-12-31")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"09:15:11")," formats."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereDay"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"whereMoth"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"whereYear")," accept ",(0,r.kt)("inlineCode",{parentName:"p"},"QDate")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"QDateTime")," instances, an integral number or a ",(0,r.kt)("inlineCode",{parentName:"p"},"QString")," that contains an integral number."),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"All the above methods offer ",(0,r.kt)("inlineCode",{parentName:"p"},"whereEqXyz")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"orWhereXyz")," shortcut methods.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"whereColumn / orWhereColumn")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereColumnEq")," method may be used to verify that two columns are equal:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereColumnEq("first_name", "last_name")\n .get();\n')),(0,r.kt)("p",null,"You may also pass a comparison operator to the ",(0,r.kt)("inlineCode",{parentName:"p"},"whereColumn")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereColumn("updated_at", ">", "created_at")\n .get();\n')),(0,r.kt)("p",null,"You may also pass a ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<Orm::WhereColumnItem>")," of column comparisons to the ",(0,r.kt)("inlineCode",{parentName:"p"},"whereColumn")," method. These conditions will be joined using the ",(0,r.kt)("inlineCode",{parentName:"p"},"and")," operator:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereColumn({\n {"first_name", "last_name"},\n {"updated_at", "created_at", ">"},\n }).get();\n')),(0,r.kt)("p",null,"Conditions operator can also be overridden by the fourth argument in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Orm::WhereColumnItem")," structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereColumn({\n {"first_name", "last_name"},\n {"updated_at", "created_at", ">", "or"},\n }).get();\n')),(0,r.kt)("p",null,"Or by the second ",(0,r.kt)("inlineCode",{parentName:"p"},"whereColumn")," argument:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereColumn({\n {"first_name", "last_name"},\n {"updated_at", "created_at", ">"},\n }, "or")\n .get();\n')),(0,r.kt)("h3",{id:"logical-grouping"},"Logical Grouping"),(0,r.kt)("p",null,'Sometimes you may need to group several "where" clauses within parentheses in order to achieve your query\'s desired logical grouping. In fact, you should generally always group calls to the ',(0,r.kt)("inlineCode",{parentName:"p"},"orWhere")," method in parentheses in order to avoid unexpected query behavior. To accomplish this, you may pass a lambda expression to the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->where("name", "=", "John")\n .where([](auto &query)\n {\n query.where("votes", ">", 100)\n .orWhere("title", "=", "Admin");\n })\n .get();\n')),(0,r.kt)("p",null,"As you can see, passing a lambda expression into the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," method instructs the query builder to begin a constraint group. The lambda expression will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sql"},'select * from users where name = "John" and (votes > 100 or title = "Admin")\n')),(0,r.kt)("h2",{id:"advanced-where-clauses"},"Advanced Where Clauses"),(0,r.kt)("h3",{id:"where-exists-clauses"},"Where Exists Clauses"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"whereExists"),' method allows you to write "where exists" SQL clauses. The ',(0,r.kt)("inlineCode",{parentName:"p"},"whereExists"),' method accepts a lambda expression which will receive a query builder instance, allowing you to define the query that should be placed inside of the "exists" clause:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereExists([](auto &query)\n {\n query.select(DB::raw(1))\n .from("orders")\n .whereColumnEq("orders.user_id", "users.id");\n })\n .get();\n')),(0,r.kt)("p",null,"Alternatively, you may provide a query object to the ",(0,r.kt)("inlineCode",{parentName:"p"},"whereExists")," method instead of a lambda expression:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'// Ownership of the std::shared_ptr<QueryBuilder>\nauto builder = DB::table("orders");\nauto orders = builder->select(DB::raw(1))\n .whereColumnEq("orders.user_id", "users.id");\n\nauto users = DB::table("users")\n ->whereExists(orders)\n .get();\n')),(0,r.kt)("p",null,"Or directly:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->whereExists(DB::table("orders")\n ->select(DB::raw(1))\n .whereColumnEq("orders.user_id", "users.id"))\n .get();\n')),(0,r.kt)("p",null,"All of the examples above will produce the following SQL:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sql"},"select * from users\nwhere exists (\n select 1\n from orders\n where orders.user_id = users.id\n)\n")),(0,r.kt)("h3",{id:"subquery-where-clauses"},"Subquery Where Clauses"),(0,r.kt)("p",null,'Sometimes you may need to construct a "where" clause that compares the results of a subquery to a given value. You may accomplish this by passing a lambda expression and a value to the ',(0,r.kt)("inlineCode",{parentName:"p"},"where"),' method. For example, the following query will retrieve all users who have a recent "membership" of a given type:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include "models/user.hpp"\n\nauto users = User::whereEq([](auto &query)\n{\n query.select("type")\n .from("membership")\n .whereColumnEq("membership.user_id", "users.id")\n .orderByDesc("membership.start_date")\n .limit(1);\n}, "Pro")->get();\n')),(0,r.kt)("p",null,'Or, you may need to construct a "where" clause that compares a column to the results of a subquery. You may accomplish this by passing a column, operator, and lambda expression to the ',(0,r.kt)("inlineCode",{parentName:"p"},"where")," method. For example, the following query will retrieve all income records where the amount is less than average;"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'#include "models/income.hpp"\n\nauto incomes = Income::where("amount", "<", [](auto &query)\n{\n query.selectRaw("avg(i.amount)").from("incomes as i");\n})->get();\n')),(0,r.kt)("h2",{id:"ordering-grouping-limit-and-offset"},"Ordering, Grouping, Limit & Offset"),(0,r.kt)("h3",{id:"ordering"},"Ordering"),(0,r.kt)("h4",{id:"the-orderby-method"},"The ",(0,r.kt)("inlineCode",{parentName:"h4"},"orderBy")," Method"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"orderBy")," method allows you to sort the results of the query by a given column. The first argument accepted by the ",(0,r.kt)("inlineCode",{parentName:"p"},"orderBy")," method should be the column you wish to sort by, while the second argument determines the direction of the sort and may be either ",(0,r.kt)("inlineCode",{parentName:"p"},"asc")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"desc"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->orderBy("name", "desc")\n .get();\n')),(0,r.kt)("p",null,"To sort by multiple columns, you may simply invoke ",(0,r.kt)("inlineCode",{parentName:"p"},"orderBy")," as many times as necessary:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->orderBy("name", "desc")\n .orderBy("email", "asc")\n .get();\n')),(0,r.kt)("h4",{id:"the-latest--oldest-methods"},"The ",(0,r.kt)("inlineCode",{parentName:"h4"},"latest")," & ",(0,r.kt)("inlineCode",{parentName:"h4"},"oldest")," Methods"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"latest")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"oldest")," methods allow you to easily order results by date. By default, the result will be ordered by the table's ",(0,r.kt)("inlineCode",{parentName:"p"},"created_at")," column. Or, you may pass the column name that you wish to sort by:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto user = DB::table("users")\n ->latest()\n .first();\n')),(0,r.kt)("h4",{id:"random-ordering"},"Random Ordering"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"inRandomOrder")," method may be used to sort the query results randomly. For example, you may use this method to fetch a random user:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto randomUser = DB::table("users")\n ->inRandomOrder()\n .first();\n')),(0,r.kt)("h4",{id:"removing-existing-orderings"},"Removing Existing Orderings"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"reorder"),' method removes all of the "order by" clauses that have previously been applied to the query:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto &query = DB::table("users")->orderBy("name");\n\nauto unorderedUsers = query.reorder().get();\n')),(0,r.kt)("p",null,"You may pass a column and direction when calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"reorder"),' method in order to remove all existing "order by" clauses and apply an entirely new order to the query:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto &query = DB::table("users")->orderBy("name");\n\nauto usersOrderedByEmail = query.reorder("email", "desc").get();\n')),(0,r.kt)("h3",{id:"grouping"},"Grouping"),(0,r.kt)("h4",{id:"the-groupby--having-methods"},"The ",(0,r.kt)("inlineCode",{parentName:"h4"},"groupBy")," & ",(0,r.kt)("inlineCode",{parentName:"h4"},"having")," Methods"),(0,r.kt)("p",null,"As you might expect, the ",(0,r.kt)("inlineCode",{parentName:"p"},"groupBy")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"having")," methods may be used to group the query results. The ",(0,r.kt)("inlineCode",{parentName:"p"},"having")," method's signature is similar to that of the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->groupBy("account_id")\n .having("account_id", ">", 100)\n .get();\n')),(0,r.kt)("p",null,"You may pass multiple items to the ",(0,r.kt)("inlineCode",{parentName:"p"},"groupBy")," method to group by multiple columns:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->groupBy({"first_name", "status"})\n .having("account_id", ">", 100)\n .get();\n')),(0,r.kt)("h3",{id:"limit-and-offset"},"Limit & Offset"),(0,r.kt)("h4",{id:"the-skip--take-methods"},"The ",(0,r.kt)("inlineCode",{parentName:"h4"},"skip")," & ",(0,r.kt)("inlineCode",{parentName:"h4"},"take")," Methods"),(0,r.kt)("p",null,"You may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"skip")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"take")," methods to limit the number of results returned from the query or to skip a given number of results in the query:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")->skip(10).take(5).get();\n')),(0,r.kt)("p",null,"Alternatively, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"limit")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"offset")," methods. These methods are functionally equivalent to the ",(0,r.kt)("inlineCode",{parentName:"p"},"take")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"skip")," methods, respectively:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto users = DB::table("users")\n ->offset(10)\n .limit(5)\n .get();\n')),(0,r.kt)("h2",{id:"insert-statements"},"Insert Statements"),(0,r.kt)("p",null,"The query builder also provides an ",(0,r.kt)("inlineCode",{parentName:"p"},"insert")," method that may be used to insert records into the database table. The ",(0,r.kt)("inlineCode",{parentName:"p"},"insert")," method accepts the ",(0,r.kt)("inlineCode",{parentName:"p"},"QVariantMap")," of column names and values:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->insert({\n {"email", "kayla@example.com"},\n {"votes", 0},\n});\n')),(0,r.kt)("a",{id:"multi-insert-overload"}),(0,r.kt)("p",null,"You may insert several records at once by passing a ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<QString>")," for column names as the first argument and ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<QVector<QVariant>>")," for values as the second argument. Each ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<QVariant>")," represents a record that should be inserted into the table. This overload is useful for multi-insert and allows to specify column names only once:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->insert({"email", "votes"},\n{\n {"picard@example.com", 0},\n {"janeway@example.com", 0},\n});\n')),(0,r.kt)("p",null,"You may also insert several records at once by passing a ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<QVariantMap>"),". Each ",(0,r.kt)("inlineCode",{parentName:"p"},"QVariantMap")," represents a record that should be inserted into the table:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->insert({\n {{"email", "picard@example.com"}, {"votes", 0}},\n {{"email", "janeway@example.com"}, {"votes", 0}},\n});\n')),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"insertOrIgnore")," method will ignore duplicate record errors while inserting records into the database and also provides the same overloads like the ",(0,r.kt)("inlineCode",{parentName:"p"},"insert")," method. When using this method, you should be aware that duplicate record errors will be ignored and other types of errors may also be ignored depending on the database engine. For example, ",(0,r.kt)("inlineCode",{parentName:"p"},"insertOrIgnore")," will ",(0,r.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/refman/en/sql-mode.html#ignore-effect-on-execution"},"bypass MySQL's strict mode"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->insertOrIgnore({"id", "email"},\n{\n {1, "sisko@example.com"},\n {2, "archer@example.com"},\n});\n\nDB::table("users")->insertOrIgnore({\n {{"id", 1}, {"email", "sisko@example.com"}},\n {{"id", 2}, {"email", "archer@example.com"}},\n});\n')),(0,r.kt)("h4",{id:"auto-incrementing-ids"},"Auto-Incrementing IDs"),(0,r.kt)("p",null,"If the table has an auto-incrementing id, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"insertGetId")," method to insert a record and then retrieve the ID:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto id = DB::table("users")->insertGetId({\n {"email", "john@example.com"},\n {"votes", 0},\n});\n')),(0,r.kt)("h3",{id:"upserts"},"Upserts"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"upsert")," method will insert records that do not exist and update the records that already exist with new values that you may specify. 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 a vector of columns that should be updated if a matching record already exists in the database:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("flights")->upsert(\n {{{"departure", "Oakland"}, {"destination", "San Diego"}, {"price", 99}},\n {{"departure", "Chicago"}, {"destination", "New York"}, {"price", 150}}},\n {"departure", "destination"},\n {"price"}\n);\n')),(0,r.kt)("p",null,"In the example above, TinyORM will attempt to insert two records. If a record already exists with the same ",(0,r.kt)("inlineCode",{parentName:"p"},"departure")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"destination")," column values, TinyORM will update that record's ",(0,r.kt)("inlineCode",{parentName:"p"},"price")," column."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"All databases except SQL Server require the columns in the second argument of the ",(0,r.kt)("inlineCode",{parentName:"p"},"upsert"),' method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the ',(0,r.kt)("inlineCode",{parentName:"p"},"upsert"),' method and always uses the "primary" and "unique" indexes of the table to detect existing records.')),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"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,r.kt)("a",{parentName:"p",href:"https://dev.mysql.com/doc/refman/8.3/en/insert-on-duplicate.html"},"documentation"),". The MySQL server version is auto-detected and can be overridden in the ",(0,r.kt)("a",{parentName:"p",href:"/database/getting-started#configuration"},"configuration"),".")),(0,r.kt)("h2",{id:"update-statements"},"Update Statements"),(0,r.kt)("p",null,"In addition to inserting records into the database, the query builder can also update existing records using the ",(0,r.kt)("inlineCode",{parentName:"p"},"update")," method. The ",(0,r.kt)("inlineCode",{parentName:"p"},"update")," method, accepts a ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<Orm::UpdateItem>")," of column and value pairs, indicating the columns to be updated and returns a ",(0,r.kt)("inlineCode",{parentName:"p"},"std::tuple<int, QSqlQuery>")," . You may constrain the ",(0,r.kt)("inlineCode",{parentName:"p"},"update")," query using ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," clauses:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'auto [affected, query] = DB::table("users")\n ->whereEq("id", 1)\n .update({{"votes", 1}});\n')),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"An ",(0,r.kt)("inlineCode",{parentName:"p"},"update")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"delete")," are affecting statements, so they return ",(0,r.kt)("inlineCode",{parentName:"p"},"std::tuple<int, QSqlQuery>"),".")),(0,r.kt)("h4",{id:"update-or-insert"},"Update Or Insert"),(0,r.kt)("p",null,"Sometimes you may want to update an existing record in the database or create it if no matching record exists. In this scenario, the ",(0,r.kt)("inlineCode",{parentName:"p"},"updateOrInsert")," method may be used. The ",(0,r.kt)("inlineCode",{parentName:"p"},"updateOrInsert")," method accepts two arguments: a vector of conditions by which to find the record, and a vector of column and value pairs indicating the columns to be updated."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"updateOrInsert")," method will attempt to locate a matching database record using the first argument's column and value pairs. If the record exists, it will be updated with the values in the second argument. If the record can not be found, a new record will be inserted with the merged attributes of both arguments:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")\n ->updateOrInsert(\n {{"email", "john@example.com"}, {"name", "John"}},\n {{"votes", 2}}\n );\n')),(0,r.kt)("h3",{id:"increment-and-decrement"},"Increment & Decrement"),(0,r.kt)("p",null,"The query builder also provides convenient methods for incrementing or decrementing the value of a given column. Both of these methods accept at least one argument: the column to modify. A second argument may be provided to specify the amount by which the column should be incremented or decremented:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->increment<int>("votes");\n\nDB::table("users")->increment("votes", 5);\n\nDB::table("users")->decrement<int>("votes");\n\nDB::table("users")->decrement("votes", 5.2); // float or double type\n')),(0,r.kt)("p",null,"You may also specify additional columns to update during the operation as a ",(0,r.kt)("inlineCode",{parentName:"p"},"QVector<Orm::UpdateItem>"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->increment("votes", 1, {{"name", "John"}});\n')),(0,r.kt)("p",null,"You should constrain ",(0,r.kt)("inlineCode",{parentName:"p"},"increment"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"decrement")," by ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," to update only specific record in the database, otherwise a column in all records will be modified."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->whereEq("id", 1).increment("votes", 5);\n')),(0,r.kt)("h2",{id:"delete-statements"},"Delete Statements"),(0,r.kt)("p",null,"The query builder's ",(0,r.kt)("inlineCode",{parentName:"p"},"remove"),", or an alias ",(0,r.kt)("inlineCode",{parentName:"p"},"deleteRow")," method may be used to delete records from the table. You may constrain ",(0,r.kt)("inlineCode",{parentName:"p"},"delete"),' statements by adding "where" clauses before calling the ',(0,r.kt)("inlineCode",{parentName:"p"},"delete")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->remove();\n\nDB::table("users")->where("votes", ">", 100).remove();\n')),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("inlineCode",{parentName:"p"},"delete")," can not be used as the method name because it is the reserved word.")),(0,r.kt)("p",null,"You may also pass record ",(0,r.kt)("inlineCode",{parentName:"p"},"id")," to the ",(0,r.kt)("inlineCode",{parentName:"p"},"remove")," method as the first argument, it is the shortcut method, which internally calls ",(0,r.kt)("inlineCode",{parentName:"p"},"where"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->remove(2);\n')),(0,r.kt)("h3",{id:"truncate-statement"},"Truncate Statement"),(0,r.kt)("p",null,"If you wish to truncate an entire table, which will remove all records from the table and reset the auto-incrementing ID to zero, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"truncate")," method:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->truncate();\n')),(0,r.kt)("h4",{id:"table-truncation--postgresql"},"Table Truncation & PostgreSQL"),(0,r.kt)("p",null,"When truncating a PostgreSQL database, the ",(0,r.kt)("inlineCode",{parentName:"p"},"CASCADE")," behavior will be applied. This means that all foreign key related records in other tables will be deleted as well."),(0,r.kt)("h2",{id:"pessimistic-locking"},"Pessimistic Locking"),(0,r.kt)("p",null,'The query builder also includes a few functions to help you achieve "pessimistic locking" when executing your ',(0,r.kt)("inlineCode",{parentName:"p"},"select"),' statements. To execute a statement with a "shared lock", you may call the ',(0,r.kt)("inlineCode",{parentName:"p"},"sharedLock")," method. A shared lock prevents the selected rows from being modified until your transaction is committed:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")\n ->where("votes", ">", 100)\n .sharedLock()\n .get();\n')),(0,r.kt)("p",null,"Alternatively, you may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"lockForUpdate"),' method. A "for update" lock prevents the selected records from being modified or from being selected with another shared lock:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")\n ->where("votes", ">", 100)\n .lockForUpdate()\n .get();\n')),(0,r.kt)("h2",{id:"debugging"},"Debugging"),(0,r.kt)("p",null,"You may use the ",(0,r.kt)("inlineCode",{parentName:"p"},"dd")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"dump")," methods while building a query to dump the current query bindings and SQL. The ",(0,r.kt)("inlineCode",{parentName:"p"},"dd")," method will display the debug information and then stop executing using the ",(0,r.kt)("inlineCode",{parentName:"p"},"exit(1)"),". The ",(0,r.kt)("inlineCode",{parentName:"p"},"dump")," method will display the debug information and continue executing:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'DB::table("users")->where("votes", ">", 100).dd();\n\nDB::table("users")->where("votes", ">", 100).dump();\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cdf0eeb2.29f89fc3.js b/assets/js/cdf0eeb2.29f89fc3.js deleted file mode 100644 index 714daaf20..000000000 --- a/assets/js/cdf0eeb2.29f89fc3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[113],{7085:e=>{e.exports=JSON.parse('{"name":"docusaurus-theme-search-algolia","id":"default"}')}}]); \ No newline at end of file diff --git a/assets/js/d459b1c4.7a1fface.js b/assets/js/d459b1c4.7a1fface.js deleted file mode 100644 index 05be494ea..000000000 --- a/assets/js/d459b1c4.7a1fface.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[966],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});var i=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function a(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?l(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function o(e,t){if(null==e)return{};var n,i,r=function(e,t){if(null==e)return{};var n,i,r={},l=Object.keys(e);for(i=0;i<l.length;i++)n=l[i],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(i=0;i<l.length;i++)n=l[i],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=i.createContext({}),s=function(e){var t=i.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=s(e.components);return i.createElement(p.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},c=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),m=s(n),c=r,k=m["".concat(p,".").concat(c)]||m[c]||u[c]||l;return n?i.createElement(k,a(a({ref:t},d),{},{components:n})):i.createElement(k,a({ref:t},d))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,a=new Array(l);a[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:r,a[1]=o;for(var s=2;s<l;s++)a[s]=n[s];return i.createElement.apply(null,a)}return i.createElement.apply(null,n)}c.displayName="MDXCreateElement"},4742:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>u,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var i=n(7462),r=(n(7294),n(3905));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"]},a="Supported Compilers",o={unversionedId:"supported-compilers",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,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/supported-compilers.mdx",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"}},p={},s=[{value:"<code>Windows >=10</code>",id:"windows-10",level:4},{value:"<code>Linux</code>",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}],d={toc:s},m="wrapper";function u(e){let{components:t,...n}=e;return(0,r.kt)(m,(0,i.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"supported-compilers"},"Supported Compilers"),(0,r.kt)("p",null,"Following compilers are backed up by the GitHub Action ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyORM/tree/main/.github/workflows"},"workflows")," (CI pipelines), these workflows also include more then ",(0,r.kt)("strong",{parentName:"p"},"3366 unit tests")," \ud83d\ude2e\ud83d\udca5."),(0,r.kt)("div",{id:"supported-compilers"},(0,r.kt)("h4",{id:"windows-10"},(0,r.kt)("inlineCode",{parentName:"h4"},"Windows >=10")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"MSVC 2019 ",(0,r.kt)("inlineCode",{parentName:"li"},">=16.9")),(0,r.kt)("li",{parentName:"ul"},"MSVC 2022 ",(0,r.kt)("inlineCode",{parentName:"li"},">=17")),(0,r.kt)("li",{parentName:"ul"},"MSYS2 UCRT64 GCC ",(0,r.kt)("inlineCode",{parentName:"li"},"10.2")," - ",(0,r.kt)("inlineCode",{parentName:"li"},"13.2")),(0,r.kt)("li",{parentName:"ul"},"MSYS2 UCRT64 Clang ",(0,r.kt)("inlineCode",{parentName:"li"},">=15")),(0,r.kt)("li",{parentName:"ul"},"clang-cl ",(0,r.kt)("inlineCode",{parentName:"li"},">=15")," with MSVC 2019/2022")),(0,r.kt)("h4",{id:"linux"},(0,r.kt)("inlineCode",{parentName:"h4"},"Linux")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"GCC ",(0,r.kt)("inlineCode",{parentName:"li"},"10.2")," - ",(0,r.kt)("inlineCode",{parentName:"li"},"13.2")),(0,r.kt)("li",{parentName:"ul"},"Clang ",(0,r.kt)("inlineCode",{parentName:"li"},">=15")," ",(0,r.kt)("small",{className:"darker"},"(libstdc++ only)")))),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"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.")),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"macOS")," and Clang with ",(0,r.kt)("inlineCode",{parentName:"p"},"libc++")," are not supported.")),(0,r.kt)("h2",{id:"supported-build-systems"},"Supported build systems"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"CMake")," ",(0,r.kt)("inlineCode",{parentName:"li"},">=3.22")," ",(0,r.kt)("small",{className:"darker"},"(policies <= CMP0128 default to NEW)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"qmake")," distributed by the Qt Framework")),(0,r.kt)("h5",{id:"make-tools"},"Make tools"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"jom")," - highly recommended with the ",(0,r.kt)("inlineCode",{parentName:"li"},"qmake")," build system on Windows ",(0,r.kt)("small",{className:"darker"},"(replacement for nmake)")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"ninja")," - recommended for ",(0,r.kt)("inlineCode",{parentName:"li"},"CMake")," as the make file generator")),(0,r.kt)("h5",{id:"parallel-building"},"Parallel building"),(0,r.kt)("p",null,"You can control parallel building using the following environment variables."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"CMake - ",(0,r.kt)("inlineCode",{parentName:"li"},"CMAKE_BUILD_PARALLEL_LEVEL")," eg. to ",(0,r.kt)("inlineCode",{parentName:"li"},"10")),(0,r.kt)("li",{parentName:"ul"},"jom - ",(0,r.kt)("inlineCode",{parentName:"li"},"JOMFLAGS")," eg. to ",(0,r.kt)("inlineCode",{parentName:"li"},"j11")),(0,r.kt)("li",{parentName:"ul"},"make - ",(0,r.kt)("inlineCode",{parentName:"li"},"MAKEFLAGS")," eg. to ",(0,r.kt)("inlineCode",{parentName:"li"},"-j10")),(0,r.kt)("li",{parentName:"ul"},"vcpkg - ",(0,r.kt)("inlineCode",{parentName:"li"},"VCPKG_MAX_CONCURRENCY")," eg. to ",(0,r.kt)("inlineCode",{parentName:"li"},"10"))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d459b1c4.ebc2aae3.js b/assets/js/d459b1c4.ebc2aae3.js new file mode 100644 index 000000000..969fca74e --- /dev/null +++ b/assets/js/d459b1c4.ebc2aae3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[27],{7893:(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:"<code>Windows >=10</code>",id:"windows-10",level:4},{value:"<code>Linux</code>",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:"13.2"})]}),"\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:"13.2"})]}),"\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/e19c288b.cae4e49f.js b/assets/js/e19c288b.cae4e49f.js new file mode 100644 index 000000000..d06c5315b --- /dev/null +++ b/assets/js/e19c288b.cae4e49f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[69],{8157:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>d,toc:()=>l});var o=t(4848),r=t(8453),s=t(6684);const a={sidebar_position:8,sidebar_label:"\u2764\ufe0f Sponsors",hide_table_of_contents:!0,description:"How to sponsor and support the TinyORM project.",keywords:["c++ orm","tinyorm","support","fund","funding","sponsors","donations","sponsors"]},i="Sponsors",d={id:"sponsors",title:"Sponsors",description:"How to sponsor and support the TinyORM project.",source:"@site/docs/sponsors.mdx",sourceDirName:".",slug:"/sponsors",permalink:"/sponsors",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:8,frontMatter:{sidebar_position:8,sidebar_label:"\u2764\ufe0f Sponsors",hide_table_of_contents:!0,description:"How to sponsor and support the TinyORM project.",keywords:["c++ orm","tinyorm","support","fund","funding","sponsors","donations","sponsors"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\udcc4 Features Summary",permalink:"/features-summary"}},c={},l=[];function p(e){const n={a:"a",h1:"h1",p:"p",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"sponsors",children:"Sponsors"}),"\n",(0,o.jsx)(n.p,{children:"I have spent ~2 years every day 10 hours of coding (excluding weekends and sick days) to make this project real. Everything was funded from my personal resources, I had no problem with it to be honest, it was really fun \ud83c\udf89, but I had to move to the new apartment a few months ago and I'm out of money now. \u2639\ufe0f"}),"\n",(0,o.jsx)(n.p,{children:"I would like to continue developing and enhancing this project and I will as long as I can. But the future is unclear now."}),"\n",(0,o.jsx)("div",{id:"apitable-sponsors",children:(0,o.jsx)(s.A,{children:(0,o.jsxs)(n.table,{children:[(0,o.jsx)(n.thead,{children:(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.th,{children:"Service"}),(0,o.jsx)(n.th,{children:"Address"})]})}),(0,o.jsxs)(n.tbody,{children:[(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:"Bitcoin address"}),(0,o.jsx)(n.td,{children:"1NiF2cTvYxUj8FTZJnGn1ycN4yisWfo1vJ"})]}),(0,o.jsxs)(n.tr,{children:[(0,o.jsx)(n.td,{children:"PayPal"}),(0,o.jsx)(n.td,{children:(0,o.jsx)(n.a,{href:"https://paypal.me/silverzachara",children:"https://paypal.me/silverzachara"})})]})]})]})})})]})}function h(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(p,{...e})}):p(e)}},6684:(e,n,t)=>{t.d(n,{A:()=>l});var o=t(6540),r=t(3427),s=t(6347);const a={apiTable:"apiTable_flxF"};var i=t(4848);function d(e,n){let{name:t,children:a}=e;const d=function(e){let n=e;for(;(0,o.isValidElement)(n);)[n]=o.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}(a),c=t?`${t}-${d}`:d,l=`#${c}`,p=(0,s.W6)();return(0,r.A)().collectAnchor(c),(0,i.jsx)("tr",{id:c,tabIndex:0,ref:p.location.hash===l?n:void 0,onClick:e=>{const n=e.target;[n,n.parentElement].some((e=>"A"===e?.tagName.toUpperCase()))||p.push(l)},onKeyDown:e=>{"Enter"===e.key&&p.push(l)},children:a.props.children})}const c=o.forwardRef(d);function l(e){let{children:n,name:t}=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[r,s]=o.Children.toArray(n.props.children),d=(0,o.useRef)(null);(0,o.useEffect)((()=>{d.current?.focus()}),[d]);const l=o.Children.map(s.props.children,(e=>(0,i.jsx)(c,{name:t,ref:d,children:e})));return(0,i.jsxs)("table",{className:a.apiTable,children:[r,(0,i.jsx)("tbody",{children:l})]})}},8453:(e,n,t)=>{t.d(n,{R:()=>a,x:()=>i});var o=t(6540);const r={},s=o.createContext(r);function a(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e19c288b.fdce2815.js b/assets/js/e19c288b.fdce2815.js deleted file mode 100644 index 64d55f841..000000000 --- a/assets/js/e19c288b.fdce2815.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[865],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?a(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):a(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function i(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,s(s({ref:t},c),{},{components:r})):n.createElement(f,s({ref:t},c))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var p=2;p<a;p++)s[p]=r[p];return n.createElement.apply(null,s)}return n.createElement.apply(null,r)}m.displayName="MDXCreateElement"},5178:(e,t,r)=>{r.d(t,{Z:()=>l});var n=r(7294),o=r(6550);const a={apiTable:"apiTable_flxF"};function s(e,t){let{name:r,children:a}=e;const s=function(e){let t=e;for(;(0,n.isValidElement)(t);)[t]=n.Children.toArray(t.props.children);if("string"!=typeof t)throw new Error(`Could not extract APITable row name from JSX tree:\n${JSON.stringify(e,null,2)}`);return t}(a),i=r?`${r}-${s}`:s,l=`#${i}`,p=(0,o.k6)();return n.createElement("tr",{id:i,tabIndex:0,ref:p.location.hash===l?t:void 0,onClick:e=>{const t=e.target;"A"===t.tagName.toUpperCase()||"A"===t.parentElement?.tagName.toUpperCase()||p.push(l)},onKeyDown:e=>{"Enter"===e.key&&p.push(l)}},a.props.children)}const i=n.forwardRef(s);function l(e){let{children:t,name:r}=e;const[o,s]=n.Children.toArray(t.props.children),l=(0,n.useRef)(null);(0,n.useEffect)((()=>{l.current?.focus()}),[l]);const p=n.Children.map(s.props.children,(e=>n.createElement(i,{name:r,ref:l},e)));return n.createElement("table",{className:a.apiTable},o,n.createElement("tbody",null,p))}},6903:(e,t,r)=>{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>m,frontMatter:()=>s,metadata:()=>l,toc:()=>c});var n=r(7462),o=(r(7294),r(3905)),a=r(5178);const s={sidebar_position:8,sidebar_label:"\u2764\ufe0f Sponsors",hide_table_of_contents:!0,description:"How to sponsor and support the TinyORM project.",keywords:["c++ orm","tinyorm","support","fund","funding","sponsors","donations","sponsors"]},i="Sponsors",l={unversionedId:"sponsors",id:"sponsors",title:"Sponsors",description:"How to sponsor and support the TinyORM project.",source:"@site/docs/sponsors.mdx",sourceDirName:".",slug:"/sponsors",permalink:"/sponsors",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/sponsors.mdx",tags:[],version:"current",sidebarPosition:8,frontMatter:{sidebar_position:8,sidebar_label:"\u2764\ufe0f Sponsors",hide_table_of_contents:!0,description:"How to sponsor and support the TinyORM project.",keywords:["c++ orm","tinyorm","support","fund","funding","sponsors","donations","sponsors"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\udcc4 Features Summary",permalink:"/features-summary"}},p={},c=[],u={toc:c},d="wrapper";function m(e){let{components:t,...r}=e;return(0,o.kt)(d,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"sponsors"},"Sponsors"),(0,o.kt)("p",null,"I have spent ~2 years every day 10 hours of coding (excluding weekends and sick days) to make this project real. Everything was funded from my personal resources, I had no problem with it to be honest, it was really fun \ud83c\udf89, but I had to move to the new apartment a few months ago and I'm out of money now. \u2639\ufe0f"),(0,o.kt)("p",null,"I would like to continue developing and enhancing this project and I will as long as I can. But the future is unclear now."),(0,o.kt)(a.Z,{mdxType:"APITable"},(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Service"),(0,o.kt)("th",{parentName:"tr",align:null},"Address"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Bitcoin address"),(0,o.kt)("td",{parentName:"tr",align:null},"1NiF2cTvYxUj8FTZJnGn1ycN4yisWfo1vJ")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"PayPal"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"https://paypal.me/silverzachara"},"https://paypal.me/silverzachara")))))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e3ac21cb.61732115.js b/assets/js/e3ac21cb.61732115.js new file mode 100644 index 000000000..831c6e468 --- /dev/null +++ b/assets/js/e3ac21cb.61732115.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[467],{7759:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>o,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>a,toc:()=>l});var r=t(4848),d=t(8453);const i={sidebar_position:1,sidebar_label:"\ud83d\udd27 Dependencies",hide_table_of_contents:!0,description:"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.",keywords:["c++ orm","dependencies","tinyorm"]},s="Dependencies",a={id:"dependencies",title:"Dependencies",description:"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.",source:"@site/docs/dependencies.mdx",sourceDirName:".",slug:"/dependencies",permalink:"/dependencies",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,sidebar_label:"\ud83d\udd27 Dependencies",hide_table_of_contents:!0,description:"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.",keywords:["c++ orm","dependencies","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\udd25 Prologue",permalink:"/"},next:{title:"\ud83d\ude80 Supported Compilers",permalink:"/supported-compilers"}},o={},l=[{value:"Required",id:"required",level:5},{value:"Optional",id:"optional",level:5},{value:"Install dependencies",id:"install-dependencies",level:3}];function c(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h3:"h3",h5:"h5",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,d.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h1,{id:"dependencies",children:"Dependencies"}),"\n",(0,r.jsx)(n.p,{children:"The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-18, so may be assumed it will work on future releases of these compilers. Minimum required ISO C++ standard is C++20.\nThe Qt framework version used during development was 5.15.2 and >=6.2."}),"\n",(0,r.jsx)(n.h5,{id:"required",children:"Required"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"minimum ISO C++ standard is C++20"}),"\n",(0,r.jsxs)(n.li,{children:[">= ",(0,r.jsx)(n.a,{href:"https://www.qt.io/download-qt-installer",children:"Qt Framework 5.15.2"})," - ",(0,r.jsx)(n.a,{href:"https://doc.qt.io/qt-5/qtcore-module.html",children:(0,r.jsx)(n.code,{children:"QtCore"})})," and ",(0,r.jsx)(n.a,{href:"https://doc.qt.io/qt-5/qtsql-index.html",children:(0,r.jsx)(n.code,{children:"QtSql"})})," modules"]}),"\n",(0,r.jsxs)(n.li,{children:[">= ",(0,r.jsx)(n.a,{href:"https://www.qt.io/download-qt-installer",children:"Qt Framework 6.2"})," - ",(0,r.jsx)(n.a,{href:"https://doc.qt.io/qt-6/qtcore-module.html",children:(0,r.jsx)(n.code,{children:"QtCore"})})," and ",(0,r.jsx)(n.a,{href:"https://doc.qt.io/qt-6/qtsql-index.html",children:(0,r.jsx)(n.code,{children:"QtSql"})})," modules"]}),"\n",(0,r.jsxs)(n.li,{children:[">= ",(0,r.jsx)(n.a,{href:"https://github.com/ericniebler/range-v3",children:"range-v3 0.11.0"})]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://github.com/p-ranav/tabulate",children:"tabulate"})}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"warning",children:(0,r.jsxs)(n.p,{children:["Be aware that the standard support for the last release of the ",(0,r.jsx)(n.strong,{children:"Qt 5"})," series ended on ",(0,r.jsx)(n.strong,{children:"26. May 2023"}),". [",(0,r.jsx)(n.a,{href:"https://endoflife.date/qt",children:"1"}),"][",(0,r.jsx)(n.a,{href:"https://www.qt.io/blog/qt-5.15-support-ends",children:"2"}),"]"]})}),"\n",(0,r.jsx)(n.h5,{id:"optional",children:"Optional"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[">= ",(0,r.jsx)(n.a,{href:"https://dev.mysql.com/downloads/c-api/",children:"MySQL Connector/C 8"})," - used only for the ",(0,r.jsx)(n.a,{href:"https://dev.mysql.com/doc/c-api/8.3/en/mysql-ping.html",children:(0,r.jsx)(n.code,{children:"mysql_ping"})})," function and provided by ",(0,r.jsx)(n.a,{href:"https://dev.mysql.com/downloads/mysql/",children:"MySQL 8 Server"})]}),"\n"]}),"\n",(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"TinyORM"})," will support ",(0,r.jsx)(n.code,{children:"Qt"})," versions that aren't ",(0,r.jsx)(n.a,{href:"https://endoflife.date/qt",children:"end-of-life"}),"."]})}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["You can view the supported database servers in the ",(0,r.jsx)(n.a,{href:"/database/getting-started#introduction",children:"Database - Getting Started"})," section."]})}),"\n",(0,r.jsx)(n.h3,{id:"install-dependencies",children:"Install dependencies"}),"\n",(0,r.jsxs)(n.p,{children:["On ",(0,r.jsx)(n.code,{children:"Linux"}),", you can install dependencies with the package manager."]}),"\n",(0,r.jsxs)("small",{children:[(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",metastring:"title='MySQL C library'",children:"Arch - pacman -S mariadb-libs\nGentoo - emerge dev-db/mysql (package.use: -server -perl)\nUbuntu - apt install libmysqlclient-dev\n"})}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",metastring:"title='range-v3 library (header only)'",children:"Arch - pacman -S range-v3\nGentoo - emerge dev-cpp/range-v3\nUbuntu - apt install librange-v3-dev\n"})}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-text",metastring:"title='ccache'",children:"Arch - pacman -S ccache\nGentoo - emerge dev-util/ccache\nUbuntu - apt install ccache\n"})})]})]})}function h(e={}){const{wrapper:n}={...(0,d.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>s,x:()=>a});var r=t(6540);const d={},i=r.createContext(d);function s(e){const n=r.useContext(i);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(d):e.components||d:s(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/e3ac21cb.9751aa02.js b/assets/js/e3ac21cb.9751aa02.js deleted file mode 100644 index 705d88b0f..000000000 --- a/assets/js/e3ac21cb.9751aa02.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[8],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){r(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},i=Object.keys(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a<i.length;a++)n=i[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var d=a.createContext({}),p=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},s=function(e){var t=p(e.components);return a.createElement(d.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,d=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),c=p(n),u=r,h=c["".concat(d,".").concat(u)]||c[u]||m[u]||i;return n?a.createElement(h,o(o({ref:t},s),{},{components:n})):a.createElement(h,o({ref:t},s))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=u;var l={};for(var d in t)hasOwnProperty.call(t,d)&&(l[d]=t[d]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p<i;p++)o[p]=n[p];return a.createElement.apply(null,o)}return a.createElement.apply(null,n)}u.displayName="MDXCreateElement"},5136:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={sidebar_position:1,sidebar_label:"\ud83d\udd27 Dependencies",hide_table_of_contents:!0,description:"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.",keywords:["c++ orm","dependencies","tinyorm"]},o="Dependencies",l={unversionedId:"dependencies",id:"dependencies",title:"Dependencies",description:"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.",source:"@site/docs/dependencies.mdx",sourceDirName:".",slug:"/dependencies",permalink:"/dependencies",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/dependencies.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1,sidebar_label:"\ud83d\udd27 Dependencies",hide_table_of_contents:!0,description:"Library dependencies are MySQL Connector/C 8, range-v3 >=0.11.0, tabulate and the Qt framework version used during development was 5.15.2 and >=6.2. The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-16.",keywords:["c++ orm","dependencies","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"\ud83d\udd25 Prologue",permalink:"/"},next:{title:"\ud83d\ude80 Supported Compilers",permalink:"/supported-compilers"}},d={},p=[{value:"Required",id:"required",level:5},{value:"Optional",id:"optional",level:5},{value:"Install dependencies",id:"install-dependencies",level:3}],s={toc:p},c="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(c,(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"dependencies"},"Dependencies"),(0,r.kt)("p",null,"The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-18, so may be assumed it will work on future releases of these compilers. Minimum required ISO C++ standard is C++20.\nThe Qt framework version used during development was 5.15.2 and >=6.2."),(0,r.kt)("h5",{id:"required"},"Required"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"minimum ISO C++ standard is C++20"),(0,r.kt)("li",{parentName:"ul"},">","= ",(0,r.kt)("a",{parentName:"li",href:"https://www.qt.io/download-qt-installer"},"Qt Framework 5.15.2")," - ",(0,r.kt)("a",{parentName:"li",href:"https://doc.qt.io/qt-5/qtcore-module.html"},(0,r.kt)("inlineCode",{parentName:"a"},"QtCore"))," and ",(0,r.kt)("a",{parentName:"li",href:"https://doc.qt.io/qt-5/qtsql-index.html"},(0,r.kt)("inlineCode",{parentName:"a"},"QtSql"))," modules"),(0,r.kt)("li",{parentName:"ul"},">","= ",(0,r.kt)("a",{parentName:"li",href:"https://www.qt.io/download-qt-installer"},"Qt Framework 6.2")," - ",(0,r.kt)("a",{parentName:"li",href:"https://doc.qt.io/qt-6/qtcore-module.html"},(0,r.kt)("inlineCode",{parentName:"a"},"QtCore"))," and ",(0,r.kt)("a",{parentName:"li",href:"https://doc.qt.io/qt-6/qtsql-index.html"},(0,r.kt)("inlineCode",{parentName:"a"},"QtSql"))," modules"),(0,r.kt)("li",{parentName:"ul"},">","= ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/ericniebler/range-v3"},"range-v3 0.11.0")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://github.com/p-ranav/tabulate"},"tabulate"))),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Be aware that the standard support for the last release of the ",(0,r.kt)("strong",{parentName:"p"},"Qt 5")," series ended on ",(0,r.kt)("strong",{parentName:"p"},"26. May 2023"),". [",(0,r.kt)("a",{parentName:"p",href:"https://endoflife.date/qt"},"1"),"][",(0,r.kt)("a",{parentName:"p",href:"https://www.qt.io/blog/qt-5.15-support-ends"},"2"),"]")),(0,r.kt)("h5",{id:"optional"},"Optional"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},">","= ",(0,r.kt)("a",{parentName:"li",href:"https://dev.mysql.com/downloads/c-api/"},"MySQL Connector/C 8")," - used only for the ",(0,r.kt)("a",{parentName:"li",href:"https://dev.mysql.com/doc/c-api/8.3/en/mysql-ping.html"},(0,r.kt)("inlineCode",{parentName:"a"},"mysql_ping"))," function and provided by ",(0,r.kt)("a",{parentName:"li",href:"https://dev.mysql.com/downloads/mysql/"},"MySQL 8 Server"))),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"TinyORM")," will support ",(0,r.kt)("inlineCode",{parentName:"p"},"Qt")," versions that aren't ",(0,r.kt)("a",{parentName:"p",href:"https://endoflife.date/qt"},"end-of-life"),".")),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"You can view the supported database servers in the ",(0,r.kt)("a",{parentName:"p",href:"/database/getting-started#introduction"},"Database - Getting Started")," section.")),(0,r.kt)("h3",{id:"install-dependencies"},"Install dependencies"),(0,r.kt)("p",null,"On ",(0,r.kt)("inlineCode",{parentName:"p"},"Linux"),", you can install dependencies with the package manager."),(0,r.kt)("small",null,(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-text",metastring:"title='MySQL C library'",title:"'MySQL",C:!0,"library'":!0},"Arch - pacman -S mariadb-libs\nGentoo - emerge dev-db/mysql (package.use: -server -perl)\nUbuntu - apt install libmysqlclient-dev\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-text",metastring:"title='range-v3 library (header only)'",title:"'range-v3",library:!0,"(header":!0,"only)'":!0},"Arch - pacman -S range-v3\nGentoo - emerge dev-cpp/range-v3\nUbuntu - apt install librange-v3-dev\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-text",metastring:"title='ccache'",title:"'ccache'"},"Arch - pacman -S ccache\nGentoo - emerge dev-util/ccache\nUbuntu - apt install ccache\n"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/fb313d4e.1478a8fb.js b/assets/js/fb313d4e.1478a8fb.js new file mode 100644 index 000000000..386ddcf7a --- /dev/null +++ b/assets/js/fb313d4e.1478a8fb.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[871],{7626:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>o,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var i=s(4848),t=s(8453);const r={sidebar_position:7,sidebar_label:"\ud83d\udcc4 Features Summary",hide_table_of_contents:!0,description:"List that fastly summarizes all TinyORM features.",keywords:["c++ orm","tinyorm","features","summary","features summary"]},a="Features Summary",l={id:"features-summary",title:"Features Summary",description:"List that fastly summarizes all TinyORM features.",source:"@site/docs/features-summary.mdx",sourceDirName:".",slug:"/features-summary",permalink:"/features-summary",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7,sidebar_label:"\ud83d\udcc4 Features Summary",hide_table_of_contents:!0,description:"List that fastly summarizes all TinyORM features.",keywords:["c++ orm","tinyorm","features","summary","features summary"]},sidebar:"tinyormSidebar",previous:{title:"Migrations",permalink:"/building/migrations"},next:{title:"\u2764\ufe0f Sponsors",permalink:"/sponsors"}},o={},d=[{value:"Summary List",id:"summary-list",level:2},{value:"Showcase Images",id:"showcase-images",level:2},{value:"Tom console application",id:"tom-console-application",level:6},{value:"Passed all unit tests \ud83e\udd73",id:"passed-all-unit-tests-",level:6},{value:"TinyOrmPlayground",id:"tinyormplayground",level:4},{value:"TinyOrmPlayground single-threaded",id:"tinyormplayground-single-threaded",level:6},{value:"TinyOrmPlayground multi-threaded",id:"tinyormplayground-multi-threaded",level:6}];function c(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h4:"h4",h6:"h6",li:"li",p:"p",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"features-summary",children:"Features Summary"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#summary-list",children:"Summary List"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#showcase-images",children:"Showcase Images"})}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"summary-list",children:"Summary List"}),"\n",(0,i.jsxs)(n.p,{children:["The following list fastly summarizes all the ",(0,i.jsx)(n.code,{children:"TinyORM"})," features."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"simple database connections management"})," \ud83e\uddec","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"database manager that helps with the database connections management"}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"Orm::DB"})," facade class for nicer and shorter syntax"]}),"\n",(0,i.jsxs)(n.li,{children:["MySQL, MariaDB, SQLite, and PostgreSQL support for ",(0,i.jsx)(n.strong,{children:"all"})," features \ud83d\udc8e"]}),"\n",(0,i.jsx)(n.li,{children:"multi-threading support \ud83d\udc40"}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"SSL"})," connections support \ud83d\udd12"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"impressive query builder"})," \ud83d\udd27","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"allows passing sub-queries and raw expressions practically everywhere, to column names, values, and to every SQL clause as select, where, joins, group by, having, order by \ud83d\udd25"}),"\n",(0,i.jsx)(n.li,{children:"a logical grouping that offers to wrap logical groups in parenthesis"}),"\n",(0,i.jsx)(n.li,{children:"chunked results for lower memory footprint \u2728"}),"\n",(0,i.jsx)(n.li,{children:"raw methods for all SQL clauses"}),"\n",(0,i.jsx)(n.li,{children:"all join types (left, right, cross, inner) and also join where clause support \ud83e\udee4"}),"\n",(0,i.jsx)(n.li,{children:"aggregate methods min, max, sum, increment, decrement, ..."}),"\n",(0,i.jsx)(n.li,{children:"whereExists and exists methods for an existence queries"}),"\n",(0,i.jsx)(n.li,{children:"transactions and pessimistic locking \ud83d\udd12"}),"\n",(0,i.jsx)(n.li,{children:"of course, insert, update, and delete SQL clauses support"}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"correct QDateTime time zone"})," using the ",(0,i.jsx)(n.code,{children:"qt_timezone"})," connection configuration option \ud83d\udcc5 (returned QDateTime instances will have the correct time zone, and also works for an ORM)","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"this feature allows you to set up the database server time zone to the UTC and all returned QDateTime instances will have the correct UTC time zone"}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"clever ORM with all relation types support"})," \ud83c\udf89","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"one-to-one, one-to-many, and many-to-many relation types (also inverse relationships) \ud83e\udde8"}),"\n",(0,i.jsx)(n.li,{children:"eager and lazy loading with custom select and constraints \ud83d\ude80"}),"\n",(0,i.jsxs)(n.li,{children:["fluent ",(0,i.jsx)(n.code,{children:"ModelsCollection"})," that expose a variety of map / reduce operations that may be chained using an intuitive interface \u2728"]}),"\n",(0,i.jsx)(n.li,{children:"all query builder methods are proxied from the model instances and also from the relation instances back to the query builder \ud83e\udd2f (everything that can be called on the query builder can also be called on the model and relation instances)"}),"\n",(0,i.jsx)(n.li,{children:"clean active record pattern"}),"\n",(0,i.jsxs)(n.li,{children:["advanced features like timestamps, touching parent timestamps, ",(0,i.jsx)(n.strong,{children:"soft deleting"}),", default models, default model attributes, and attribute casting \ud83e\udd13"]}),"\n",(0,i.jsxs)(n.li,{children:["querying relationships existence/absence using the has, whereHas, and hasNested methods (using dot notation for selecting nested relationships ",(0,i.jsx)(n.em,{children:"users.posts.comments"}),")"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"serializing"})," models and collection of models including all nested relations to ",(0,i.jsx)(n.strong,{children:"JSON"})," and converting to vectors and maps \ud83e\udea1","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"supports controlling a custom date format during serialization"}),"\n",(0,i.jsx)(n.li,{children:"supports hiding and appending attributes"}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"compiled database migrations and seeders"})," \ud83d\udd7a","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"create, update, drop, and rename database tables"}),"\n",(0,i.jsx)(n.li,{children:"create, drop, and rename table columns"}),"\n",(0,i.jsx)(n.li,{children:"extensive schema builder that allows creating of all possible column types"}),"\n",(0,i.jsx)(n.li,{children:"terser syntax for creating foreign keys and foreign key constraints"}),"\n",(0,i.jsx)(n.li,{children:"supports creating, and dropping column indexes (primary, unique, fulltext, spatial)"}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsxs)(n.strong,{children:["the ",(0,i.jsx)(n.code,{children:"tom"})," console application with tab completion for all shells (pwsh, bash, zsh)"]})," \ud83e\udd73","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"scaffolding of models, migrations, and seeders"}),"\n",(0,i.jsxs)(n.li,{children:["impressive models scaffolding, every feature that is supported by models can be generated using the ",(0,i.jsx)(n.code,{children:"tom make:model"})," cli command"]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["a huge amount of code is unit tested, currently ",(0,i.jsx)(n.strong,{children:"3366 unit tests"})," \ud83e\udd2f"]}),"\n",(0,i.jsxs)(n.li,{children:["C++20 only, with all the latest features used like concepts/constraints, ranges, smart pointers (no ",(0,i.jsx)(n.code,{children:"new"})," keyword in the whole code \ud83d\ude0e), folding expressions"]}),"\n",(0,i.jsxs)(n.li,{children:["qmake and CMake build systems support","\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"CMake FetchContent module support \ud83e\udd19"}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.li,{children:"vcpkg support (also the vcpkg port, currently not committed to the vcpkg repository \u2639\ufe0f)"}),"\n",(0,i.jsx)(n.li,{children:"it's really fast, you can run 1000 complex queries in 500ms (heavily DB dependant, the PostgreSQL is by far the fastest) \u231a"}),"\n",(0,i.jsx)(n.li,{children:"extensive documentation \ud83d\udcc3"}),"\n",(0,i.jsx)(n.li,{children:"..."}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["See the ",(0,i.jsx)(n.code,{children:"TinyDrivers"})," ",(0,i.jsx)(n.a,{href:"tinydrivers/getting-started#features-summary",children:"Features summary"}),"."]})}),"\n",(0,i.jsx)(n.h2,{id:"showcase-images",children:"Showcase Images"}),"\n",(0,i.jsx)(n.h6,{id:"tom-console-application",children:"Tom console application"}),"\n",(0,i.jsx)("img",{src:s(5848).A,alt:"TinyORM - Tom console application - Showcase",title:"Tom console application"}),"\n",(0,i.jsx)(n.h6,{id:"passed-all-unit-tests-",children:"Passed all unit tests \ud83e\udd73"}),"\n",(0,i.jsx)("img",{src:s(8994).A,alt:"TinyORM - Passed all unit tests - Showcase",title:"Passed all unit tests",width:"700",className:"no-blurry"}),"\n",(0,i.jsx)(n.h4,{id:"tinyormplayground",children:"TinyOrmPlayground"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyOrmPlayground",children:"TinyOrmPlayground"})," project is my personal project where I have tested all the TinyORM database queries in the early development phases, currently, it executes ~1600 database queries across the whole TinyORM framework. Every query has a nice title header, is logged to the console, and is counted and measured (elapsed time). Every query also runs on all ",(0,i.jsx)(n.a,{href:"/database/getting-started#introduction",children:"supported databases"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The TinyOrmPlayground project can be compiled in a single-threaded or multi-threaded mode. In the multi-threaded mode, every database connection runs in its own thread. At the end of every database connection is logged a connection summary and before an exit is logged the application summary. Whole TinyOrmPlayground application is configurable through the ",(0,i.jsx)(n.a,{href:"https://github.com/silverqx/TinyOrmPlayground/blob/main/src/configuration.hpp",children:"src/configuration.hpp"})," class."]}),"\n",(0,i.jsx)(n.h6,{id:"tinyormplayground-single-threaded",children:"TinyOrmPlayground single-threaded"}),"\n",(0,i.jsx)("img",{src:s(3672).A,alt:"TinyORM - Invoked TinyOrmPlayground single-threaded - Showcase",title:"Invoked TinyOrmPlayground single-threaded"}),"\n",(0,i.jsx)(n.h6,{id:"tinyormplayground-multi-threaded",children:"TinyOrmPlayground multi-threaded"}),"\n",(0,i.jsx)("img",{src:s(2599).A,alt:"TinyORM - Invoked TinyOrmPlayground multi-threaded - Showcase",title:"Invoked TinyOrmPlayground multi-threaded"})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},8994:(e,n,s)=>{s.d(n,{A:()=>i});const i=s.p+"assets/images/tinyorm-passed_all_unit_tests-d730d995b6b490fb42c3671738e3b81e.png"},2599:(e,n,s)=>{s.d(n,{A:()=>i});const i=s.p+"assets/images/tinyormplayground-multi-threaded-edb67030c75e2845e1fa7013e510174c.png"},3672:(e,n,s)=>{s.d(n,{A:()=>i});const i=s.p+"assets/images/tinyormplayground-single-threaded-4e7a5769ad5a768a4d04c6dc856c4391.png"},5848:(e,n,s)=>{s.d(n,{A:()=>i});const i=s.p+"assets/images/tom_cli-402f7dd4dfe7dbd0b20dfe5fb61838a2.png"},8453:(e,n,s)=>{s.d(n,{R:()=>a,x:()=>l});var i=s(6540);const t={},r=i.createContext(t);function a(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:a(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/fb313d4e.246c2a2a.js b/assets/js/fb313d4e.246c2a2a.js deleted file mode 100644 index a8c506088..000000000 --- a/assets/js/fb313d4e.246c2a2a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[832],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>y});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?i(Object(a),!0).forEach((function(t){r(e,t,a[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):i(Object(a)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))}))}return e}function s(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=n.createContext({}),m=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},u=function(e){var t=m(e.components);return n.createElement(o.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=m(a),c=r,y=p["".concat(o,".").concat(c)]||p[c]||d[c]||i;return a?n.createElement(y,l(l({ref:t},u),{},{components:a})):n.createElement(y,l({ref:t},u))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,l=new Array(i);l[0]=c;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[p]="string"==typeof e?e:r,l[1]=s;for(var m=2;m<i;m++)l[m]=a[m];return n.createElement.apply(null,l)}return n.createElement.apply(null,a)}c.displayName="MDXCreateElement"},4716:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>m});var n=a(7462),r=(a(7294),a(3905));const i={sidebar_position:7,sidebar_label:"\ud83d\udcc4 Features Summary",hide_table_of_contents:!0,description:"List that fastly summarizes all TinyORM features.",keywords:["c++ orm","tinyorm","features","summary","features summary"]},l="Features Summary",s={unversionedId:"features-summary",id:"features-summary",title:"Features Summary",description:"List that fastly summarizes all TinyORM features.",source:"@site/docs/features-summary.mdx",sourceDirName:".",slug:"/features-summary",permalink:"/features-summary",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/features-summary.mdx",tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7,sidebar_label:"\ud83d\udcc4 Features Summary",hide_table_of_contents:!0,description:"List that fastly summarizes all TinyORM features.",keywords:["c++ orm","tinyorm","features","summary","features summary"]},sidebar:"tinyormSidebar",previous:{title:"Migrations",permalink:"/building/migrations"},next:{title:"\u2764\ufe0f Sponsors",permalink:"/sponsors"}},o={},m=[{value:"Summary List",id:"summary-list",level:2},{value:"Showcase Images",id:"showcase-images",level:2},{value:"Tom console application",id:"tom-console-application",level:6},{value:"Passed all unit tests \ud83e\udd73",id:"passed-all-unit-tests-",level:6},{value:"TinyOrmPlayground",id:"tinyormplayground",level:4},{value:"TinyOrmPlayground single-threaded",id:"tinyormplayground-single-threaded",level:6},{value:"TinyOrmPlayground multi-threaded",id:"tinyormplayground-multi-threaded",level:6}],u={toc:m},p="wrapper";function d(e){let{components:t,...i}=e;return(0,r.kt)(p,(0,n.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"features-summary"},"Features Summary"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#summary-list"},"Summary List")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#showcase-images"},"Showcase Images"))),(0,r.kt)("h2",{id:"summary-list"},"Summary List"),(0,r.kt)("p",null,"The following list fastly summarizes all the ",(0,r.kt)("inlineCode",{parentName:"p"},"TinyORM")," features."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"simple database connections management")," \ud83e\uddec",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"database manager that helps with the database connections management"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"Orm::DB")," facade class for nicer and shorter syntax"),(0,r.kt)("li",{parentName:"ul"},"MySQL, MariaDB, SQLite, and PostgreSQL support for ",(0,r.kt)("strong",{parentName:"li"},"all")," features \ud83d\udc8e"),(0,r.kt)("li",{parentName:"ul"},"multi-threading support \ud83d\udc40"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"SSL")," connections support \ud83d\udd12"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"impressive query builder")," \ud83d\udd27",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"allows passing sub-queries and raw expressions practically everywhere, to column names, values, and to every SQL clause as select, where, joins, group by, having, order by \ud83d\udd25"),(0,r.kt)("li",{parentName:"ul"},"a logical grouping that offers to wrap logical groups in parenthesis"),(0,r.kt)("li",{parentName:"ul"},"chunked results for lower memory footprint \u2728"),(0,r.kt)("li",{parentName:"ul"},"raw methods for all SQL clauses"),(0,r.kt)("li",{parentName:"ul"},"all join types (left, right, cross, inner) and also join where clause support \ud83e\udee4"),(0,r.kt)("li",{parentName:"ul"},"aggregate methods min, max, sum, increment, decrement, ..."),(0,r.kt)("li",{parentName:"ul"},"whereExists and exists methods for an existence queries"),(0,r.kt)("li",{parentName:"ul"},"transactions and pessimistic locking \ud83d\udd12"),(0,r.kt)("li",{parentName:"ul"},"of course, insert, update, and delete SQL clauses support"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"correct QDateTime time zone")," using the ",(0,r.kt)("inlineCode",{parentName:"li"},"qt_timezone")," connection configuration option \ud83d\udcc5 (returned QDateTime instances will have the correct time zone, and also works for an ORM)",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"this feature allows you to set up the database server time zone to the UTC and all returned QDateTime instances will have the correct UTC time zone"))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"clever ORM with all relation types support")," \ud83c\udf89",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"one-to-one, one-to-many, and many-to-many relation types (also inverse relationships) \ud83e\udde8"),(0,r.kt)("li",{parentName:"ul"},"eager and lazy loading with custom select and constraints \ud83d\ude80"),(0,r.kt)("li",{parentName:"ul"},"fluent ",(0,r.kt)("inlineCode",{parentName:"li"},"ModelsCollection")," that expose a variety of map / reduce operations that may be chained using an intuitive interface \u2728"),(0,r.kt)("li",{parentName:"ul"},"all query builder methods are proxied from the model instances and also from the relation instances back to the query builder \ud83e\udd2f (everything that can be called on the query builder can also be called on the model and relation instances)"),(0,r.kt)("li",{parentName:"ul"},"clean active record pattern"),(0,r.kt)("li",{parentName:"ul"},"advanced features like timestamps, touching parent timestamps, ",(0,r.kt)("strong",{parentName:"li"},"soft deleting"),", default models, default model attributes, and attribute casting \ud83e\udd13"),(0,r.kt)("li",{parentName:"ul"},"querying relationships existence/absence using the has, whereHas, and hasNested methods (using dot notation for selecting nested relationships ",(0,r.kt)("em",{parentName:"li"},"users.posts.comments"),")"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"serializing")," models and collection of models including all nested relations to ",(0,r.kt)("strong",{parentName:"li"},"JSON")," and converting to vectors and maps \ud83e\udea1",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"supports controlling a custom date format during serialization"),(0,r.kt)("li",{parentName:"ul"},"supports hiding and appending attributes"))))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"compiled database migrations and seeders")," \ud83d\udd7a",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"create, update, drop, and rename database tables"),(0,r.kt)("li",{parentName:"ul"},"create, drop, and rename table columns"),(0,r.kt)("li",{parentName:"ul"},"extensive schema builder that allows creating of all possible column types"),(0,r.kt)("li",{parentName:"ul"},"terser syntax for creating foreign keys and foreign key constraints"),(0,r.kt)("li",{parentName:"ul"},"supports creating, and dropping column indexes (primary, unique, fulltext, spatial)"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"the ",(0,r.kt)("inlineCode",{parentName:"strong"},"tom")," console application with tab completion for all shells (pwsh, bash, zsh)")," \ud83e\udd73",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"scaffolding of models, migrations, and seeders"),(0,r.kt)("li",{parentName:"ul"},"impressive models scaffolding, every feature that is supported by models can be generated using the ",(0,r.kt)("inlineCode",{parentName:"li"},"tom make:model")," cli command"))),(0,r.kt)("li",{parentName:"ul"},"a huge amount of code is unit tested, currently ",(0,r.kt)("strong",{parentName:"li"},"3366 unit tests")," \ud83e\udd2f"),(0,r.kt)("li",{parentName:"ul"},"C++20 only, with all the latest features used like concepts/constraints, ranges, smart pointers (no ",(0,r.kt)("inlineCode",{parentName:"li"},"new")," keyword in the whole code \ud83d\ude0e), folding expressions"),(0,r.kt)("li",{parentName:"ul"},"qmake and CMake build systems support",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"CMake FetchContent module support \ud83e\udd19"))),(0,r.kt)("li",{parentName:"ul"},"vcpkg support (also the vcpkg port, currently not committed to the vcpkg repository \u2639\ufe0f)"),(0,r.kt)("li",{parentName:"ul"},"it's really fast, you can run 1000 complex queries in 500ms (heavily DB dependant, the PostgreSQL is by far the fastest) \u231a"),(0,r.kt)("li",{parentName:"ul"},"extensive documentation \ud83d\udcc3"),(0,r.kt)("li",{parentName:"ul"},"...")),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"See the ",(0,r.kt)("inlineCode",{parentName:"p"},"TinyDrivers")," ",(0,r.kt)("a",{parentName:"p",href:"tinydrivers/getting-started#features-summary"},"Features summary"),".")),(0,r.kt)("h2",{id:"showcase-images"},"Showcase Images"),(0,r.kt)("h6",{id:"tom-console-application"},"Tom console application"),(0,r.kt)("img",{src:a(9566).Z,alt:"TinyORM - Tom console application - Showcase",title:"Tom console application"}),(0,r.kt)("h6",{id:"passed-all-unit-tests-"},"Passed all unit tests \ud83e\udd73"),(0,r.kt)("img",{src:a(5734).Z,alt:"TinyORM - Passed all unit tests - Showcase",title:"Passed all unit tests",width:"700",className:"no-blurry"}),(0,r.kt)("h4",{id:"tinyormplayground"},"TinyOrmPlayground"),(0,r.kt)("p",null,"The ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyOrmPlayground"},"TinyOrmPlayground")," project is my personal project where I have tested all the TinyORM database queries in the early development phases, currently, it executes ~1600 database queries across the whole TinyORM framework. Every query has a nice title header, is logged to the console, and is counted and measured (elapsed time). Every query also runs on all ",(0,r.kt)("a",{parentName:"p",href:"/database/getting-started#introduction"},"supported databases"),"."),(0,r.kt)("p",null,"The TinyOrmPlayground project can be compiled in a single-threaded or multi-threaded mode. In the multi-threaded mode, every database connection runs in its own thread. At the end of every database connection is logged a connection summary and before an exit is logged the application summary. Whole TinyOrmPlayground application is configurable through the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/silverqx/TinyOrmPlayground/blob/main/src/configuration.hpp"},"src/configuration.hpp")," class."),(0,r.kt)("h6",{id:"tinyormplayground-single-threaded"},"TinyOrmPlayground single-threaded"),(0,r.kt)("img",{src:a(3179).Z,alt:"TinyORM - Invoked TinyOrmPlayground single-threaded - Showcase",title:"Invoked TinyOrmPlayground single-threaded"}),(0,r.kt)("h6",{id:"tinyormplayground-multi-threaded"},"TinyOrmPlayground multi-threaded"),(0,r.kt)("img",{src:a(1177).Z,alt:"TinyORM - Invoked TinyOrmPlayground multi-threaded - Showcase",title:"Invoked TinyOrmPlayground multi-threaded"}))}d.isMDXComponent=!0},5734:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/tinyorm-passed_all_unit_tests-d730d995b6b490fb42c3671738e3b81e.png"},1177:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/tinyormplayground-multi-threaded-edb67030c75e2845e1fa7013e510174c.png"},3179:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/tinyormplayground-single-threaded-4e7a5769ad5a768a4d04c6dc856c4391.png"},9566:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/tom_cli-402f7dd4dfe7dbd0b20dfe5fb61838a2.png"}}]); \ No newline at end of file diff --git a/assets/js/feaee7f3.0f0c7251.js b/assets/js/feaee7f3.0f0c7251.js new file mode 100644 index 000000000..0151e6e9b --- /dev/null +++ b/assets/js/feaee7f3.0f0c7251.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[983],{3750:(e,n,l)=>{l.r(n),l.d(n,{assets:()=>p,contentTitle:()=>h,default:()=>j,frontMatter:()=>c,metadata:()=>u,toc:()=>m});var i=l(4848),r=l(8453),t=l(2364),o=l(9365),a=l(1470),s=l(7324),d=l(6694);const c={sidebar_position:2,sidebar_label:"Hello world",description:"Hello world example created in the terminal and QtCreator IDE.",keywords:["c++ orm","building","hello world","tinyorm"]},h="Building: Hello world",u={id:"building/hello-world",title:"Building: Hello world",description:"Hello world example created in the terminal and QtCreator IDE.",source:"@site/docs/building/hello-world.mdx",sourceDirName:"building",slug:"/building/hello-world",permalink:"/building/hello-world",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Hello world",description:"Hello world example created in the terminal and QtCreator IDE.",keywords:["c++ orm","building","hello world","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"TinyORM",permalink:"/building/tinyorm"},next:{title:"Migrations",permalink:"/building/migrations"}},p={},m=[{value:"Introduction",id:"introduction",level:2},{value:"Prepare SQLite 3 database",id:"prepare-sqlite-3-database",level:2},{value:"Install dependencies",id:"install-dependencies",level:2},{value:"Using vcpkg.json <small>(manifest mode)</small>",id:"using-vcpkg-json-manifest-mode",level:4},{value:"Using vcpkg install <small>(manually)</small>",id:"using-vcpkg-install-manually",level:4},{value:"Source code",id:"source-code",level:2},{value:"Hello world with CMake",id:"hello-world-with-cmake",level:2},{value:"CMake project",id:"cmake-project",level:3},{value:"FetchContent",id:"fetchcontent",level:3},{value:"How FetchContent module works",id:"how-fetchcontent-module-works",level:4},{value:"Build Hello world",id:"build-hello-world-cmake",level:3},{value:"Execute Hello world",id:"execute-hello-world-cmake",level:3},{value:"Hello world with qmake",id:"hello-world-with-qmake",level:2},{value:"qmake project",id:"qmake-project",level:3},{value:"<code>Auto-configure</code> using <code>.qmake.conf</code> and <code>.env</code>",id:"auto-configure-using-qmake_conf-and-env",level:4},{value:"Build Hello world",id:"build-hello-world-qmake",level:3},{value:"Execute Hello world",id:"execute-hello-world-qmake",level:3}];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",ul:"ul",...(0,r.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"building-hello-world",children:"Building: Hello world"}),"\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:"#prepare-sqlite-3-database",children:"Prepare SQLite 3 database"})}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#install-dependencies",children:"Install dependencies"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#using-vcpkg-json-manifest-mode",children:"Using vcpkg.json"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#using-vcpkg-install-manually",children:"Using vcpkg install"})}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#source-code",children:"Source code"})}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#hello-world-with-cmake",children:"Hello world with CMake"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#cmake-project",children:"CMake project"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#fetchcontent",children:"FetchContent"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#build-hello-world-cmake",children:"Build Hello world"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#execute-hello-world-cmake",children:"Execute Hello world"})}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"#hello-world-with-qmake",children:"Hello world with qmake"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#qmake-project",children:"qmake project"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#build-hello-world-qmake",children:"Build Hello world"})}),"\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"#execute-hello-world-qmake",children:"Execute Hello world"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"introduction",children:"Introduction"}),"\n",(0,i.jsxs)(n.p,{children:["We will try to create the simplest working console application, in the terminal with the ",(0,i.jsx)(n.code,{children:"CMake"})," and in the ",(0,i.jsx)(n.code,{children:"QtCreator IDE"})," with the ",(0,i.jsx)(n.code,{children:"qmake"})," build systems."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"HelloWorld"})," example also expects the following ",(0,i.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"}),", let's create them."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-powershell",children:`cd ${(0,d.OZ)(s.b)}\nmkdir HelloWorld/HelloWorld\ncd HelloWorld`})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-bash",children:`cd ${(0,d.OZ)(s.xj)}\nmkdir -p HelloWorld/HelloWorld\ncd HelloWorld`})})]}),"\n",(0,i.jsx)(n.h2,{id:"prepare-sqlite-3-database",children:"Prepare SQLite 3 database"}),"\n",(0,i.jsxs)(n.p,{children:["The easiest way to demonstrate the ",(0,i.jsx)(n.code,{children:"HelloWorld"})," example will be with a ",(0,i.jsx)(n.code,{children:"SQLite 3"})," database."]}),"\n",(0,i.jsxs)(n.p,{children:["Execute the following command in the terminal to create and insert two rows into the ",(0,i.jsx)(n.code,{children:"SQLite 3"})," database."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"sqlite3 HelloWorld.sqlite3 \"\ncreate table posts(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name VARCHAR NOT NULL);\ninsert into posts values(1, 'First Post');\ninsert into posts values(2, 'Second Post');\nselect * from posts;\"\n"})}),"\n",(0,i.jsx)(n.h2,{id:"install-dependencies",children:"Install dependencies"}),"\n",(0,i.jsxs)(n.p,{children:["First, install the ",(0,i.jsx)(n.code,{children:"vcpkg"})," package manager as is described ",(0,i.jsx)(n.a,{href:"/building/tinyorm#vcpkg",children:"here"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"range-v3"})," and ",(0,i.jsx)(n.code,{children:"tabulate"})," libraries are required dependencies because ",(0,i.jsx)(n.code,{children:"TinyORM"})," uses them in header files, you have to install them before you can use ",(0,i.jsx)(n.code,{children:"TinyORM"}),". The ",(0,i.jsx)(n.code,{children:"tabulate"})," library is only needed in the ",(0,i.jsx)(n.code,{children:"tom"})," migrations it's used by the ",(0,i.jsx)(n.code,{children:"migrate:status"})," command."]}),"\n",(0,i.jsxs)(n.p,{children:["There are two ways how to install the ",(0,i.jsx)(n.code,{children:"range-v3"})," and ",(0,i.jsx)(n.code,{children:"tabulate"})," libraries using ",(0,i.jsx)(n.code,{children:"vcpkg"}),"."]}),"\n",(0,i.jsxs)(n.h4,{id:"using-vcpkg-json-manifest-mode",children:["Using vcpkg.json ",(0,i.jsx)("small",{children:"(manifest mode)"})]}),"\n",(0,i.jsxs)(n.p,{children:["Create a ",(0,i.jsx)(n.code,{children:"vcpkg.json"})," file with the following content. ",(0,i.jsx)(n.code,{children:"CMake"})," example below uses this method."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cd HelloWorld\nvim vcpkg.json\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.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": "tinyorm-helloworld",\n "version-semver": "0.1.0",\n "maintainers": "Silver Zachara <silver.zachara@gmail.com>",\n "description": "Hello world console application for TinyORM C++ library",\n "homepage": "https://github.com/silverqx/TinyORM",\n "documentation": "https://www.tinyorm.org/building/hello-world",\n "supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",\n "dependencies": [\n "range-v3",\n "tabulate"\n ]\n}\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Only ",(0,i.jsx)(n.code,{children:"CMake"})," via the ",(0,i.jsx)(n.code,{children:"toolchain file"})," supports this method."]})}),"\n",(0,i.jsxs)(n.h4,{id:"using-vcpkg-install-manually",children:["Using vcpkg install ",(0,i.jsx)("small",{children:"(manually)"})]}),"\n",(0,i.jsxs)(n.p,{children:["This method can be used with both ",(0,i.jsx)(n.code,{children:"CMake"})," and ",(0,i.jsx)(n.code,{children:"qmake"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.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,i.jsx)(n.h2,{id:"source-code",children:"Source code"}),"\n",(0,i.jsxs)(n.p,{children:["Let's start in the ",(0,i.jsx)(n.code,{children:"HelloWorld"})," project folder."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-powershell",children:`cd ${(0,d.OZ)(s.b)}/HelloWorld/HelloWorld`})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-bash",children:`cd ${(0,d.OZ)(s.xj)}/HelloWorld/HelloWorld`})})]}),"\n",(0,i.jsxs)(n.p,{children:["Create ",(0,i.jsx)(n.code,{children:"main.cpp"})," source file."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"vim main.cpp\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["To paste a source code correctly in ",(0,i.jsx)(n.code,{children:"vim"}),", press ",(0,i.jsx)("kbd",{children:"Shift"})," + ",(0,i.jsx)("kbd",{children:"p"}),"."]})}),"\n",(0,i.jsx)(n.p,{children:"And paste the following code."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-cpp",metastring:"title='main.cpp'",children:'#include <QCoreApplication>\n#include <QDebug>\n\n#ifdef _WIN32\n# include <qt_windows.h>\n#endif\n\n#include <orm/db.hpp>\n\nusing Orm::DB;\n\nint main(int argc, char *argv[])\n{\n#ifdef _WIN32\n SetConsoleOutputCP(CP_UTF8);\n// SetConsoleOutputCP(1250);\n#endif\n\n /* Needed from Qt v6.5.3 to avoid:\n qt.core.qobject.connect: QObject::connect(QObject, Unknown): invalid nullptr parameter */\n QCoreApplication app(argc, argv);\n\n // Ownership of a shared_ptr()\n auto manager = DB::create({\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("TINYORM_HELLOWORLD_DB_SQLITE_DATABASE",\n "../../HelloWorld.sqlite3")},\n {"check_database_exists", true},\n });\n\n auto posts = DB::select("select * from posts");\n\n while(posts.next())\n qDebug() << posts.value("id").toULongLong()\n << posts.value("name").toString();\n}\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"QSqlDatabase"})," depends on ",(0,i.jsx)(n.code,{children:"QCoreApplication"})," from ",(0,i.jsx)(n.code,{children:"Qt v6.5.3"})," so you must create the ",(0,i.jsx)(n.code,{children:"QCoreApplication"})," instance before you will call anything from the ",(0,i.jsx)(n.code,{children:"TinyORM"})," library. \ud83e\udee4 The change was made ",(0,i.jsx)(n.a,{href:"https://github.com/qt/qtbase/commit/8d2bdc9cd5482eace12ba7e45304857bd24db0e6#diff-1d355c25c0b0eddec2be48253407780c4dc510d986739aec61e1ec892ccaf86e",children:"here"}),"."]})}),"\n",(0,i.jsx)(n.h2,{id:"hello-world-with-cmake",children:"Hello world with CMake"}),"\n",(0,i.jsxs)(n.p,{children:["Create a folder for the ",(0,i.jsx)(n.code,{children:"CMake"})," build."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-powershell",children:"cd ..\nmkdir HelloWorld-builds-cmake/build-debug\n\ncd HelloWorld"})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-bash",children:"cd ..\nmkdir -p HelloWorld-builds-cmake/build-debug\n\ncd HelloWorld"})})]}),"\n",(0,i.jsx)(n.h3,{id:"cmake-project",children:"CMake project"}),"\n",(0,i.jsxs)(n.p,{children:["Create ",(0,i.jsx)(n.code,{children:"CMakeLists.txt"})," file with the following content."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-cmake",children:`cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\n# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,d.nC)(s.b,(0,d.OZ)(s.b))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt\${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)`})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-cmake",children:`cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\n# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,d.nC)(s.xj,(0,d.OZ)(s.xj))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt\${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)`})})]}),"\n",(0,i.jsx)(n.h3,{id:"fetchcontent",children:"FetchContent"}),"\n",(0,i.jsxs)(n.p,{children:["If you don't have cloned and built the ",(0,i.jsx)(n.code,{children:"TinyORM"})," library, or you want to quickly try TinyORM without wasting time with cloning and building the TinyORM library, then you can use CMake's ",(0,i.jsx)(n.a,{href:"https://cmake.org/cmake/help/latest/module/FetchContent.html",children:(0,i.jsx)(n.code,{children:"FetchContent"})})," module that will do all of this for you."]}),"\n",(0,i.jsxs)(n.p,{children:["Instead of providing a path by the ",(0,i.jsx)(n.code,{children:"CMAKE_PREFIX_PATH"})," (or using the ",(0,i.jsx)(n.code,{children:"User Package Registry"}),") like in the example below:"]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,d.nC)(s.b,(0,d.OZ)(s.b))}/TinyORM/TinyORM-builds-cmake/build-debug")`})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-cmake",children:`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,d.nC)(s.xj,(0,d.OZ)(s.xj))}/TinyORM/TinyORM-builds-cmake/build-debug")`})})]}),"\n",(0,i.jsxs)(n.p,{children:["You can use the ",(0,i.jsx)(n.a,{href:"https://cmake.org/cmake/help/latest/module/FetchContent.html",children:(0,i.jsx)(n.code,{children:"FetchContent"})})," module like in the following example."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-cmake",children:"cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\n# FetchContent method\ninclude(FetchContent)\nFetchContent_Declare(TinyOrm\n GIT_REPOSITORY https://github.com/silverqx/TinyORM.git\n GIT_TAG origin/main\n OVERRIDE_FIND_PACKAGE\n)\n# Here you can configure TinyORM CMake options\nset(MYSQL_PING OFF)\nset(TOM_EXAMPLE ON)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)"})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-cmake",children:"cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\n# FetchContent method\ninclude(FetchContent)\nFetchContent_Declare(TinyOrm\n GIT_REPOSITORY https://github.com/silverqx/TinyORM.git\n GIT_TAG origin/main\n OVERRIDE_FIND_PACKAGE\n)\n# Here you can configure TinyORM CMake options\nset(MYSQL_PING OFF)\nset(TOM_EXAMPLE ON)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)"})})]}),"\n",(0,i.jsx)(n.h4,{id:"how-fetchcontent-module-works",children:"How FetchContent module works"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"FetchContent_Declare"})," command is like calling the git clone inside the build folder and then adding a cloned folder in a similar way as the ",(0,i.jsx)(n.code,{children:"add_subdirectory(<cloned_folder>)"})," command does."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"FetchContent_MakeAvailable(<package>)"})," internally calls the ",(0,i.jsx)(n.code,{children:"find_package(<package>)"})," command or if you pass the ",(0,i.jsx)(n.code,{children:"OVERRIDE_FIND_PACKAGE"})," argument, then you don't have to call the the ",(0,i.jsx)(n.code,{children:"FetchContent_MakeAvailable"}),", but you must call the ",(0,i.jsx)(n.code,{children:"find_package(<package> x.y.z CONFIG REQUIRED)"})," command manually."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["An advantage of the ",(0,i.jsx)(n.code,{children:"OVERRIDE_FIND_PACKAGE"})," argument is that you can call the ",(0,i.jsx)(n.code,{children:"find_package"})," command much later, and you can insert additional configurations between."]})}),"\n",(0,i.jsx)(n.h3,{id:"build-hello-world-cmake",children:"Build Hello world"}),"\n",(0,i.jsxs)(n.p,{children:["Now you are ready to configure ",(0,i.jsx)(n.code,{children:"HelloWorld"})," ",(0,i.jsx)(n.code,{children:"CMake"})," application."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cd ../HelloWorld-builds-cmake/build-debug\n"})}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-powershell",children:`cmake.exe \`\n-S "${(0,d.OZ)(s.b)}/HelloWorld/HelloWorld" \`\n-B "${(0,d.OZ)(s.b)}/HelloWorld/HelloWorld-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,d.Sn)(s.b)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,d.Sn)(s.b)}/tmp/HelloWorld"`})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-bash",children:`cmake \\\n-S "${(0,d.OZ)(s.xj)}/HelloWorld/HelloWorld" \\\n-B "${(0,d.OZ)(s.xj)}/HelloWorld/HelloWorld-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,d.Sn)(s.xj)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_CXX_SCAN_FOR_MODULES:BOOL=OFF \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,d.Sn)(s.xj)}/tmp/TinyORM"`})})]}),"\n",(0,i.jsx)(n.p,{children:"And build."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cmake --build . --target all\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Enable the ",(0,i.jsx)(n.a,{href:"/building/tinyorm#cmake-strict_mode-option",children:(0,i.jsx)(n.code,{children:"TINYORM_STRICT_MODE"})})," environment variable to produce better code and to follow good code practices."]})}),"\n",(0,i.jsx)(n.h3,{id:"execute-hello-world-cmake",children:"Execute Hello world"}),"\n",(0,i.jsxs)(n.p,{children:["Do not forget to add ",(0,i.jsx)(n.code,{children:"TinyOrm0d.dll"})," on the path on Windows and on the ",(0,i.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux, so ",(0,i.jsx)(n.code,{children:"HelloWorld"})," application can find it during execution, as is described ",(0,i.jsx)(n.a,{href:"/building/tinyorm#tinyorm-on-path-cmake",children:"here"}),"."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,name:"tinyorm-on-path",children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-powershell",children:`$env:Path = "${(0,d.OZ)(s.b,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-bash",children:`export LD_LIBRARY_PATH=${(0,d.OZ)(s.xj)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`})})]}),"\n",(0,i.jsxs)(n.p,{children:["Execute ",(0,i.jsx)(n.code,{children:"HelloWorld"})," example."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:".\\HelloWorld.exe\n"})})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"./HelloWorld\n"})})})]}),"\n",(0,i.jsx)(n.p,{children:"The output will look like this."}),"\n",(0,i.jsx)(t.A,{className:"language-less",children:'Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts\n1 "First Post"\n2 "Second Post"'}),"\n",(0,i.jsx)(n.h2,{id:"hello-world-with-qmake",children:"Hello world with qmake"}),"\n",(0,i.jsxs)(n.p,{children:["Create a folder for the ",(0,i.jsx)(n.code,{children:"qmake"})," build."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:s.ux,children:(0,i.jsx)(t.A,{className:"language-powershell",children:`cd ${(0,d.OZ)(s.b)}/HelloWorld\n\nmkdir HelloWorld-builds-qmake`})}),(0,i.jsx)(o.A,{value:s.xj,label:s.gg,children:(0,i.jsx)(t.A,{className:"language-bash",children:`cd ${(0,d.OZ)(s.xj)}/HelloWorld\n\nmkdir HelloWorld-builds-qmake`})})]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.a,{href:"#source-code",children:(0,i.jsx)(n.code,{children:"source code"})})," is the same as for the ",(0,i.jsx)(n.code,{children:"HelloWorld CMake"})," example."]}),"\n",(0,i.jsx)(n.h3,{id:"qmake-project",children:"qmake project"}),"\n",(0,i.jsxs)(n.p,{children:["Create ",(0,i.jsx)(n.code,{children:"HelloWorld.pro"})," qmake file with the following content."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"cd HelloWorld\nvim HelloWorld.pro\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["To paste a source code correctly in ",(0,i.jsx)(n.code,{children:"vim"}),", press ",(0,i.jsx)("kbd",{children:"Shift"})," + ",(0,i.jsx)("kbd",{children:"p"}),"."]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-qmake",metastring:"title='HelloWorld.pro'",children:"QT -= gui\n\nTEMPLATE = app\n\nCONFIG *= cmdline\n\nDEFINES *= PROJECT_TINYORM_HELLOWORLD\n\nSOURCES += $$PWD/main.cpp\n\n# Auto-configure TinyORM library \ud83d\udd25\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["The exact ",(0,i.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"})," is crucial in this example because the paths to the ",(0,i.jsx)(n.code,{children:"TinyORM"})," source and build folders are relative."]})}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsx)(n.p,{children:"Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!"})}),"\n",(0,i.jsxs)(n.h4,{id:"auto-configure-using-qmake_conf-and-env",children:[(0,i.jsx)(n.code,{children:"Auto-configure"})," using ",(0,i.jsx)(n.code,{children:".qmake.conf"})," and ",(0,i.jsx)(n.code,{children:".env"})]}),"\n",(0,i.jsxs)(n.p,{children:["If you want to have properly configured ",(0,i.jsx)(n.code,{children:"DEFINES"})," (C preprocessor macros) or have Qt headers marked as system headers, then you need to specify a path to the ",(0,i.jsx)(n.code,{children:"TinyORM"})," qmake features (",(0,i.jsx)(n.code,{children:".prf"})," files) which handle this correctly; this path is provided by the ",(0,i.jsx)(n.code,{children:"QMAKEFEATURES"})," variable and can only be set in the ",(0,i.jsx)(n.code,{children:".qmake.conf"})," file."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Read the ",(0,i.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,i.jsxs)(n.p,{children:["Create the ",(0,i.jsx)(n.code,{children:".qmake.conf"})," file in the ",(0,i.jsx)(n.code,{children:"HelloWorld"})," project root folder with the following content."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.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,i.jsxs)(n.p,{children:["Then, create a ",(0,i.jsx)("code",{children:".env.(win32|unix|mingw)"})," file in the ",(0,i.jsx)(n.code,{children:"HelloWorld"})," project root folder with the following content."]}),"\n",(0,i.jsxs)(a.A,{groupId:s.vf,children:[(0,i.jsx)(o.A,{value:s.b,label:".env.win32",children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in HelloWorld.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_0_MSVC2022_64bit-Debug/)\n\n# Path to the vcpkg - range-v3\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 *= tiny_ccache_win32\n"})})}),(0,i.jsx)(o.A,{value:s.xj,label:".env.unix",children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in HelloWorld.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_0_clang16_64bit_ccache-Debug/)\n\n# Path to the vcpkg - range-v3\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,i.jsx)(o.A,{value:"mingw",label:".env.mingw",children:(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-qmake",children:"# Names and values of these qmake variables are crucial, they are used in HelloWorld.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_0_MSYS2_UCRT64_clang_64bit-Debug/)\n\n# Path to the vcpkg - range-v3\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 *= tiny_ccache_win32\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,i.jsxs)(n.p,{children:["Don't forget to update the ",(0,i.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," and ",(0,i.jsx)(n.code,{children:"TINY_VCPKG_ROOT"})," folder paths to your needs if you are not using the recommended ",(0,i.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:(0,i.jsx)(n.code,{children:"Folders structure"})}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["You can use the ",(0,i.jsxs)(n.a,{href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,i.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," if you don't like to specify it manually. Just comment out the ",(0,i.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," and uncomment the ",(0,i.jsx)(n.code,{children:"TINY_BUILD_TREE = $$shadowed($$PWD)"})," in the ",(0,i.jsx)(n.code,{children:".qmake.conf"})," file."]}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["You can entirely avoid the ",(0,i.jsx)(n.code,{children:".env"})," files, just move the ",(0,i.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})," to the ",(0,i.jsx)(n.code,{children:".qmake.conf"})," or remove it by help of ",(0,i.jsxs)(n.a,{href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree",children:["Partial guessing of the ",(0,i.jsx)(n.code,{children:"TINYORM_BUILD_TREE"})]})," and set the ",(0,i.jsx)(n.code,{children:"VCPKG_ROOT"})," environment variable at system level as is described in ",(0,i.jsx)(n.a,{href:"/building/tinyorm#set-up-vcpkg-environment",children:(0,i.jsx)(n.code,{children:"Set up vcpkg environment"})}),"."]})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["Configuring by the ",(0,i.jsx)(n.code,{children:".qmake.conf"})," and ",(0,i.jsx)(n.code,{children:".env"})," files has one big advantage, which is that you don't have to modify the project files."]})}),"\n",(0,i.jsx)(n.h3,{id:"build-hello-world-qmake",children:"Build Hello world"}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["I recommend creating a new ",(0,i.jsx)(n.code,{children:"Session"})," in the ",(0,i.jsx)(n.code,{children:"QtCreator IDE"})," as is described ",(0,i.jsx)(n.a,{href:"/building/tinyorm#open-qtcreator-ide",children:"here"}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["Now you can open the ",(0,i.jsx)(n.code,{children:"HelloWorld.pro"})," project in the ",(0,i.jsx)(n.code,{children:"QtCreator IDE"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This will open the ",(0,i.jsx)(n.code,{children:"Configure Project"})," tab, select some kit and update build folder paths to meet our ",(0,i.jsx)(n.a,{href:"/building/tinyorm#folders-structure",children:"folders structure"})," or like you want."]}),"\n",(0,i.jsx)("img",{src:l(3180).A,alt:"HelloWorld - QtCreator - Configure Project",width:"760"}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["You can force the ",(0,i.jsx)(n.code,{children:"QtCreator"})," to generate a build folders structure as is described ",(0,i.jsx)(n.a,{href:"/building/tinyorm#qtcreator-default-build-directory",children:"here"}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["You are ready to configure build options, hit ",(0,i.jsx)("kbd",{children:"Ctrl"}),"+",(0,i.jsx)("kbd",{children:"5"})," to open ",(0,i.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,i.jsx)(n.code,{children:"Build"})," in the left sidebar to open the ",(0,i.jsx)(n.code,{children:"Build Settings"}),", it should look similar to the following picture."]}),"\n",(0,i.jsx)("img",{src:l(7028).A,className:"no-blurry",alt:"HelloWorld - QtCreator - Build Settings",width:"760"}),"\n",(0,i.jsxs)(n.p,{children:["Disable ",(0,i.jsx)(n.code,{children:"QML debugging and profiling"})," and ",(0,i.jsx)(n.code,{children:"Qt Quick Compiler"}),", they are not used."]}),"\n",(0,i.jsxs)(n.p,{children:["In the left sidebar open ",(0,i.jsx)(n.code,{children:"Dependencies"})," and check ",(0,i.jsx)(n.code,{children:"TinyORM"})," project and ",(0,i.jsx)(n.code,{children:"Synchronize configuration"}),", this setting ensures that the current project will be rebuilt correctly when the ",(0,i.jsx)(n.code,{children:"TinyORM"})," library source code changes."]}),"\n",(0,i.jsxs)(n.p,{children:["Everything is ready to build, you can press ",(0,i.jsx)("kbd",{children:"Ctrl"}),"+",(0,i.jsx)("kbd",{children:"b"})," to build the project."]}),"\n",(0,i.jsx)(n.h3,{id:"execute-hello-world-qmake",children:"Execute Hello world"}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.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,i.jsx)(n.code,{children:"LD_LIBRARY_PATH"})," on Linux."]}),"\n",(0,i.jsxs)(n.p,{children:["The only thing you might want to change is to run the ",(0,i.jsx)(n.code,{children:"HelloWorld"})," example in the new terminal window. To do so, hit ",(0,i.jsx)("kbd",{children:"Ctrl"}),"+",(0,i.jsx)("kbd",{children:"5"})," to open the ",(0,i.jsx)(n.code,{children:"Project Settings"})," tab and select ",(0,i.jsx)(n.code,{children:"Run"})," in the left sidebar to open the ",(0,i.jsx)(n.code,{children:"Run Settings"}),", then in the ",(0,i.jsx)(n.code,{children:"Run"})," section select the ",(0,i.jsx)(n.code,{children:"Run in terminal"})," checkbox."]}),"\n",(0,i.jsxs)(n.p,{children:["To execute the ",(0,i.jsx)(n.code,{children:"HelloWorld"})," example press ",(0,i.jsx)("kbd",{children:"Ctrl"})," + ",(0,i.jsx)("kbd",{children:"r"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"The output will look like this."}),"\n",(0,i.jsx)(t.A,{className:"language-less",children:'Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts\n1 "First Post"\n2 "Second Post"'})]})}function j(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(x,{...e})}):x(e)}},9365:(e,n,l)=>{l.d(n,{A:()=>o});l(6540);var i=l(4164);const r={tabItem:"tabItem_Ymn6"};var t=l(4848);function o(e){let{children:n,hidden:l,className:o}=e;return(0,t.jsx)("div",{role:"tabpanel",className:(0,i.A)(r.tabItem,o),hidden:l,children:n})}},1470:(e,n,l)=>{l.d(n,{A:()=>y});var i=l(6540),r=l(4164),t=l(3104),o=l(6347),a=l(205),s=l(7485),d=l(1682),c=l(9466);function h(e){return i.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,i.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 <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function u(e){const{values:n,children:l}=e;return(0,i.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:l,attributes:i,default:r}}=e;return{value:n,label:l,attributes:i,default:r}}))}(l);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 <Tabs>. Every value needs to be unique.`)}(e),e}),[n,l])}function p(e){let{value:n,tabValues:l}=e;return l.some((e=>e.value===n))}function m(e){let{queryString:n=!1,groupId:l}=e;const r=(0,o.W6)(),t=function(e){let{queryString:n=!1,groupId:l}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!l)throw new Error('Docusaurus error: The <Tabs> 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 l??null}({queryString:n,groupId:l});return[(0,s.aZ)(t),(0,i.useCallback)((e=>{if(!t)return;const n=new URLSearchParams(r.location.search);n.set(t,e),r.replace({...r.location,search:n.toString()})}),[t,r])]}function x(e){const{defaultValue:n,queryString:l=!1,groupId:r}=e,t=u(e),[o,s]=(0,i.useState)((()=>function(e){let{defaultValue:n,tabValues:l}=e;if(0===l.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(n){if(!p({value:n,tabValues:l}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${l.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const i=l.find((e=>e.default))??l[0];if(!i)throw new Error("Unexpected error: 0 tabValues");return i.value}({defaultValue:n,tabValues:t}))),[d,h]=m({queryString:l,groupId:r}),[x,j]=function(e){let{groupId:n}=e;const l=function(e){return e?`docusaurus.tab.${e}`:null}(n),[r,t]=(0,c.Dv)(l);return[r,(0,i.useCallback)((e=>{l&&t.set(e)}),[l,t])]}({groupId:r}),g=(()=>{const e=d??x;return p({value:e,tabValues:t})?e:null})();(0,a.A)((()=>{g&&s(g)}),[g]);return{selectedValue:o,selectValue:(0,i.useCallback)((e=>{if(!p({value:e,tabValues:t}))throw new Error(`Can't select invalid tab value=${e}`);s(e),h(e),j(e)}),[h,j,t]),tabValues:t}}var j=l(2303);const g={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var b=l(4848);function f(e){let{className:n,block:l,selectedValue:i,selectValue:o,tabValues:a}=e;const s=[],{blockElementScrollPositionUntilNextRender:d}=(0,t.a_)(),c=e=>{const n=e.currentTarget,l=s.indexOf(n),r=a[l].value;r!==i&&(d(n),o(r))},h=e=>{let n=null;switch(e.key){case"Enter":c(e);break;case"ArrowRight":{const l=s.indexOf(e.currentTarget)+1;n=s[l]??s[0];break}case"ArrowLeft":{const l=s.indexOf(e.currentTarget)-1;n=s[l]??s[s.length-1];break}}n?.focus()};return(0,b.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs",{"tabs--block":l},n),children:a.map((e=>{let{value:n,label:l,attributes:t}=e;return(0,b.jsx)("li",{role:"tab",tabIndex:i===n?0:-1,"aria-selected":i===n,ref:e=>s.push(e),onKeyDown:h,onClick:c,...t,className:(0,r.A)("tabs__item",g.tabItem,t?.className,{"tabs__item--active":i===n}),children:l??n},n)}))})}function _(e){let{lazy:n,children:l,selectedValue:r}=e;const t=(Array.isArray(l)?l:[l]).filter(Boolean);if(n){const e=t.find((e=>e.props.value===r));return e?(0,i.cloneElement)(e,{className:"margin-top--md"}):null}return(0,b.jsx)("div",{className:"margin-top--md",children:t.map(((e,n)=>(0,i.cloneElement)(e,{key:n,hidden:e.props.value!==r})))})}function T(e){const n=x(e);return(0,b.jsxs)("div",{className:(0,r.A)("tabs-container",g.tabList),children:[(0,b.jsx)(f,{...n,...e}),(0,b.jsx)(_,{...n,...e})]})}function y(e){const n=(0,j.A)();return(0,b.jsx)(T,{...e,children:h(e.children)},String(n))}},7324:(e,n,l)=>{l.d(n,{$E:()=>j,A3:()=>b,CW:()=>g,Dx:()=>c,F4:()=>u,Fi:()=>d,J_:()=>y,LQ:()=>f,Lf:()=>k,OO:()=>r,Q7:()=>_,b:()=>a,cy:()=>s,gg:()=>m,kl:()=>p,os:()=>h,pW:()=>t,ux:()=>x,vf:()=>i,xj:()=>o,xt:()=>T});const i="shell",r="database",t="application",o="bash",a="pwsh",s="zsh",d="maria",c="mysql",h="postgres",u="sqlite",p="application",m="bash",x="pwsh",j="zsh",g="MariaDB",b="MySQL",f="PostgreSQL",_="SQLite",T="tinyorm.org",y="$HOME/Code/c/",k="$env:USERPROFILE\\Code\\c\\"},6362:(e,n,l)=>{l.d(n,{A:()=>t});var i=l(6540),r=l(1838);function t(){const e=(0,i.useContext)(r.A);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6694:(e,n,l)=>{l.d(n,{OZ:()=>s,Sn:()=>o,T3:()=>c,bw:()=>d,nC:()=>h,np:()=>a});var i=l(6362),r=l(2303),t=l(7324);const o=function(e,n){return void 0===n&&(n=!0),u((0,i.A)().rootFolder[e]??d(e),e,n)},a=()=>(0,i.A)().rootFolder[t.pW]??d(t.pW),s=function(e,n){if(void 0===n&&(n=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const l=n||e!==t.b?"/":"\\";return u(o(e)+l+a(),e,n)};function d(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,r.A)())return"";switch(e){case t.b:return t.Lf;case t.xj:return t.J_;case t.pW:return t.xt;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function c(e){return e===t.pW}function h(e,n){if(null==n||""===n)return n;const l="$ENV{$1}$2";switch(e){case t.b:return m(n).replace(/\$env:(.+?)(\/.*)/,l);case t.xj:return n.replace(/\$(.+?)(\/.*)/,l);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function u(e,n,l){if(void 0===l&&(l=!0),null==e||""===e)return e;if(n!==t.b)return p(e);const i=p(e);return l?m(i):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(i)}function p(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function m(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},7028:(e,n,l)=>{l.d(n,{A:()=>i});const i=l.p+"assets/images/qmake-build_settings-ebdc6c0c056d11462096ff10cba682a1.png"},3180:(e,n,l)=>{l.d(n,{A:()=>i});const i=l.p+"assets/images/qmake-configure_project-8caf87e6af4452f0c28bd15c85c392fc.png"}}]); \ No newline at end of file diff --git a/assets/js/feaee7f3.1f08f71e.js b/assets/js/feaee7f3.1f08f71e.js deleted file mode 100644 index e0f3dcd5d..000000000 --- a/assets/js/feaee7f3.1f08f71e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[168],{5162:(e,t,n)=>{n.d(t,{Z:()=>i});var a=n(7294),l=n(6010);const o={tabItem:"tabItem_Ymn6"};function i(e){let{children:t,hidden:n,className:i}=e;return a.createElement("div",{role:"tabpanel",className:(0,l.Z)(o.tabItem,i),hidden:n},t)}},4866:(e,t,n)=>{n.d(t,{Z:()=>f});var a=n(7462),l=n(7294),o=n(6010),i=n(2466),r=n(6550),d=n(1980),p=n(7392),s=n(12);function u(e){return function(e){return l.Children.map(e,(e=>{if(!e||(0,l.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(e).map((e=>{let{props:{value:t,label:n,attributes:a,default:l}}=e;return{value:t,label:n,attributes:a,default:l}}))}function c(e){const{values:t,children:n}=e;return(0,l.useMemo)((()=>{const e=t??u(n);return function(e){const t=(0,p.l)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e}),[t,n])}function m(e){let{value:t,tabValues:n}=e;return n.some((e=>e.value===t))}function k(e){let{queryString:t=!1,groupId:n}=e;const a=(0,r.k6)(),o=function(e){let{queryString:t=!1,groupId:n}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!n)throw new Error('Docusaurus error: The <Tabs> 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 n??null}({queryString:t,groupId:n});return[(0,d._X)(o),(0,l.useCallback)((e=>{if(!o)return;const t=new URLSearchParams(a.location.search);t.set(o,e),a.replace({...a.location,search:t.toString()})}),[o,a])]}function h(e){const{defaultValue:t,queryString:n=!1,groupId:a}=e,o=c(e),[i,r]=(0,l.useState)((()=>function(e){let{defaultValue:t,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(t){if(!m({value:t,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const a=n.find((e=>e.default))??n[0];if(!a)throw new Error("Unexpected error: 0 tabValues");return a.value}({defaultValue:t,tabValues:o}))),[d,p]=k({queryString:n,groupId:a}),[u,h]=function(e){let{groupId:t}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(t),[a,o]=(0,s.Nk)(n);return[a,(0,l.useCallback)((e=>{n&&o.set(e)}),[n,o])]}({groupId:a}),g=(()=>{const e=d??u;return m({value:e,tabValues:o})?e:null})();(0,l.useLayoutEffect)((()=>{g&&r(g)}),[g]);return{selectedValue:i,selectValue:(0,l.useCallback)((e=>{if(!m({value:e,tabValues:o}))throw new Error(`Can't select invalid tab value=${e}`);r(e),p(e),h(e)}),[p,h,o]),tabValues:o}}var g=n(2389);const b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function N(e){let{className:t,block:n,selectedValue:r,selectValue:d,tabValues:p}=e;const s=[],{blockElementScrollPositionUntilNextRender:u}=(0,i.o5)(),c=e=>{const t=e.currentTarget,n=s.indexOf(t),a=p[n].value;a!==r&&(u(t),d(a))},m=e=>{let t=null;switch(e.key){case"Enter":c(e);break;case"ArrowRight":{const n=s.indexOf(e.currentTarget)+1;t=s[n]??s[0];break}case"ArrowLeft":{const n=s.indexOf(e.currentTarget)-1;t=s[n]??s[s.length-1];break}}t?.focus()};return l.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":n},t)},p.map((e=>{let{value:t,label:n,attributes:i}=e;return l.createElement("li",(0,a.Z)({role:"tab",tabIndex:r===t?0:-1,"aria-selected":r===t,key:t,ref:e=>s.push(e),onKeyDown:m,onClick:c},i,{className:(0,o.Z)("tabs__item",b.tabItem,i?.className,{"tabs__item--active":r===t})}),n??t)})))}function T(e){let{lazy:t,children:n,selectedValue:a}=e;const o=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){const e=o.find((e=>e.props.value===a));return e?(0,l.cloneElement)(e,{className:"margin-top--md"}):null}return l.createElement("div",{className:"margin-top--md"},o.map(((e,t)=>(0,l.cloneElement)(e,{key:t,hidden:e.props.value!==a}))))}function C(e){const t=h(e);return l.createElement("div",{className:(0,o.Z)("tabs-container",b.tabList)},l.createElement(N,(0,a.Z)({},e,t)),l.createElement(T,(0,a.Z)({},e,t)))}function f(e){const t=(0,g.Z)();return l.createElement(C,(0,a.Z)({key:String(t)},e))}},2044:(e,t,n)=>{n.d(t,{$t:()=>u,Ae:()=>g,C:()=>k,DK:()=>b,Fo:()=>r,Fs:()=>l,IM:()=>h,IZ:()=>a,RS:()=>_,VE:()=>N,Wg:()=>C,_A:()=>p,al:()=>y,jk:()=>m,js:()=>d,of:()=>s,q5:()=>i,qb:()=>f,vk:()=>c,wU:()=>o,zg:()=>T});const a="shell",l="database",o="application",i="bash",r="pwsh",d="zsh",p="maria",s="mysql",u="postgres",c="sqlite",m="application",k="bash",h="pwsh",g="zsh",b="MariaDB",N="MySQL",T="PostgreSQL",C="SQLite",f="tinyorm.org",y="$HOME/Code/c/",_="$env:USERPROFILE\\Code\\c\\"},4355:(e,t,n)=>{n.d(t,{Z:()=>o});var a=n(7294),l=n(9482);function o(){const e=(0,a.useContext)(l.Z);if(null!=e)return e;throw new Error("useRootFolderContext is used outside of Layout component.")}},6005:(e,t,n)=>{n.d(t,{AE:()=>r,EA:()=>i,em:()=>p,go:()=>d,mT:()=>s,we:()=>u});var a=n(4355),l=n(2389),o=n(2044);const i=function(e,t){return void 0===t&&(t=!0),c((0,a.Z)().rootFolder[e]??p(e),e,t)},r=()=>(0,a.Z)().rootFolder[o.wU]??p(o.wU),d=function(e,t){if(void 0===t&&(t=!0),null==e)throw new Error("The groupId in the applicationFolderPath() can not be empty.");const n=t||e!==o.Fo?"/":"\\";return c(i(e)+n+r(),e,t)};function p(e){if(null==e)throw new Error("The groupId in the folderDefaultValue() can not be empty.");if(!(0,l.Z)())return"";switch(e){case o.Fo:return o.RS;case o.q5:return o.al;case o.wU:return o.qb;default:throw new Error(`No default value for '${e}' groupId in the folderDefaultValue().`)}}function s(e){return e===o.wU}function u(e,t){if(null==t||""===t)return t;const n="$ENV{$1}$2";switch(e){case o.Fo:return k(t).replace(/\$env:(.+?)(\/.*)/,n);case o.q5:return t.replace(/\$(.+?)(\/.*)/,n);default:throw new Error(`Unsupported shell type '${e}' in the convertToCmakeEnvVariable().`)}}function c(e,t,n){if(void 0===n&&(n=!0),null==e||""===e)return e;if(t!==o.Fo)return m(e);const a=m(e);return n?k(a):function(e){return null==e||""===e?e:e.replaceAll(/\/+/g,"\\")}(a)}function m(e){return null==e||""===e?e:e.replace(/[/\\]+$/,"")}function k(e){return null==e||""===e?e:e.replaceAll(/\\+(?! )/g,"/")}},4588:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>m,contentTitle:()=>u,default:()=>b,frontMatter:()=>s,metadata:()=>c,toc:()=>k});var a=n(7462),l=(n(7294),n(3905)),o=n(7693),i=n(5162),r=n(4866),d=n(2044),p=n(6005);const s={sidebar_position:2,sidebar_label:"Hello world",description:"Hello world example created in the terminal and QtCreator IDE.",keywords:["c++ orm","building","hello world","tinyorm"]},u="Building: Hello world",c={unversionedId:"building/hello-world",id:"building/hello-world",title:"Building: Hello world",description:"Hello world example created in the terminal and QtCreator IDE.",source:"@site/docs/building/hello-world.mdx",sourceDirName:"building",slug:"/building/hello-world",permalink:"/building/hello-world",draft:!1,editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/docs/building/hello-world.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{sidebar_position:2,sidebar_label:"Hello world",description:"Hello world example created in the terminal and QtCreator IDE.",keywords:["c++ orm","building","hello world","tinyorm"]},sidebar:"tinyormSidebar",previous:{title:"TinyORM",permalink:"/building/tinyorm"},next:{title:"Migrations",permalink:"/building/migrations"}},m={},k=[{value:"Introduction",id:"introduction",level:2},{value:"Prepare SQLite 3 database",id:"prepare-sqlite-3-database",level:2},{value:"Install dependencies",id:"install-dependencies",level:2},{value:"Using vcpkg.json <small>(manifest mode)</small>",id:"using-vcpkg-json-manifest-mode",level:4},{value:"Using vcpkg install <small>(manually)</small>",id:"using-vcpkg-install-manually",level:4},{value:"Source code",id:"source-code",level:2},{value:"Hello world with CMake",id:"hello-world-with-cmake",level:2},{value:"CMake project",id:"cmake-project",level:3},{value:"FetchContent",id:"fetchcontent",level:3},{value:"How FetchContent module works",id:"how-fetchcontent-module-works",level:4},{value:"Build Hello world",id:"build-hello-world-cmake",level:3},{value:"Execute Hello world",id:"execute-hello-world-cmake",level:3},{value:"Hello world with qmake",id:"hello-world-with-qmake",level:2},{value:"qmake project",id:"qmake-project",level:3},{value:"<code>Auto-configure</code> using <code>.qmake.conf</code> and <code>.env</code>",id:"auto-configure-using-qmake_conf-and-env",level:4},{value:"Build Hello world",id:"build-hello-world-qmake",level:3},{value:"Execute Hello world",id:"execute-hello-world-qmake",level:3}],h={toc:k},g="wrapper";function b(e){let{components:t,...s}=e;return(0,l.kt)(g,(0,a.Z)({},h,s,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"building-hello-world"},"Building: Hello world"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#introduction"},"Introduction")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#prepare-sqlite-3-database"},"Prepare SQLite 3 database")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#install-dependencies"},"Install dependencies"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#using-vcpkg-json-manifest-mode"},"Using vcpkg.json")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#using-vcpkg-install-manually"},"Using vcpkg install")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#source-code"},"Source code")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#hello-world-with-cmake"},"Hello world with CMake"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#cmake-project"},"CMake project")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#fetchcontent"},"FetchContent")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#build-hello-world-cmake"},"Build Hello world")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#execute-hello-world-cmake"},"Execute Hello world")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#hello-world-with-qmake"},"Hello world with qmake"),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#qmake-project"},"qmake project")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#build-hello-world-qmake"},"Build Hello world")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#execute-hello-world-qmake"},"Execute Hello world"))))),(0,l.kt)("h2",{id:"introduction"},"Introduction"),(0,l.kt)("p",null,"We will try to create the simplest working console application, in the terminal with the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," and in the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator IDE")," with the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build systems."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," example also expects the following ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},"folders structure"),", let's create them."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,p.go)(d.Fo)}\nmkdir HelloWorld/HelloWorld\ncd HelloWorld`)),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,p.go)(d.q5)}\nmkdir -p HelloWorld/HelloWorld\ncd HelloWorld`))),(0,l.kt)("h2",{id:"prepare-sqlite-3-database"},"Prepare SQLite 3 database"),(0,l.kt)("p",null,"The easiest way to demonstrate the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," example will be with a ",(0,l.kt)("inlineCode",{parentName:"p"},"SQLite 3")," database."),(0,l.kt)("p",null,"Execute the following command in the terminal to create and insert two rows into the ",(0,l.kt)("inlineCode",{parentName:"p"},"SQLite 3")," database."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sqlite3 HelloWorld.sqlite3 \"\ncreate table posts(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name VARCHAR NOT NULL);\ninsert into posts values(1, 'First Post');\ninsert into posts values(2, 'Second Post');\nselect * from posts;\"\n")),(0,l.kt)("h2",{id:"install-dependencies"},"Install dependencies"),(0,l.kt)("p",null,"First, install the ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg")," package manager as is described ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#vcpkg"},"here"),"."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"range-v3")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"tabulate")," libraries are required dependencies because ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," uses them in header files, you have to install them before you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM"),". The ",(0,l.kt)("inlineCode",{parentName:"p"},"tabulate")," library is only needed in the ",(0,l.kt)("inlineCode",{parentName:"p"},"tom")," migrations it's used by the ",(0,l.kt)("inlineCode",{parentName:"p"},"migrate:status")," command."),(0,l.kt)("p",null,"There are two ways how to install the ",(0,l.kt)("inlineCode",{parentName:"p"},"range-v3")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"tabulate")," libraries using ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg"),"."),(0,l.kt)("h4",{id:"using-vcpkg-json-manifest-mode"},"Using vcpkg.json ",(0,l.kt)("small",null,"(manifest mode)")),(0,l.kt)("p",null,"Create a ",(0,l.kt)("inlineCode",{parentName:"p"},"vcpkg.json")," file with the following content. ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," example below uses this method."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cd HelloWorld\nvim vcpkg.json\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-json",metastring:"title='vcpkg.json'",title:"'vcpkg.json'"},'{\n "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",\n "name": "tinyorm-helloworld",\n "version-semver": "0.1.0",\n "description": "Hello world console application for TinyORM C++ library",\n "homepage": "https://github.com/silverqx/TinyORM",\n "documentation": "https://www.tinyorm.org/building/hello-world",\n "maintainers": "Silver Zachara <silver.zachara@gmail.com>",\n "supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",\n "dependencies": [\n "range-v3",\n "tabulate"\n ]\n}\n')),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"Only ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," via the ",(0,l.kt)("inlineCode",{parentName:"p"},"toolchain file")," supports this method.")),(0,l.kt)("h4",{id:"using-vcpkg-install-manually"},"Using vcpkg install ",(0,l.kt)("small",null,"(manually)")),(0,l.kt)("p",null,"This method can be used with both ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cd ../../vcpkg\n\nvcpkg search range-v3\nvcpkg search tabulate\nvcpkg install range-v3 tabulate\nvcpkg list\n")),(0,l.kt)("h2",{id:"source-code"},"Source code"),(0,l.kt)("p",null,"Let's start in the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," project folder."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,p.go)(d.Fo)}/HelloWorld/HelloWorld`)),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,p.go)(d.q5)}/HelloWorld/HelloWorld`))),(0,l.kt)("p",null,"Create ",(0,l.kt)("inlineCode",{parentName:"p"},"main.cpp")," source file."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"vim main.cpp\n")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"To paste a source code correctly in ",(0,l.kt)("inlineCode",{parentName:"p"},"vim"),", press ",(0,l.kt)("kbd",null,"Shift")," + ",(0,l.kt)("kbd",null,"p"),".")),(0,l.kt)("p",null,"And paste the following code."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-cpp",metastring:"title='main.cpp'",title:"'main.cpp'"},'#include <QCoreApplication>\n#include <QDebug>\n\n#ifdef _WIN32\n# include <qt_windows.h>\n#endif\n\n#include <orm/db.hpp>\n\nusing Orm::DB;\n\nint main(int argc, char *argv[])\n{\n#ifdef _WIN32\n SetConsoleOutputCP(CP_UTF8);\n// SetConsoleOutputCP(1250);\n#endif\n\n /* Needed from Qt v6.5.3 to avoid:\n qt.core.qobject.connect: QObject::connect(QObject, Unknown): invalid nullptr parameter */\n QCoreApplication app(argc, argv);\n\n // Ownership of a shared_ptr()\n auto manager = DB::create({\n {"driver", "QSQLITE"},\n {"database", qEnvironmentVariable("TINYORM_HELLOWORLD_DB_SQLITE_DATABASE",\n "../../HelloWorld.sqlite3")},\n {"check_database_exists", true},\n });\n\n auto posts = DB::select("select * from posts");\n\n while(posts.next())\n qDebug() << posts.value("id").toULongLong()\n << posts.value("name").toString();\n}\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("inlineCode",{parentName:"p"},"QSqlDatabase")," depends on ",(0,l.kt)("inlineCode",{parentName:"p"},"QCoreApplication")," from ",(0,l.kt)("inlineCode",{parentName:"p"},"Qt v6.5.3")," so you must create the ",(0,l.kt)("inlineCode",{parentName:"p"},"QCoreApplication")," instance before you will call anything from the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library. \ud83e\udee4 The change was made ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/qt/qtbase/commit/8d2bdc9cd5482eace12ba7e45304857bd24db0e6#diff-1d355c25c0b0eddec2be48253407780c4dc510d986739aec61e1ec892ccaf86e"},"here"),".")),(0,l.kt)("h2",{id:"hello-world-with-cmake"},"Hello world with CMake"),(0,l.kt)("p",null,"Create a folder for the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," build."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},"cd ..\nmkdir HelloWorld-builds-cmake/build-debug\n\ncd HelloWorld")),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},"cd ..\nmkdir -p HelloWorld-builds-cmake/build-debug\n\ncd HelloWorld"))),(0,l.kt)("h3",{id:"cmake-project"},"CMake project"),(0,l.kt)("p",null,"Create ",(0,l.kt)("inlineCode",{parentName:"p"},"CMakeLists.txt")," file with the following content."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},`cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\n# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,p.we)(d.Fo,(0,p.go)(d.Fo))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt\${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)`)),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},`cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\n# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,p.we)(d.q5,(0,p.go)(d.q5))}/TinyORM/TinyORM-builds-cmake/build-debug")\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt\${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)`))),(0,l.kt)("h3",{id:"fetchcontent"},"FetchContent"),(0,l.kt)("p",null,"If you don't have cloned and built the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library, or you want to quickly try TinyORM without wasting time with cloning and building the TinyORM library, then you can use CMake's ",(0,l.kt)("a",{parentName:"p",href:"https://cmake.org/cmake/help/latest/module/FetchContent.html"},(0,l.kt)("inlineCode",{parentName:"a"},"FetchContent"))," module that will do all of this for you."),(0,l.kt)("p",null,"Instead of providing a path by the ",(0,l.kt)("inlineCode",{parentName:"p"},"CMAKE_PREFIX_PATH")," (or using the ",(0,l.kt)("inlineCode",{parentName:"p"},"User Package Registry"),") like in the example below:"),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,p.we)(d.Fo,(0,p.go)(d.Fo))}/TinyORM/TinyORM-builds-cmake/build-debug")`)),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},`# build tree\nlist(APPEND CMAKE_PREFIX_PATH "${(0,p.we)(d.q5,(0,p.go)(d.q5))}/TinyORM/TinyORM-builds-cmake/build-debug")`))),(0,l.kt)("p",null,"You can use the ",(0,l.kt)("a",{parentName:"p",href:"https://cmake.org/cmake/help/latest/module/FetchContent.html"},(0,l.kt)("inlineCode",{parentName:"a"},"FetchContent"))," module like in the following example."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},"cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\n# FetchContent method\ninclude(FetchContent)\nFetchContent_Declare(TinyOrm\n GIT_REPOSITORY https://github.com/silverqx/TinyORM.git\n GIT_TAG origin/main\n OVERRIDE_FIND_PACKAGE\n)\n# Here you can configure TinyORM CMake options\nset(MYSQL_PING OFF)\nset(TOM_EXAMPLE ON)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)")),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-cmake",mdxType:"CodeBlock"},'cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)\n\nproject(HelloWorld LANGUAGES CXX)\n\n# FetchContent method\ninclude(FetchContent)\nFetchContent_Declare(TinyORM\n GIT_REPOSITORY https://github.com/silverqx/TinyORM.git\n GIT_TAG origin/main\n OVERRIDE_FIND_PACKAGE\n)\n# Here you can configure TinyORM CMake options\nset(MYSQL_PING OFF)\nset(TOM_EXAMPLE ON)\n\nTinyORM-builds-cmake/build-debug")\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nadd_executable(HelloWorld\n main.cpp\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\ntarget_link_libraries(HelloWorld\n PRIVATE\n Qt${QT_VERSION_MAJOR}::Core\n TinyOrm::TinyOrm\n)'))),(0,l.kt)("h4",{id:"how-fetchcontent-module-works"},"How FetchContent module works"),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"FetchContent_Declare")," command is like calling the git clone inside the build folder and then adding a cloned folder in a similar way as the ",(0,l.kt)("inlineCode",{parentName:"p"},"add_subdirectory(<cloned_folder>)")," command does."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"FetchContent_MakeAvailable(<package>)")," internally calls the ",(0,l.kt)("inlineCode",{parentName:"p"},"find_package(<package>)")," command or if you pass the ",(0,l.kt)("inlineCode",{parentName:"p"},"OVERRIDE_FIND_PACKAGE")," argument, then you don't have to call the the ",(0,l.kt)("inlineCode",{parentName:"p"},"FetchContent_MakeAvailable"),", but you must call the ",(0,l.kt)("inlineCode",{parentName:"p"},"find_package(<package> x.y.z CONFIG REQUIRED)")," command manually."),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"An advantage of the ",(0,l.kt)("inlineCode",{parentName:"p"},"OVERRIDE_FIND_PACKAGE")," argument is that you can call the ",(0,l.kt)("inlineCode",{parentName:"p"},"find_package")," command much later, and you can insert additional configurations between.")),(0,l.kt)("h3",{id:"build-hello-world-cmake"},"Build Hello world"),(0,l.kt)("p",null,"Now you are ready to configure ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," application."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cd ../HelloWorld-builds-cmake/build-debug\n")),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cmake.exe \`\n-S "${(0,p.go)(d.Fo)}/HelloWorld/HelloWorld" \`\n-B "${(0,p.go)(d.Fo)}/HelloWorld/HelloWorld-builds-cmake/build-debug" \`\n-G 'Ninja' \`\n-D CMAKE_BUILD_TYPE:STRING='Debug' \`\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,p.EA)(d.Fo)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \`\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,p.EA)(d.Fo)}/tmp/HelloWorld"`)),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cmake \\\n-S "${(0,p.go)(d.q5)}/HelloWorld/HelloWorld" \\\n-B "${(0,p.go)(d.q5)}/HelloWorld/HelloWorld-builds-cmake/build-debug" \\\n-G 'Ninja' \\\n-D CMAKE_BUILD_TYPE:STRING='Debug' \\\n-D CMAKE_TOOLCHAIN_FILE:FILEPATH="${(0,p.EA)(d.q5)}/vcpkg/scripts/buildsystems/vcpkg.cmake" \\\n-D CMAKE_INSTALL_PREFIX:PATH="${(0,p.EA)(d.q5)}/tmp/TinyORM"`))),(0,l.kt)("p",null,"And build."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cmake --build . --target all\n")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"Enable the ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#cmake-strict_mode-option"},(0,l.kt)("inlineCode",{parentName:"a"},"TINYORM_STRICT_MODE"))," environment variable to produce better code and to follow good code practices.")),(0,l.kt)("h3",{id:"execute-hello-world-cmake"},"Execute Hello world"),(0,l.kt)("p",null,"Do not forget to add ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyOrm0d.dll")," on the path on Windows and on the ",(0,l.kt)("inlineCode",{parentName:"p"},"LD_LIBRARY_PATH")," on Linux, so ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," application can find it during execution, as is described ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#tinyorm-on-path-cmake"},"here"),"."),(0,l.kt)(r.Z,{groupId:d.IZ,name:"tinyorm-on-path",mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`$env:Path = "${(0,p.go)(d.Fo,!1)}\\TinyORM\\TinyORM-builds-cmake\\build-debug;" + $env:Path`)),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`export LD_LIBRARY_PATH=${(0,p.go)(d.q5)}/TinyORM/TinyORM-builds-cmake/build-debug\${PATH:+:}$PATH`))),(0,l.kt)("p",null,"Execute ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," example."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},".\\HelloWorld.exe\n"))),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"./HelloWorld\n")))),(0,l.kt)("p",null,"The output will look like this."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-less"},'Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts\n1 "First Post"\n2 "Second Post"\n')),(0,l.kt)("h2",{id:"hello-world-with-qmake"},"Hello world with qmake"),(0,l.kt)("p",null,"Create a folder for the ",(0,l.kt)("inlineCode",{parentName:"p"},"qmake")," build."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:d.IM,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-powershell",mdxType:"CodeBlock"},`cd ${(0,p.go)(d.Fo)}/HelloWorld\n\nmkdir HelloWorld-builds-qmake`)),(0,l.kt)(i.Z,{value:d.q5,label:d.C,mdxType:"TabItem"},(0,l.kt)(o.Z,{className:"language-bash",mdxType:"CodeBlock"},`cd ${(0,p.go)(d.q5)}/HelloWorld\n\nmkdir HelloWorld-builds-qmake`))),(0,l.kt)("p",null,"The ",(0,l.kt)("a",{parentName:"p",href:"#source-code"},(0,l.kt)("inlineCode",{parentName:"a"},"source code"))," is the same as for the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld CMake")," example."),(0,l.kt)("h3",{id:"qmake-project"},"qmake project"),(0,l.kt)("p",null,"Create ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld.pro")," qmake file with the following content."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cd HelloWorld\nvim HelloWorld.pro\n")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"To paste a source code correctly in ",(0,l.kt)("inlineCode",{parentName:"p"},"vim"),", press ",(0,l.kt)("kbd",null,"Shift")," + ",(0,l.kt)("kbd",null,"p"),".")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='HelloWorld.pro'",title:"'HelloWorld.pro'"},"QT -= gui\n\nTEMPLATE = app\n\nCONFIG *= cmdline\n\nDEFINES *= PROJECT_TINYORM_HELLOWORLD\n\nSOURCES += $$PWD/main.cpp\n\n# Auto-configure TinyORM library \ud83d\udd25\ninclude($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)\n")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"The exact ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},"folders structure")," is crucial in this example because the paths to the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," source and build folders are relative.")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!")),(0,l.kt)("h4",{id:"auto-configure-using-qmake_conf-and-env"},(0,l.kt)("inlineCode",{parentName:"h4"},"Auto-configure")," using ",(0,l.kt)("inlineCode",{parentName:"h4"},".qmake.conf")," and ",(0,l.kt)("inlineCode",{parentName:"h4"},".env")),(0,l.kt)("p",null,"If you want to have properly configured ",(0,l.kt)("inlineCode",{parentName:"p"},"DEFINES")," (C preprocessor macros) or have Qt headers marked as system headers, then you need to specify a path to the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," qmake features (",(0,l.kt)("inlineCode",{parentName:"p"},".prf")," files) which handle this correctly; this path is provided by the ",(0,l.kt)("inlineCode",{parentName:"p"},"QMAKEFEATURES")," variable and can only be set in the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"Read the ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#consume-tinyorm-library-qmake"},"Consume TinyOrm library (qmake)")," section, as everything that is described in that section applies here as well.")),(0,l.kt)("p",null,"Create the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file in the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," project root folder with the following content."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake",metastring:"title='.qmake.conf'",title:"'.qmake.conf'"},"# 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")),(0,l.kt)("p",null,"Then, create a ",(0,l.kt)("code",null,".env.(win32","|","unix","|","mingw)")," file in the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," project root folder with the following content."),(0,l.kt)(r.Z,{groupId:d.IZ,mdxType:"Tabs"},(0,l.kt)(i.Z,{value:d.Fo,label:".env.win32",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake"},"# Names and values of these qmake variables are crucial, they are used in HelloWorld.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_0_MSVC2022_64bit-Debug/)\n\n# Path to the vcpkg - range-v3\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 *= tiny_ccache_win32\n"))),(0,l.kt)(i.Z,{value:d.q5,label:".env.unix",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake"},"# Names and values of these qmake variables are crucial, they are used in HelloWorld.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_0_clang16_64bit_ccache-Debug/)\n\n# Path to the vcpkg - range-v3\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,l.kt)(i.Z,{value:"mingw",label:".env.mingw",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-qmake"},"# Names and values of these qmake variables are crucial, they are used in HelloWorld.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_0_MSYS2_UCRT64_clang_64bit-Debug/)\n\n# Path to the vcpkg - range-v3\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 *= tiny_ccache_win32\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")))),(0,l.kt)("p",null,"Don't forget to update the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"TINY_VCPKG_ROOT")," folder paths to your needs if you are not using the recommended ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},(0,l.kt)("inlineCode",{parentName:"a"},"Folders structure")),"."),(0,l.kt)("p",null,"You can use the ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree"},"Partial guessing of the ",(0,l.kt)("inlineCode",{parentName:"a"},"TINYORM_BUILD_TREE"))," if you don't like to specify it manually. Just comment out the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," and uncomment the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINY_BUILD_TREE = $$shadowed($$PWD)")," in the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," file."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can entirely avoid the ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," files, just move the ",(0,l.kt)("inlineCode",{parentName:"p"},"TINYORM_BUILD_TREE")," to the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," or remove it by help of ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#partial-guessing-of-the-tinyorm_build_tree"},"Partial guessing of the ",(0,l.kt)("inlineCode",{parentName:"a"},"TINYORM_BUILD_TREE"))," and set the ",(0,l.kt)("inlineCode",{parentName:"p"},"VCPKG_ROOT")," environment variable at system level as is described in ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#set-up-vcpkg-environment"},(0,l.kt)("inlineCode",{parentName:"a"},"Set up vcpkg environment")),".")),(0,l.kt)("admonition",{type:"info"},(0,l.kt)("p",{parentName:"admonition"},"Configuring by the ",(0,l.kt)("inlineCode",{parentName:"p"},".qmake.conf")," and ",(0,l.kt)("inlineCode",{parentName:"p"},".env")," files has one big advantage, which is that you don't have to modify the project files.")),(0,l.kt)("h3",{id:"build-hello-world-qmake"},"Build Hello world"),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"I recommend creating a new ",(0,l.kt)("inlineCode",{parentName:"p"},"Session")," in the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator IDE")," as is described ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#open-qtcreator-ide"},"here"),".")),(0,l.kt)("p",null,"Now you can open the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld.pro")," project in the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator IDE"),"."),(0,l.kt)("p",null,"This will open the ",(0,l.kt)("inlineCode",{parentName:"p"},"Configure Project")," tab, select some kit and update build folder paths to meet our ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#folders-structure"},"folders structure")," or like you want."),(0,l.kt)("img",{src:n(1465).Z,alt:"HelloWorld - QtCreator - Configure Project",width:"760"}),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"You can force the ",(0,l.kt)("inlineCode",{parentName:"p"},"QtCreator")," to generate a build folders structure as is described ",(0,l.kt)("a",{parentName:"p",href:"/building/tinyorm#qtcreator-default-build-directory"},"here"),".")),(0,l.kt)("p",null,"You are ready to configure build options, hit ",(0,l.kt)("kbd",null,"Ctrl"),"+",(0,l.kt)("kbd",null,"5")," to open ",(0,l.kt)("inlineCode",{parentName:"p"},"Project Settings")," tab and select ",(0,l.kt)("inlineCode",{parentName:"p"},"Build")," in the left sidebar to open the ",(0,l.kt)("inlineCode",{parentName:"p"},"Build Settings"),", it should look similar to the following picture."),(0,l.kt)("img",{src:n(6511).Z,className:"no-blurry",alt:"HelloWorld - QtCreator - Build Settings",width:"760"}),(0,l.kt)("p",null,"Disable ",(0,l.kt)("inlineCode",{parentName:"p"},"QML debugging and profiling")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"Qt Quick Compiler"),", they are not used."),(0,l.kt)("p",null,"In the left sidebar open ",(0,l.kt)("inlineCode",{parentName:"p"},"Dependencies")," and check ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," project and ",(0,l.kt)("inlineCode",{parentName:"p"},"Synchronize configuration"),", this setting ensures that the current project will be rebuilt correctly when the ",(0,l.kt)("inlineCode",{parentName:"p"},"TinyORM")," library source code changes."),(0,l.kt)("p",null,"Everything is ready to build, you can press ",(0,l.kt)("kbd",null,"Ctrl"),"+",(0,l.kt)("kbd",null,"b")," to build the project."),(0,l.kt)("h3",{id:"execute-hello-world-qmake"},"Execute Hello world"),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"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,l.kt)("inlineCode",{parentName:"p"},"LD_LIBRARY_PATH")," on Linux."),(0,l.kt)("p",null,"The only thing you might want to change is to run the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," example in the new terminal window. To do so, hit ",(0,l.kt)("kbd",null,"Ctrl"),"+",(0,l.kt)("kbd",null,"5")," to open the ",(0,l.kt)("inlineCode",{parentName:"p"},"Project Settings")," tab and select ",(0,l.kt)("inlineCode",{parentName:"p"},"Run")," in the left sidebar to open the ",(0,l.kt)("inlineCode",{parentName:"p"},"Run Settings"),", then in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Run")," section select the ",(0,l.kt)("inlineCode",{parentName:"p"},"Run in terminal")," checkbox."),(0,l.kt)("p",null,"To execute the ",(0,l.kt)("inlineCode",{parentName:"p"},"HelloWorld")," example press ",(0,l.kt)("kbd",null,"Ctrl")," + ",(0,l.kt)("kbd",null,"r"),"."),(0,l.kt)("p",null,"The output will look like this."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-less"},'Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts\n1 "First Post"\n2 "Second Post"\n')))}b.isMDXComponent=!0},6511:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/qmake-build_settings-ebdc6c0c056d11462096ff10cba682a1.png"},1465:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/qmake-configure_project-8caf87e6af4452f0c28bd15c85c392fc.png"}}]); \ No newline at end of file diff --git a/assets/js/main.120f60f5.js b/assets/js/main.120f60f5.js new file mode 100644 index 000000000..8360c5e30 --- /dev/null +++ b/assets/js/main.120f60f5.js @@ -0,0 +1,2 @@ +/*! For license information please see main.120f60f5.js.LICENSE.txt */ +(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[792],{9188:(e,t,n)=>{"use strict";n.d(t,{W:()=>a});var r=n(6540);function a(){return r.createElement("svg",{width:"20",height:"20",className:"DocSearch-Search-Icon",viewBox:"0 0 20 20","aria-hidden":"true"},r.createElement("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}},8328:(e,t,n)=>{"use strict";n.d(t,{A:()=>f});n(6540);var r=n(3259),a=n.n(r),o=n(4054);const i={"0ab078a9":[()=>Promise.all([n.e(869),n.e(446),n.e(395)]).then(n.bind(n,993)),"@site/docs/building/tinyorm.mdx",993],"1222ea4e":[()=>n.e(153).then(n.bind(n,5897)),"@site/docs/tinyorm/serialization.mdx",5897],17896441:[()=>Promise.all([n.e(869),n.e(446),n.e(401)]).then(n.bind(n,4086)),"@theme/DocItem",4086],"1a4e3797":[()=>Promise.all([n.e(869),n.e(138)]).then(n.bind(n,9057)),"@theme/SearchPage",9057],"21dc2778":[()=>Promise.all([n.e(869),n.e(446),n.e(295)]).then(n.bind(n,6807)),"@site/docs/database/migrations.mdx",6807],"3dd307b5":[()=>n.e(117).then(n.bind(n,1126)),"@site/docs/tinyorm/collections.mdx",1126],"59b1a96c":[()=>n.e(485).then(n.bind(n,3398)),"@site/docs/README.mdx",3398],"5b254f70":[()=>n.e(82).then(n.bind(n,5105)),"@site/docs/tinyorm/getting-started.mdx",5105],"5e95c892":[()=>n.e(647).then(n.bind(n,7121)),"@theme/DocsRoot",7121],"62a1276f":[()=>n.e(304).then(n.bind(n,6257)),"@site/docs/tinyorm/casts.mdx",6257],"6629c45f":[()=>n.e(820).then(n.t.bind(n,72,19)),"@generated/docusaurus-plugin-content-docs/default/p/index.json",72],"7333c691":[()=>n.e(638).then(n.bind(n,3156)),"@site/docs/tinyorm/relationships.mdx",3156],"8a8faf8d":[()=>Promise.all([n.e(869),n.e(446),n.e(129)]).then(n.bind(n,5270)),"@site/docs/building/migrations.mdx",5270],a4d3e054:[()=>n.e(755).then(n.bind(n,7667)),"@site/docs/database/seeding.mdx",7667],a7bd4aaa:[()=>n.e(98).then(n.bind(n,4532)),"@theme/DocVersionRoot",4532],a94703ab:[()=>Promise.all([n.e(869),n.e(48)]).then(n.bind(n,2559)),"@theme/DocRoot",2559],aba21aa0:[()=>n.e(742).then(n.t.bind(n,7093,19)),"@generated/docusaurus-plugin-content-docs/default/__plugin.json",7093],ba3d4959:[()=>Promise.all([n.e(869),n.e(170)]).then(n.bind(n,3418)),"@site/docs/database/getting-started.mdx",3418],c141421f:[()=>n.e(957).then(n.t.bind(n,936,19)),"@generated/docusaurus-theme-search-algolia/default/__plugin.json",936],cb1e72f9:[()=>n.e(258).then(n.bind(n,4028)),"@site/docs/tinydrivers/getting-started.mdx",4028],cbe663fe:[()=>n.e(995).then(n.bind(n,4380)),"@site/docs/database/query-builder.mdx",4380],d459b1c4:[()=>n.e(27).then(n.bind(n,7893)),"@site/docs/supported-compilers.mdx",7893],e19c288b:[()=>Promise.all([n.e(869),n.e(69)]).then(n.bind(n,8157)),"@site/docs/sponsors.mdx",8157],e3ac21cb:[()=>n.e(467).then(n.bind(n,7759)),"@site/docs/dependencies.mdx",7759],fb313d4e:[()=>n.e(871).then(n.bind(n,7626)),"@site/docs/features-summary.mdx",7626],feaee7f3:[()=>Promise.all([n.e(869),n.e(446),n.e(983)]).then(n.bind(n,3750)),"@site/docs/building/hello-world.mdx",3750]};var l=n(4848);function s(e){let{error:t,retry:n,pastDelay:r}=e;return t?(0,l.jsxs)("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"},children:[(0,l.jsx)("p",{children:String(t)}),(0,l.jsx)("div",{children:(0,l.jsx)("button",{type:"button",onClick:n,children:"Retry"})})]}):r?(0,l.jsx)("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"},children:(0,l.jsx)("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb",children:(0,l.jsxs)("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2",children:[(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsxs)("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0",children:[(0,l.jsx)("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),(0,l.jsx)("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})]}),(0,l.jsx)("circle",{cx:"22",cy:"22",r:"8",children:(0,l.jsx)("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"})})]})})}):null}var u=n(6921),c=n(3102);function d(e,t){if("*"===e)return a()({loading:s,loader:()=>n.e(237).then(n.bind(n,2237)),modules:["@theme/NotFound"],webpack:()=>[2237],render(e,t){const n=e.default;return(0,l.jsx)(c.W,{value:{plugin:{name:"native",id:"default"}},children:(0,l.jsx)(n,{...t})})}});const r=o[`${e}-${t}`],d={},f=[],p=[],m=(0,u.A)(r);return Object.entries(m).forEach((e=>{let[t,n]=e;const r=i[n];r&&(d[t]=r[0],f.push(r[1]),p.push(r[2]))})),a().Map({loading:s,loader:d,modules:f,webpack:()=>p,render(t,n){const a=JSON.parse(JSON.stringify(r));Object.entries(t).forEach((t=>{let[n,r]=t;const o=r.default;if(!o)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof o&&"function"!=typeof o||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{o[e]=r[e]}));let i=a;const l=n.split(".");l.slice(0,-1).forEach((e=>{i=i[e]})),i[l[l.length-1]]=o}));const o=a.__comp;delete a.__comp;const i=a.__context;delete a.__context;const s=a.__props;return delete a.__props,(0,l.jsx)(c.W,{value:i,children:(0,l.jsx)(o,{...a,...s,...n})})}})}const f=[{path:"/search",component:d("/search","5de"),exact:!0},{path:"/",component:d("/","dbe"),routes:[{path:"/",component:d("/","8df"),routes:[{path:"/",component:d("/","017"),routes:[{path:"/building/hello-world",component:d("/building/hello-world","9c2"),exact:!0,sidebar:"tinyormSidebar"},{path:"/building/migrations",component:d("/building/migrations","531"),exact:!0,sidebar:"tinyormSidebar"},{path:"/building/tinyorm",component:d("/building/tinyorm","b57"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/getting-started",component:d("/database/getting-started","0b1"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/migrations",component:d("/database/migrations","6de"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/query-builder",component:d("/database/query-builder","2bb"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/seeding",component:d("/database/seeding","9c2"),exact:!0,sidebar:"tinyormSidebar"},{path:"/dependencies",component:d("/dependencies","a43"),exact:!0,sidebar:"tinyormSidebar"},{path:"/features-summary",component:d("/features-summary","235"),exact:!0,sidebar:"tinyormSidebar"},{path:"/sponsors",component:d("/sponsors","3aa"),exact:!0,sidebar:"tinyormSidebar"},{path:"/supported-compilers",component:d("/supported-compilers","699"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinydrivers/getting-started",component:d("/tinydrivers/getting-started","071"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/casts",component:d("/tinyorm/casts","09c"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/collections",component:d("/tinyorm/collections","5b8"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/getting-started",component:d("/tinyorm/getting-started","699"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/relationships",component:d("/tinyorm/relationships","80b"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/serialization",component:d("/tinyorm/serialization","b90"),exact:!0,sidebar:"tinyormSidebar"},{path:"/",component:d("/","f1e"),exact:!0,sidebar:"tinyormSidebar"}]}]}]},{path:"*",component:d("*")}]},6125:(e,t,n)=>{"use strict";n.d(t,{o:()=>o,x:()=>i});var r=n(6540),a=n(4848);const o=r.createContext(!1);function i(e){let{children:t}=e;const[n,i]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{i(!0)}),[]),(0,a.jsx)(o.Provider,{value:n,children:t})}},6756:(e,t,n)=>{"use strict";var r=n(6540),a=n(5338),o=n(4625),i=n(545),l=n(8193);const s=[n(1911),n(119),n(6491),n(6294),n(1043)];var u=n(8328),c=n(6347),d=n(2831),f=n(1838),p=n(9466);const m="tinyorm.rootFolder.",h=()=>{const[e,t]=(0,r.useState)({}),n=(0,r.useCallback)(((e,t)=>{(0,p.Wf)(`${m}${e}`).set(t)}),[]);return(0,r.useEffect)((()=>{try{const e={};(0,p.Eo)().forEach((t=>{if(t.startsWith(m)){const n=t.substring(19);e[n]=(0,p.Wf)(t).get()}})),t(e)}catch(e){console.error(e)}}),[]),{rootFolder:e,setRootFolder:(e,r)=>{t((t=>({...t,[e]:r}))),n(e,r)}}};var g=n(4848);function y(e){const{rootFolder:t,setRootFolder:n}=h(),a=(0,r.useMemo)((()=>({rootFolder:t,setRootFolder:n})),[t,n]);return(0,g.jsx)(f.A.Provider,{value:a,children:e.children})}let b,v,E,S=0;function _(){const e=document.querySelector('.theme-doc-sidebar-container div[title="Expand sidebar"]');e&&(e.title+=" (q)",clearTimeout(v))}function w(){E=document.querySelector(".theme-doc-sidebar-container > div > div > button"),S>=50?clearInterval(b):E?(E.title+=" (q)",clearInterval(b),E.addEventListener("click",(()=>{v=setTimeout(_,300)}))):++S}function k(e){const t=e.target,n=e.target.nodeName;t.isContentEditable||"INPUT"===n||"TEXTAREA"===n||"SELECT"===n||"KeyQ"===e.code&&(E.click(),v=setTimeout(_,300))}function T(){var e;e=()=>{b=setInterval(w,30),document.addEventListener("keyup",k)},"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)}function x(e){let{children:t}=e;return(0,g.jsx)(y,{children:t})}l.A.canUseDOM&&T();var A=n(5260),C=n(4586),R=n(6025),O=n(6342),N=n(9024),I=n(2131),L=n(4090),P=n(2967),D=n(440),M=n(1463);function j(){const{i18n:{currentLocale:e,defaultLocale:t,localeConfigs:n}}=(0,C.A)(),r=(0,I.o)(),a=n[e].htmlLang,o=e=>e.replace("-","_");return(0,g.jsxs)(A.A,{children:[Object.entries(n).map((e=>{let[t,{htmlLang:n}]=e;return(0,g.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:n},t)})),(0,g.jsx)("link",{rel:"alternate",href:r.createUrl({locale:t,fullyQualified:!0}),hrefLang:"x-default"}),(0,g.jsx)("meta",{property:"og:locale",content:o(a)}),Object.values(n).filter((e=>a!==e.htmlLang)).map((e=>(0,g.jsx)("meta",{property:"og:locale:alternate",content:o(e.htmlLang)},`meta-og-${e.htmlLang}`)))]})}function U(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,C.A)(),r=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,C.A)(),{pathname:r}=(0,c.zy)();return e+(0,D.applyTrailingSlash)((0,R.A)(r),{trailingSlash:n,baseUrl:t})}(),a=t?`${n}${t}`:r;return(0,g.jsxs)(A.A,{children:[(0,g.jsx)("meta",{property:"og:url",content:a}),(0,g.jsx)("link",{rel:"canonical",href:a})]})}function F(){const{i18n:{currentLocale:e}}=(0,C.A)(),{metadata:t,image:n}=(0,O.p)();return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(A.A,{children:[(0,g.jsx)("meta",{name:"twitter:card",content:"summary_large_image"}),(0,g.jsx)("body",{className:L.w})]}),n&&(0,g.jsx)(N.be,{image:n}),(0,g.jsx)(U,{}),(0,g.jsx)(j,{}),(0,g.jsx)(M.A,{tag:P.Cy,locale:e}),(0,g.jsx)(A.A,{children:t.map(((e,t)=>(0,g.jsx)("meta",{...e},t)))})]})}const B=new Map;var z=n(6125),$=n(6988),H=n(205);function G(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=s.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const V=function(e){let{children:t,location:n,previousLocation:r}=e;return(0,H.A)((()=>{r!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:r}),G("onRouteDidUpdate",{previousLocation:r,location:n}))}),[r,n]),t};function W(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.u)(u.A,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class Y extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.A.canUseDOM?G("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=G("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),W(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return(0,g.jsx)(V,{previousLocation:this.previousLocation,location:t,children:(0,g.jsx)(c.qh,{location:t,render:()=>e})})}}const K=Y,q="__docusaurus-base-url-issue-banner-container",X="__docusaurus-base-url-issue-banner",Q="__docusaurus-base-url-issue-banner-suggestion-container";function Z(e){return`\ndocument.addEventListener('DOMContentLoaded', function maybeInsertBanner() {\n var shouldInsert = typeof window['docusaurus'] === 'undefined';\n shouldInsert && insertBanner();\n});\n\nfunction insertBanner() {\n var bannerContainer = document.createElement('div');\n bannerContainer.id = '${q}';\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${X}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${Q}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n document.body.prepend(bannerContainer);\n var suggestionContainer = document.getElementById('${Q}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function J(){const{siteConfig:{baseUrl:e}}=(0,C.A)();return(0,g.jsx)(g.Fragment,{children:!l.A.canUseDOM&&(0,g.jsx)(A.A,{children:(0,g.jsx)("script",{children:Z(e)})})})}function ee(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,C.A)(),{pathname:n}=(0,c.zy)();return t&&n===e?(0,g.jsx)(J,{}):null}function te(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:r,localeConfigs:a}}=(0,C.A)(),o=(0,R.A)(e),{htmlLang:i,direction:l}=a[r];return(0,g.jsxs)(A.A,{children:[(0,g.jsx)("html",{lang:i,dir:l}),(0,g.jsx)("title",{children:t}),(0,g.jsx)("meta",{property:"og:title",content:t}),(0,g.jsx)("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&(0,g.jsx)("meta",{name:"robots",content:"noindex, nofollow"}),e&&(0,g.jsx)("link",{rel:"icon",href:o})]})}var ne=n(7489),re=n(2303);function ae(){const e=(0,re.A)();return(0,g.jsx)(A.A,{children:(0,g.jsx)("html",{"data-has-hydrated":e})})}const oe=(0,d.v)(u.A);function ie(){const e=function(e){if(B.has(e.pathname))return{...e,pathname:B.get(e.pathname)};if((0,d.u)(u.A,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return B.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return B.set(e.pathname,t),{...e,pathname:t}}((0,c.zy)());return(0,g.jsx)(K,{location:e,children:oe})}function le(){return(0,g.jsx)(ne.A,{children:(0,g.jsx)($.l,{children:(0,g.jsxs)(z.x,{children:[(0,g.jsxs)(x,{children:[(0,g.jsx)(te,{}),(0,g.jsx)(F,{}),(0,g.jsx)(ee,{}),(0,g.jsx)(ie,{})]}),(0,g.jsx)(ae,{})]})})})}var se=n(4054);const ue=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var ce=n(6921);const de=new Set,fe=new Set,pe=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,me={prefetch:e=>{if(!(e=>!pe()&&!fe.has(e)&&!de.has(e))(e))return!1;de.add(e);const t=(0,d.u)(u.A,e).flatMap((e=>{return t=e.route.path,Object.entries(se).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,ce.A)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?ue(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!pe()&&!fe.has(e))(e)&&(fe.add(e),W(e))},he=Object.freeze(me),ge=Boolean(!0);if(l.A.canUseDOM){window.docusaurus=he;const e=document.getElementById("__docusaurus"),t=(0,g.jsx)(i.vd,{children:(0,g.jsx)(o.Kd,{children:(0,g.jsx)(le,{})})}),n=(e,t)=>{console.error("Docusaurus React Root onRecoverableError:",e,t)},l=()=>{if(window.docusaurusRoot)window.docusaurusRoot.render(t);else if(ge)window.docusaurusRoot=a.hydrateRoot(e,t,{onRecoverableError:n});else{const r=a.createRoot(e,{onRecoverableError:n});r.render(t),window.docusaurusRoot=r}};W(window.location.pathname).then((()=>{(0,r.startTransition)(l)}))}},6988:(e,t,n)=>{"use strict";n.d(t,{o:()=>d,l:()=>f});var r=n(6540),a=n(4784);const o=JSON.parse('{"docusaurus-plugin-content-docs":{"default":{"path":"/","versions":[{"name":"current","label":"Next","isLast":true,"path":"/","mainDocId":"README","docs":[{"id":"building/hello-world","path":"/building/hello-world","sidebar":"tinyormSidebar"},{"id":"building/migrations","path":"/building/migrations","sidebar":"tinyormSidebar"},{"id":"building/tinyorm","path":"/building/tinyorm","sidebar":"tinyormSidebar"},{"id":"database/getting-started","path":"/database/getting-started","sidebar":"tinyormSidebar"},{"id":"database/migrations","path":"/database/migrations","sidebar":"tinyormSidebar"},{"id":"database/query-builder","path":"/database/query-builder","sidebar":"tinyormSidebar"},{"id":"database/seeding","path":"/database/seeding","sidebar":"tinyormSidebar"},{"id":"dependencies","path":"/dependencies","sidebar":"tinyormSidebar"},{"id":"features-summary","path":"/features-summary","sidebar":"tinyormSidebar"},{"id":"README","path":"/","sidebar":"tinyormSidebar"},{"id":"sponsors","path":"/sponsors","sidebar":"tinyormSidebar"},{"id":"supported-compilers","path":"/supported-compilers","sidebar":"tinyormSidebar"},{"id":"tinydrivers/getting-started","path":"/tinydrivers/getting-started","sidebar":"tinyormSidebar"},{"id":"tinyorm/casts","path":"/tinyorm/casts","sidebar":"tinyormSidebar"},{"id":"tinyorm/collections","path":"/tinyorm/collections","sidebar":"tinyormSidebar"},{"id":"tinyorm/getting-started","path":"/tinyorm/getting-started","sidebar":"tinyormSidebar"},{"id":"tinyorm/relationships","path":"/tinyorm/relationships","sidebar":"tinyormSidebar"},{"id":"tinyorm/serialization","path":"/tinyorm/serialization","sidebar":"tinyormSidebar"}],"draftIds":[],"sidebars":{"tinyormSidebar":{"link":{"path":"/","label":"\ud83d\udd25 Prologue"}}}}],"breadcrumbs":true}},"docusaurus-plugin-google-gtag":{"default":{"trackingID":["G-2QRS622BWQ"],"anonymizeIP":false,"id":"default"}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var l=n(2654);const s=JSON.parse('{"docusaurusVersion":"3.3.2","siteVersion":"1.1.0","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"3.3.2"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"3.3.2"},"docusaurus-plugin-google-gtag":{"type":"package","name":"@docusaurus/plugin-google-gtag","version":"3.3.2"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"3.3.2"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"3.3.2"},"docusaurus-theme-search-algolia":{"type":"package","name":"@docusaurus/theme-search-algolia","version":"3.3.2"},"docusaurus-plugin-client-redirects":{"type":"package","name":"@docusaurus/plugin-client-redirects","version":"3.3.2"},"webpack-configuration-plugin":{"type":"local"},"postcss-configuration-plugin":{"type":"local"},"tiny-common":{"type":"local"}}}');var u=n(4848);const c={siteConfig:a.A,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},d=r.createContext(c);function f(e){let{children:t}=e;return(0,u.jsx)(d.Provider,{value:c,children:t})}},7489:(e,t,n)=>{"use strict";n.d(t,{A:()=>h});var r=n(6540),a=n(8193),o=n(5260),i=n(440),l=n(9201),s=n(3102),u=n(4848);function c(e){let{error:t,tryAgain:n}=e;return(0,u.jsxs)("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"},children:[(0,u.jsx)("h1",{style:{fontSize:"3rem"},children:"This page crashed"}),(0,u.jsx)("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"},children:"Try again"}),(0,u.jsx)(d,{error:t})]})}function d(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,u.jsx)("p",{style:{whiteSpace:"pre-wrap"},children:n})}function f(e){let{children:t}=e;return(0,u.jsx)(s.W,{value:{plugin:{name:"docusaurus-core-error-boundary",id:"default"}},children:t})}function p(e){let{error:t,tryAgain:n}=e;return(0,u.jsx)(f,{children:(0,u.jsxs)(h,{fallback:()=>(0,u.jsx)(c,{error:t,tryAgain:n}),children:[(0,u.jsx)(o.A,{children:(0,u.jsx)("title",{children:"Page Error"})}),(0,u.jsx)(l.A,{children:(0,u.jsx)(c,{error:t,tryAgain:n})})]})})}const m=e=>(0,u.jsx)(p,{...e});class h extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.A.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??m)(e)}return e??null}}},8193:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5260:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});n(6540);var r=n(545),a=n(4848);function o(e){return(0,a.jsx)(r.mg,{...e})}},8774:(e,t,n)=>{"use strict";n.d(t,{A:()=>p});var r=n(6540),a=n(4625),o=n(440),i=n(4586),l=n(6654),s=n(8193),u=n(3427),c=n(6025),d=n(4848);function f(e,t){let{isNavLink:n,to:f,href:p,activeClassName:m,isActive:h,"data-noBrokenLinkCheck":g,autoAddBaseUrl:y=!0,...b}=e;const{siteConfig:{trailingSlash:v,baseUrl:E}}=(0,i.A)(),{withBaseUrl:S}=(0,c.h)(),_=(0,u.A)(),w=(0,r.useRef)(null);(0,r.useImperativeHandle)(t,(()=>w.current));const k=f||p;const T=(0,l.A)(k),x=k?.replace("pathname://","");let A=void 0!==x?(C=x,y&&(e=>e.startsWith("/"))(C)?S(C):C):void 0;var C;A&&T&&(A=(0,o.applyTrailingSlash)(A,{trailingSlash:v,baseUrl:E}));const R=(0,r.useRef)(!1),O=n?a.k2:a.N_,N=s.A.canUseIntersectionObserver,I=(0,r.useRef)(),L=()=>{R.current||null==A||(window.docusaurus.preload(A),R.current=!0)};(0,r.useEffect)((()=>(!N&&T&&null!=A&&window.docusaurus.prefetch(A),()=>{N&&I.current&&I.current.disconnect()})),[I,A,N,T]);const P=A?.startsWith("#")??!1,D=!b.target||"_self"===b.target,M=!A||!T||!D||P;return g||!P&&M||_.collectLink(A),b.id&&_.collectAnchor(b.id),M?(0,d.jsx)("a",{ref:w,href:A,...k&&!T&&{target:"_blank",rel:"noopener noreferrer"},...b}):(0,d.jsx)(O,{...b,onMouseEnter:L,onTouchStart:L,innerRef:e=>{w.current=e,N&&e&&T&&(I.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(I.current.unobserve(e),I.current.disconnect(),null!=A&&window.docusaurus.prefetch(A))}))})),I.current.observe(e))},to:A,...n&&{isActive:h,activeClassName:m}})}const p=r.forwardRef(f)},1312:(e,t,n)=>{"use strict";n.d(t,{A:()=>u,T:()=>s});var r=n(6540),a=n(4848);function o(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var i=n(2654);function l(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return i[t??n]??n??t}function s(e,t){let{message:n,id:r}=e;return o(l({message:n,id:r}),t)}function u(e){let{children:t,id:n,values:r}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const i=l({message:t,id:n});return(0,a.jsx)(a.Fragment,{children:o(i,r)})}},7065:(e,t,n)=>{"use strict";n.d(t,{W:()=>r});const r="default"},6654:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{A:()=>a,z:()=>r})},6025:(e,t,n)=>{"use strict";n.d(t,{A:()=>l,h:()=>i});var r=n(6540),a=n(4586),o=n(6654);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.A)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.z)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},3427:(e,t,n)=>{"use strict";n.d(t,{A:()=>i});var r=n(6540);n(4848);const a=r.createContext({collectAnchor:()=>{},collectLink:()=>{}}),o=()=>(0,r.useContext)(a);function i(){return o()}},4586:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var r=n(6540),a=n(6988);function o(){return(0,r.useContext)(a.o)}},2303:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var r=n(6540),a=n(6125);function o(){return(0,r.useContext)(a.o)}},205:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});var r=n(6540);const a=n(8193).A.canUseDOM?r.useLayoutEffect:r.useEffect},6921:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[o,i]=n;const l=a?`${a}.${o}`:o;r(i)?e(i,l):t[l]=i}))}(e),t}},3102:(e,t,n)=>{"use strict";n.d(t,{W:()=>i,o:()=>o});var r=n(6540),a=n(4848);const o=r.createContext(null);function i(e){let{children:t,value:n}=e;const i=r.useContext(o),l=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:i,value:n})),[i,n]);return(0,a.jsx)(o.Provider,{value:l,children:t})}},4070:(e,t,n)=>{"use strict";n.d(t,{zK:()=>y,vT:()=>p,gk:()=>m,Gy:()=>d,HW:()=>b,ht:()=>f,r7:()=>g,jh:()=>h});var r=n(6347),a=n(4586),o=n(7065);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.A)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.B6)(t,{path:e.path,exact:!1,strict:!1})))}function u(e,t){const n=s(e,t),a=n?.docs.find((e=>!!(0,r.B6)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const c={},d=()=>i("docusaurus-plugin-content-docs")??c,f=e=>{try{return function(e,t,n){void 0===t&&(t=o.W),void 0===n&&(n={});const r=i(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0})}catch(t){throw new Error("You are using a feature of the Docusaurus docs plugin, but this plugin does not seem to be enabled"+("Default"===e?"":` (pluginId=${e}`),{cause:t})}};function p(e){void 0===e&&(e={});const t=d(),{pathname:n}=(0,r.zy)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.B6)(t,{path:n.path,exact:!1,strict:!1})})),o=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!o&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return o}(t,n,e)}function m(e){void 0===e&&(e={});const t=p(e),{pathname:n}=(0,r.zy)();if(!t)return;return{activePlugin:t,activeVersion:s(t.pluginData,n)}}function h(e){return f(e).versions}function g(e){const t=f(e);return l(t)}function y(e){const t=f(e),{pathname:n}=(0,r.zy)();return u(t,n)}function b(e){const t=f(e),{pathname:n}=(0,r.zy)();return function(e,t){const n=l(e);return{latestDocSuggestion:u(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},1911:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={onRouteDidUpdate(e){let{location:t,previousLocation:n}=e;!n||t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash||setTimeout((()=>{window.gtag("set","page_path",t.pathname+t.search+t.hash),window.gtag("event","page_view")}))}}},6294:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(5947),a=n.n(r);a().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},6491:(e,t,n)=>{"use strict";n.r(t);var r=n(1765),a=n(4784);!function(e){const{themeConfig:{prism:t}}=a.A,{additionalLanguages:r}=t;globalThis.Prism=e,r.forEach((e=>{"php"===e&&n(9700),n(652)(`./prism-${e}`)})),["qmake"].forEach((e=>n(1910)(`./prism-${e}`))),delete globalThis.Prism}(r.My)},1107:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});n(6540);var r=n(4164),a=n(1312),o=n(6342),i=n(8774),l=n(3427);const s={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};var u=n(4848);function c(e){let{as:t,id:n,...c}=e;const d=(0,l.A)(),{navbar:{hideOnScroll:f}}=(0,o.p)();if("h1"===t||!n)return(0,u.jsx)(t,{...c,id:void 0});d.collectAnchor(n);const p=(0,a.T)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof c.children?c.children:n});return(0,u.jsxs)(t,{...c,className:(0,r.A)("anchor",f?s.anchorWithHideOnScrollNavbar:s.anchorWithStickyNavbar,c.className),id:n,children:[c.children,(0,u.jsx)(i.A,{className:"hash-link",to:`#${n}`,"aria-label":p,title:p,children:"\u200b"})]})}},3186:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});n(6540);const r={iconExternalLink:"iconExternalLink_nPIU"};var a=n(4848);function o(e){let{width:t=13.5,height:n=13.5}=e;return(0,a.jsx)("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:r.iconExternalLink,children:(0,a.jsx)("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"})})}},9201:(e,t,n)=>{"use strict";n.d(t,{A:()=>Lt});var r=n(6540),a=n(4164),o=n(7489),i=n(9024),l=n(6347),s=n(1312),u=n(5062),c=n(4848);const d="__docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,r.useRef)(null),{action:t}=(0,l.W6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&f(t)}),[]);return(0,u.$)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}const m=(0,s.T)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??m,{containerRef:n,onClick:r}=p();return(0,c.jsx)("div",{ref:n,role:"region","aria-label":m,children:(0,c.jsx)("a",{...e,href:`#${d}`,onClick:r,children:t})})}var g=n(7559),y=n(4090);const b={skipToContent:"skipToContent_fXgn"};function v(){return(0,c.jsx)(h,{className:b.skipToContent})}var E=n(6342),S=n(5041);function _(e){let{width:t=21,height:n=21,color:r="currentColor",strokeWidth:a=1.2,className:o,...i}=e;return(0,c.jsx)("svg",{viewBox:"0 0 15 15",width:t,height:n,...i,children:(0,c.jsx)("g",{stroke:r,strokeWidth:a,children:(0,c.jsx)("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})})})}const w={closeButton:"closeButton_CVFx"};function k(e){return(0,c.jsx)("button",{type:"button","aria-label":(0,s.T)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"}),...e,className:(0,a.A)("clean-btn close",w.closeButton,e.className),children:(0,c.jsx)(_,{width:14,height:14,strokeWidth:3.1})})}const T={content:"content_knG7"};function x(e){const{announcementBar:t}=(0,E.p)(),{content:n}=t;return(0,c.jsx)("div",{...e,className:(0,a.A)(T.content,e.className),dangerouslySetInnerHTML:{__html:n}})}const A={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function C(){const{announcementBar:e}=(0,E.p)(),{isActive:t,close:n}=(0,S.Mj)();if(!t)return null;const{backgroundColor:r,textColor:a,isCloseable:o}=e;return(0,c.jsxs)("div",{className:A.announcementBar,style:{backgroundColor:r,color:a},role:"banner",children:[o&&(0,c.jsx)("div",{className:A.announcementBarPlaceholder}),(0,c.jsx)(x,{className:A.announcementBarContent}),o&&(0,c.jsx)(k,{onClick:n,className:A.announcementBarClose})]})}var R=n(2069),O=n(3104);var N=n(9532),I=n(5600);const L=r.createContext(null);function P(e){let{children:t}=e;const n=function(){const e=(0,R.M)(),t=(0,I.YL)(),[n,a]=(0,r.useState)(!1),o=null!==t.component,i=(0,N.ZC)(o);return(0,r.useEffect)((()=>{o&&!i&&a(!0)}),[o,i]),(0,r.useEffect)((()=>{o?e.shown||a(!0):a(!1)}),[e.shown,o]),(0,r.useMemo)((()=>[n,a]),[n])}();return(0,c.jsx)(L.Provider,{value:n,children:t})}function D(e){if(e.component){const t=e.component;return(0,c.jsx)(t,{...e.props})}}function M(){const e=(0,r.useContext)(L);if(!e)throw new N.dV("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),o=(0,I.YL)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:D(o)})),[a,o,t])}function j(e){let{header:t,primaryMenu:n,secondaryMenu:r}=e;const{shown:o}=M();return(0,c.jsxs)("div",{className:"navbar-sidebar",children:[t,(0,c.jsxs)("div",{className:(0,a.A)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":o}),children:[(0,c.jsx)("div",{className:"navbar-sidebar__item menu",children:n}),(0,c.jsx)("div",{className:"navbar-sidebar__item menu",children:r})]})]})}var U=n(5293),F=n(2303);function B(e){return(0,c.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,c.jsx)("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"})})}function z(e){return(0,c.jsx)("svg",{viewBox:"0 0 24 24",width:24,height:24,...e,children:(0,c.jsx)("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"})})}const $={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function H(e){let{className:t,buttonClassName:n,value:r,onChange:o}=e;const i=(0,F.A)(),l=(0,s.T)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===r?(0,s.T)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,s.T)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return(0,c.jsx)("div",{className:(0,a.A)($.toggle,t),children:(0,c.jsxs)("button",{className:(0,a.A)("clean-btn",$.toggleButton,!i&&$.toggleButtonDisabled,n),type:"button",onClick:()=>o("dark"===r?"light":"dark"),disabled:!i,title:l,"aria-label":l,"aria-live":"polite",children:[(0,c.jsx)(B,{className:(0,a.A)($.toggleIcon,$.lightToggleIcon)}),(0,c.jsx)(z,{className:(0,a.A)($.toggleIcon,$.darkToggleIcon)})]})})}const G=r.memo(H),V={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function W(e){let{className:t}=e;const n=(0,E.p)().navbar.style,r=(0,E.p)().colorMode.disableSwitch,{colorMode:a,setColorMode:o}=(0,U.G)();return r?null:(0,c.jsx)(G,{className:t,buttonClassName:"dark"===n?V.darkNavbarColorModeToggle:void 0,value:a,onChange:o})}var Y=n(3465);function K(){return(0,c.jsx)(Y.A,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function q(){const e=(0,R.M)();return(0,c.jsx)("button",{type:"button","aria-label":(0,s.T)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle(),children:(0,c.jsx)(_,{color:"var(--ifm-color-emphasis-600)"})})}function X(){return(0,c.jsxs)("div",{className:"navbar-sidebar__brand",children:[(0,c.jsx)(K,{}),(0,c.jsx)(W,{className:"margin-right--md"}),(0,c.jsx)(q,{})]})}var Q=n(8774),Z=n(6025),J=n(6654),ee=n(1252),te=n(3186);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:r,href:a,label:o,html:i,isDropdownLink:l,prependBaseUrlToHref:s,...u}=e;const d=(0,Z.A)(r),f=(0,Z.A)(t),p=(0,Z.A)(a,{forcePrependBaseUrl:!0}),m=o&&a&&!(0,J.A)(a),h=i?{dangerouslySetInnerHTML:{__html:i}}:{children:(0,c.jsxs)(c.Fragment,{children:[o,m&&(0,c.jsx)(te.A,{...l&&{width:12,height:12}})]})};return a?(0,c.jsx)(Q.A,{href:s?p:a,...u,...h}):(0,c.jsx)(Q.A,{to:d,isNavLink:!0,...(t||n)&&{isActive:(e,t)=>n?(0,ee.G)(n,t.pathname):t.pathname.startsWith(f)},...u,...h})}function re(e){let{className:t,isDropdownItem:n=!1,...r}=e;const o=(0,c.jsx)(ne,{className:(0,a.A)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n,...r});return n?(0,c.jsx)("li",{children:o}):o}function ae(e){let{className:t,isDropdownItem:n,...r}=e;return(0,c.jsx)("li",{className:"menu__list-item",children:(0,c.jsx)(ne,{className:(0,a.A)("menu__link",t),...r})})}function oe(e){let{mobile:t=!1,position:n,...r}=e;const a=t?ae:re;return(0,c.jsx)(a,{...r,activeClassName:r.activeClassName??(t?"menu__link--active":"navbar__link--active")})}var ie=n(1422),le=n(9169),se=n(4586);const ue={dropdownNavbarItemMobile:"dropdownNavbarItemMobile_S0Fm"};function ce(e,t){return e.some((e=>function(e,t){return!!(0,le.ys)(e.to,t)||!!(0,ee.G)(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function de(e){let{items:t,position:n,className:o,onClick:i,...l}=e;const s=(0,r.useRef)(null),[u,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{s.current&&!s.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[s]),(0,c.jsxs)("div",{ref:s,className:(0,a.A)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":u}),children:[(0,c.jsx)(ne,{"aria-haspopup":"true","aria-expanded":u,role:"button",href:l.to?void 0:"#",className:(0,a.A)("navbar__link",o),...l,onClick:l.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!u))},children:l.children??l.label}),(0,c.jsx)("ul",{className:"dropdown__menu",children:t.map(((e,t)=>(0,r.createElement)(Ve,{isDropdownItem:!0,activeClassName:"dropdown__link--active",...e,key:t})))})]})}function fe(e){let{items:t,className:n,position:o,onClick:i,...s}=e;const u=function(){const{siteConfig:{baseUrl:e}}=(0,se.A)(),{pathname:t}=(0,l.zy)();return t.replace(e,"/")}(),d=ce(t,u),{collapsed:f,toggleCollapsed:p,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[u,d,m]),(0,c.jsxs)("li",{className:(0,a.A)("menu__list-item",{"menu__list-item--collapsed":f}),children:[(0,c.jsx)(ne,{role:"button",className:(0,a.A)(ue.dropdownNavbarItemMobile,"menu__link menu__link--sublist menu__link--sublist-caret",n),...s,onClick:e=>{e.preventDefault(),p()},children:s.children??s.label}),(0,c.jsx)(ie.N,{lazy:!0,as:"ul",className:"menu__list",collapsed:f,children:t.map(((e,t)=>(0,r.createElement)(Ve,{mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active",...e,key:t})))})]})}function pe(e){let{mobile:t=!1,...n}=e;const r=t?fe:de;return(0,c.jsx)(r,{...n})}var me=n(2131);function he(e){let{width:t=20,height:n=20,...r}=e;return(0,c.jsx)("svg",{viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0,...r,children:(0,c.jsx)("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"})})}const ge="iconLanguage_nlXk";var ye=n(961);function be(){return r.createElement("svg",{width:"15",height:"15",className:"DocSearch-Control-Key-Icon"},r.createElement("path",{d:"M4.505 4.496h2M5.505 5.496v5M8.216 4.496l.055 5.993M10 7.5c.333.333.5.667.5 1v2M12.326 4.5v5.996M8.384 4.496c1.674 0 2.116 0 2.116 1.5s-.442 1.5-2.116 1.5M3.205 9.303c-.09.448-.277 1.21-1.241 1.203C1 10.5.5 9.513.5 8V7c0-1.57.5-2.5 1.464-2.494.964.006 1.134.598 1.24 1.342M12.553 10.5h1.953",strokeWidth:"1.2",stroke:"currentColor",fill:"none",strokeLinecap:"square"}))}var ve=n(9188),Ee=["translations"];function Se(){return Se=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},Se.apply(this,arguments)}function _e(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,a,o=[],i=!0,l=!1;try{for(n=n.call(e);!(i=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);i=!0);}catch(s){l=!0,a=s}finally{try{i||null==n.return||n.return()}finally{if(l)throw a}}return o}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return we(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return we(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function we(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function ke(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var Te="Ctrl";var xe=r.forwardRef((function(e,t){var n=e.translations,a=void 0===n?{}:n,o=ke(e,Ee),i=a.buttonText,l=void 0===i?"Search":i,s=a.buttonAriaLabel,u=void 0===s?"Search":s,c=_e((0,r.useState)(null),2),d=c[0],f=c[1];return(0,r.useEffect)((function(){"undefined"!=typeof navigator&&(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?f("\u2318"):f(Te))}),[]),r.createElement("button",Se({type:"button",className:"DocSearch DocSearch-Button","aria-label":u},o,{ref:t}),r.createElement("span",{className:"DocSearch-Button-Container"},r.createElement(ve.W,null),r.createElement("span",{className:"DocSearch-Button-Placeholder"},l)),r.createElement("span",{className:"DocSearch-Button-Keys"},null!==d&&r.createElement(r.Fragment,null,r.createElement(Ae,{reactsToKey:d===Te?Te:"Meta"},d===Te?r.createElement(be,null):d),r.createElement(Ae,{reactsToKey:"k"},"K"))))}));function Ae(e){var t=e.reactsToKey,n=e.children,a=_e((0,r.useState)(!1),2),o=a[0],i=a[1];return(0,r.useEffect)((function(){if(t)return window.addEventListener("keydown",e),window.addEventListener("keyup",n),function(){window.removeEventListener("keydown",e),window.removeEventListener("keyup",n)};function e(e){e.key===t&&i(!0)}function n(e){e.key!==t&&"Meta"!==e.key||i(!1)}}),[t]),r.createElement("kbd",{className:o?"DocSearch-Button-Key DocSearch-Button-Key--pressed":"DocSearch-Button-Key"},n)}var Ce=n(5260),Re=n(4255),Oe=n(1062),Ne=n(2967);const Ie={button:{buttonText:(0,s.T)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"}),buttonAriaLabel:(0,s.T)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"})},modal:{searchBox:{resetButtonTitle:(0,s.T)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),resetButtonAriaLabel:(0,s.T)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),cancelButtonText:(0,s.T)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"}),cancelButtonAriaLabel:(0,s.T)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"})},startScreen:{recentSearchesTitle:(0,s.T)({id:"theme.SearchModal.startScreen.recentSearchesTitle",message:"Recent",description:"The title for recent searches"}),noRecentSearchesText:(0,s.T)({id:"theme.SearchModal.startScreen.noRecentSearchesText",message:"No recent searches",description:"The text when no recent searches"}),saveRecentSearchButtonTitle:(0,s.T)({id:"theme.SearchModal.startScreen.saveRecentSearchButtonTitle",message:"Save this search",description:"The label for save recent search button"}),removeRecentSearchButtonTitle:(0,s.T)({id:"theme.SearchModal.startScreen.removeRecentSearchButtonTitle",message:"Remove this search from history",description:"The label for remove recent search button"}),favoriteSearchesTitle:(0,s.T)({id:"theme.SearchModal.startScreen.favoriteSearchesTitle",message:"Favorite",description:"The title for favorite searches"}),removeFavoriteSearchButtonTitle:(0,s.T)({id:"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle",message:"Remove this search from favorites",description:"The label for remove favorite search button"})},errorScreen:{titleText:(0,s.T)({id:"theme.SearchModal.errorScreen.titleText",message:"Unable to fetch results",description:"The title for error screen of search modal"}),helpText:(0,s.T)({id:"theme.SearchModal.errorScreen.helpText",message:"You might want to check your network connection.",description:"The help text for error screen of search modal"})},footer:{selectText:(0,s.T)({id:"theme.SearchModal.footer.selectText",message:"to select",description:"The explanatory text of the action for the enter key"}),selectKeyAriaLabel:(0,s.T)({id:"theme.SearchModal.footer.selectKeyAriaLabel",message:"Enter key",description:"The ARIA label for the Enter key button that makes the selection"}),navigateText:(0,s.T)({id:"theme.SearchModal.footer.navigateText",message:"to navigate",description:"The explanatory text of the action for the Arrow up and Arrow down key"}),navigateUpKeyAriaLabel:(0,s.T)({id:"theme.SearchModal.footer.navigateUpKeyAriaLabel",message:"Arrow up",description:"The ARIA label for the Arrow up key button that makes the navigation"}),navigateDownKeyAriaLabel:(0,s.T)({id:"theme.SearchModal.footer.navigateDownKeyAriaLabel",message:"Arrow down",description:"The ARIA label for the Arrow down key button that makes the navigation"}),closeText:(0,s.T)({id:"theme.SearchModal.footer.closeText",message:"to close",description:"The explanatory text of the action for Escape key"}),closeKeyAriaLabel:(0,s.T)({id:"theme.SearchModal.footer.closeKeyAriaLabel",message:"Escape key",description:"The ARIA label for the Escape key button that close the modal"}),searchByText:(0,s.T)({id:"theme.SearchModal.footer.searchByText",message:"Search by",description:"The text explain that the search is making by Algolia"})},noResultsScreen:{noResultsText:(0,s.T)({id:"theme.SearchModal.noResultsScreen.noResultsText",message:"No results for",description:"The text explains that there are no results for the following search"}),suggestedQueryText:(0,s.T)({id:"theme.SearchModal.noResultsScreen.suggestedQueryText",message:"Try searching for",description:"The text for the suggested query when no results are found for the following search"}),reportMissingResultsText:(0,s.T)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsText",message:"Believe this query should return results?",description:"The text for the question where the user thinks there are missing results"}),reportMissingResultsLinkText:(0,s.T)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText",message:"Let us know.",description:"The text for the link to report missing results"})}},placeholder:(0,s.T)({id:"theme.SearchModal.placeholder",message:"Search docs",description:"The placeholder of the input of the DocSearch pop-up modal"})};let Le=null;function Pe(e){let{hit:t,children:n}=e;return(0,c.jsx)(Q.A,{to:t.url,children:n})}function De(e){let{state:t,onClose:n}=e;const r=(0,Re.w)();return(0,c.jsx)(Q.A,{to:r(t.query),onClick:n,children:(0,c.jsx)(s.A,{id:"theme.SearchBar.seeAll",values:{count:t.context.nbHits},children:"See all {count} results"})})}function Me(e){let{contextualSearch:t,externalUrlRegex:a,...o}=e;const{siteMetadata:i}=(0,se.A)(),s=(0,Oe.C)(),u=function(){const{locale:e,tags:t}=(0,Ne.af)();return[`language:${e}`,t.map((e=>`docusaurus_tag:${e}`))]}(),d=o.searchParameters?.facetFilters??[],f=t?function(e,t){const n=e=>"string"==typeof e?[e]:e;return[...n(e),...n(t)]}(u,d):d,p={...o.searchParameters,facetFilters:f},m=(0,l.W6)(),h=(0,r.useRef)(null),g=(0,r.useRef)(null),[y,b]=(0,r.useState)(!1),[v,E]=(0,r.useState)(void 0),S=(0,r.useCallback)((()=>Le?Promise.resolve():Promise.all([n.e(462).then(n.bind(n,9462)),Promise.all([n.e(869),n.e(913)]).then(n.bind(n,8913)),Promise.all([n.e(869),n.e(416)]).then(n.bind(n,416))]).then((e=>{let[{DocSearchModal:t}]=e;Le=t}))),[]),_=(0,r.useCallback)((()=>{S().then((()=>{h.current=document.createElement("div"),document.body.insertBefore(h.current,document.body.firstChild),b(!0)}))}),[S,b]),w=(0,r.useCallback)((()=>{b(!1),h.current?.remove(),g.current?.focus()}),[b]),k=(0,r.useCallback)((e=>{S().then((()=>{b(!0),E(e.key)}))}),[S,b,E]),T=(0,r.useRef)({navigate(e){let{itemUrl:t}=e;(0,ee.G)(a,t)?window.location.href=t:m.push(t)}}).current,x=(0,r.useRef)((e=>o.transformItems?o.transformItems(e):e.map((e=>({...e,url:s(e.url)}))))).current,A=(0,r.useMemo)((()=>e=>(0,c.jsx)(De,{...e,onClose:w})),[w]),C=(0,r.useCallback)((e=>(e.addAlgoliaAgent("docusaurus",i.docusaurusVersion),e)),[i.docusaurusVersion]);return function(e){var t=e.isOpen,n=e.onOpen,a=e.onClose,o=e.onInput,i=e.searchButtonRef;r.useEffect((function(){function e(e){var r;(27===e.keyCode&&t||"k"===(null===(r=e.key)||void 0===r?void 0:r.toLowerCase())&&(e.metaKey||e.ctrlKey)||!function(e){var t=e.target,n=t.tagName;return t.isContentEditable||"INPUT"===n||"SELECT"===n||"TEXTAREA"===n}(e)&&"/"===e.key&&!t)&&(e.preventDefault(),t?a():document.body.classList.contains("DocSearch--active")||document.body.classList.contains("DocSearch--active")||n()),i&&i.current===document.activeElement&&o&&/[a-zA-Z0-9]/.test(String.fromCharCode(e.keyCode))&&o(e)}return window.addEventListener("keydown",e),function(){window.removeEventListener("keydown",e)}}),[t,n,a,o,i])}({isOpen:y,onOpen:_,onClose:w,onInput:k,searchButtonRef:g}),(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(Ce.A,{children:(0,c.jsx)("link",{rel:"preconnect",href:`https://${o.appId}-dsn.algolia.net`,crossOrigin:"anonymous"})}),(0,c.jsx)(xe,{onTouchStart:S,onFocus:S,onMouseOver:S,onClick:_,ref:g,translations:Ie.button}),y&&Le&&h.current&&(0,ye.createPortal)((0,c.jsx)(Le,{onClose:w,initialScrollY:window.scrollY,initialQuery:v,navigator:T,transformItems:x,hitComponent:Pe,transformSearchClient:C,...o.searchPagePath&&{resultsFooterComponent:A},...o,searchParameters:p,placeholder:Ie.placeholder,translations:Ie.modal}),h.current)]})}function je(){const{siteConfig:e}=(0,se.A)();return(0,c.jsx)(Me,{...e.themeConfig.algolia})}const Ue={navbarSearchContainer:"navbarSearchContainer_Bca1"};function Fe(e){let{children:t,className:n}=e;return(0,c.jsx)("div",{className:(0,a.A)(n,Ue.navbarSearchContainer),children:t})}var Be=n(4070),ze=n(4142);var $e=n(5597);const He=e=>e.docs.find((t=>t.id===e.mainDocId));const Ge={default:oe,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:r,queryString:a="",...o}=e;const{i18n:{currentLocale:i,locales:u,localeConfigs:d}}=(0,se.A)(),f=(0,me.o)(),{search:p,hash:m}=(0,l.zy)(),h=[...n,...u.map((e=>{const n=`${`pathname://${f.createUrl({locale:e,fullyQualified:!1})}`}${p}${m}${a}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...r],g=t?(0,s.T)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return(0,c.jsx)(pe,{...o,mobile:t,label:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(he,{className:ge}),g]}),items:h})},search:function(e){let{mobile:t,className:n}=e;return t?null:(0,c.jsx)(Fe,{className:n,children:(0,c.jsx)(je,{})})},dropdown:pe,html:function(e){let{value:t,className:n,mobile:r=!1,isDropdownItem:o=!1}=e;const i=o?"li":"div";return(0,c.jsx)(i,{className:(0,a.A)({navbar__item:!r&&!o,"menu__list-item":r},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:r,...a}=e;const{activeDoc:o}=(0,Be.zK)(r),i=(0,ze.QB)(t,r),l=o?.path===i?.path;return null===i||i.unlisted&&!l?null:(0,c.jsx)(oe,{exact:!0,...a,isActive:()=>l||!!o?.sidebar&&o.sidebar===i.sidebar,label:n??i.id,to:i.path})},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:r,...a}=e;const{activeDoc:o}=(0,Be.zK)(r),i=(0,ze.fW)(t,r).link;if(!i)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return(0,c.jsx)(oe,{exact:!0,...a,isActive:()=>o?.sidebar===t,label:n??i.label,to:i.path})},docsVersion:function(e){let{label:t,to:n,docsPluginId:r,...a}=e;const o=(0,ze.Vd)(r)[0],i=t??o.label,l=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(o).path;return(0,c.jsx)(oe,{...a,label:i,to:l})},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:r,dropdownItemsBefore:a,dropdownItemsAfter:o,...i}=e;const{search:u,hash:d}=(0,l.zy)(),f=(0,Be.zK)(n),p=(0,Be.jh)(n),{savePreferredVersionName:m}=(0,$e.g1)(n),h=[...a,...p.map((e=>{const t=f.alternateDocVersions[e.name]??He(e);return{label:e.label,to:`${t.path}${u}${d}`,isActive:()=>e===f.activeVersion,onClick:()=>m(e.name)}})),...o],g=(0,ze.Vd)(n)[0],y=t&&h.length>1?(0,s.T)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):g.label,b=t&&h.length>1?void 0:He(g).path;return h.length<=1?(0,c.jsx)(oe,{...i,mobile:t,label:y,to:b,isActive:r?()=>!1:void 0}):(0,c.jsx)(pe,{...i,mobile:t,label:y,to:b,items:h,isActive:r?()=>!1:void 0})}};function Ve(e){let{type:t,...n}=e;const r=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),a=Ge[r];if(!a)throw new Error(`No NavbarItem component found for type "${t}".`);return(0,c.jsx)(a,{...n})}function We(){const e=(0,R.M)(),t=(0,E.p)().navbar.items;return(0,c.jsx)("ul",{className:"menu__list",children:t.map(((t,n)=>(0,r.createElement)(Ve,{mobile:!0,...t,onClick:()=>e.toggle(),key:n})))})}function Ye(e){return(0,c.jsx)("button",{...e,type:"button",className:"clean-btn navbar-sidebar__back",children:(0,c.jsx)(s.A,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",children:"\u2190 Back to main menu"})})}function Ke(){const e=0===(0,E.p)().navbar.items.length,t=M();return(0,c.jsxs)(c.Fragment,{children:[!e&&(0,c.jsx)(Ye,{onClick:()=>t.hide()}),t.content]})}function qe(){const e=(0,R.M)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?(0,c.jsx)(j,{header:(0,c.jsx)(X,{}),primaryMenu:(0,c.jsx)(We,{}),secondaryMenu:(0,c.jsx)(Ke,{})}):null}const Xe={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Qe(e){return(0,c.jsx)("div",{role:"presentation",...e,className:(0,a.A)("navbar-sidebar__backdrop",e.className)})}function Ze(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:o}}=(0,E.p)(),i=(0,R.M)(),{navbarRef:l,isNavbarVisible:d}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),o=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return(0,O.Mq)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i<o.current)return void n(!0);if(a.current)return void(a.current=!1);const l=r?.scrollY,s=document.documentElement.scrollHeight-o.current,u=window.innerHeight;l&&i>=l?n(!1):i+u<s&&n(!0)})),(0,u.$)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return(0,c.jsxs)("nav",{ref:l,"aria-label":(0,s.T)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.A)("navbar","navbar--fixed-top",n&&[Xe.navbarHideable,!d&&Xe.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown}),children:[t,(0,c.jsx)(Qe,{onClick:i.toggle}),(0,c.jsx)(qe,{})]})}var Je=n(440);const et={errorBoundaryError:"errorBoundaryError_a6uf",errorBoundaryFallback:"errorBoundaryFallback_VBag"};function tt(e){return(0,c.jsx)("button",{type:"button",...e,children:(0,c.jsx)(s.A,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error",children:"Try again"})})}function nt(e){let{error:t}=e;const n=(0,Je.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return(0,c.jsx)("p",{className:et.errorBoundaryError,children:n})}class rt extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const at="right";function ot(e){let{width:t=30,height:n=30,className:r,...a}=e;return(0,c.jsx)("svg",{className:r,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true",...a,children:(0,c.jsx)("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"})})}function it(){const{toggle:e,shown:t}=(0,R.M)();return(0,c.jsx)("button",{onClick:e,"aria-label":(0,s.T)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button",children:(0,c.jsx)(ot,{})})}const lt={colorModeToggle:"colorModeToggle_DEke"};function st(e){let{items:t}=e;return(0,c.jsx)(c.Fragment,{children:t.map(((e,t)=>(0,c.jsx)(rt,{onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t}),children:(0,c.jsx)(Ve,{...e})},t)))})}function ut(e){let{left:t,right:n}=e;return(0,c.jsxs)("div",{className:"navbar__inner",children:[(0,c.jsx)("div",{className:"navbar__items",children:t}),(0,c.jsx)("div",{className:"navbar__items navbar__items--right",children:n})]})}function ct(){const e=(0,R.M)(),t=(0,E.p)().navbar.items,[n,r]=function(e){function t(e){return"left"===(e.position??at)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),a=t.find((e=>"search"===e.type));return(0,c.jsx)(ut,{left:(0,c.jsxs)(c.Fragment,{children:[!e.disabled&&(0,c.jsx)(it,{}),(0,c.jsx)(K,{}),(0,c.jsx)(st,{items:n})]}),right:(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(st,{items:r}),(0,c.jsx)(W,{className:lt.colorModeToggle}),!a&&(0,c.jsx)(Fe,{children:(0,c.jsx)(je,{})})]})})}function dt(){return(0,c.jsx)(Ze,{children:(0,c.jsx)(ct,{})})}function ft(e){let{item:t}=e;const{to:n,href:r,label:a,prependBaseUrlToHref:o,...i}=t,l=(0,Z.A)(n),s=(0,Z.A)(r,{forcePrependBaseUrl:!0});return(0,c.jsxs)(Q.A,{className:"footer__link-item",...r?{href:o?s:r}:{to:l},...i,children:[a,r&&!(0,J.A)(r)&&(0,c.jsx)(te.A,{})]})}function pt(e){let{item:t}=e;return t.html?(0,c.jsx)("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):(0,c.jsx)("li",{className:"footer__item",children:(0,c.jsx)(ft,{item:t})},t.href??t.to)}function mt(e){let{column:t}=e;return(0,c.jsxs)("div",{className:"col footer__col",children:[(0,c.jsx)("div",{className:"footer__title",children:t.title}),(0,c.jsx)("ul",{className:"footer__items clean-list",children:t.items.map(((e,t)=>(0,c.jsx)(pt,{item:e},t)))})]})}function ht(e){let{columns:t}=e;return(0,c.jsx)("div",{className:"row footer__links",children:t.map(((e,t)=>(0,c.jsx)(mt,{column:e},t)))})}function gt(){return(0,c.jsx)("span",{className:"footer__link-separator",children:"\xb7"})}function yt(e){let{item:t}=e;return t.html?(0,c.jsx)("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):(0,c.jsx)(ft,{item:t})}function bt(e){let{links:t}=e;return(0,c.jsx)("div",{className:"footer__links text--center",children:(0,c.jsx)("div",{className:"footer__links",children:t.map(((e,n)=>(0,c.jsxs)(r.Fragment,{children:[(0,c.jsx)(yt,{item:e}),t.length!==n+1&&(0,c.jsx)(gt,{})]},n)))})})}function vt(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?(0,c.jsx)(ht,{columns:t}):(0,c.jsx)(bt,{links:t})}var Et=n(1122);const St={footerLogoLink:"footerLogoLink_BH7S"};function _t(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Z.h)(),r={light:n(t.src),dark:n(t.srcDark??t.src)};return(0,c.jsx)(Et.A,{className:(0,a.A)("footer__logo",t.className),alt:t.alt,sources:r,width:t.width,height:t.height,style:t.style})}function wt(e){let{logo:t}=e;return t.href?(0,c.jsx)(Q.A,{href:t.href,className:St.footerLogoLink,target:t.target,children:(0,c.jsx)(_t,{logo:t})}):(0,c.jsx)(_t,{logo:t})}function kt(e){let{copyright:t}=e;return(0,c.jsx)("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function Tt(e){let{style:t,links:n,logo:r,copyright:o}=e;return(0,c.jsx)("footer",{className:(0,a.A)("footer",{"footer--dark":"dark"===t}),children:(0,c.jsxs)("div",{className:"container container-fluid",children:[n,(r||o)&&(0,c.jsxs)("div",{className:"footer__bottom text--center",children:[r&&(0,c.jsx)("div",{className:"margin-bottom--sm",children:r}),o]})]})})}function xt(){const{footer:e}=(0,E.p)();if(!e)return null;const{copyright:t,links:n,logo:r,style:a}=e;return(0,c.jsx)(Tt,{style:a,links:n&&n.length>0&&(0,c.jsx)(vt,{links:n}),logo:r&&(0,c.jsx)(wt,{logo:r}),copyright:t&&(0,c.jsx)(kt,{copyright:t})})}const At=r.memo(xt),Ct=(0,N.fM)([U.a,S.oq,O.Tv,$e.VQ,i.Jx,function(e){let{children:t}=e;return(0,c.jsx)(I.y_,{children:(0,c.jsx)(R.e,{children:(0,c.jsx)(P,{children:t})})})}]);function Rt(e){let{children:t}=e;return(0,c.jsx)(Ct,{children:t})}var Ot=n(1107);function Nt(e){let{error:t,tryAgain:n}=e;return(0,c.jsx)("main",{className:"container margin-vert--xl",children:(0,c.jsx)("div",{className:"row",children:(0,c.jsxs)("div",{className:"col col--6 col--offset-3",children:[(0,c.jsx)(Ot.A,{as:"h1",className:"hero__title",children:(0,c.jsx)(s.A,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed",children:"This page crashed."})}),(0,c.jsx)("div",{className:"margin-vert--lg",children:(0,c.jsx)(tt,{onClick:n,className:"button button--primary shadow--lw"})}),(0,c.jsx)("hr",{}),(0,c.jsx)("div",{className:"margin-vert--md",children:(0,c.jsx)(nt,{error:t})})]})})})}const It={mainWrapper:"mainWrapper_z2l0"};function Lt(e){const{children:t,noFooter:n,wrapperClassName:r,title:l,description:s}=e;return(0,y.J)(),(0,c.jsxs)(Rt,{children:[(0,c.jsx)(i.be,{title:l,description:s}),(0,c.jsx)(v,{}),(0,c.jsx)(C,{}),(0,c.jsx)(dt,{}),(0,c.jsx)("div",{id:d,className:(0,a.A)(g.G.wrapper.main,It.mainWrapper,r),children:(0,c.jsx)(o.A,{fallback:e=>(0,c.jsx)(Nt,{...e}),children:t})}),!n&&(0,c.jsx)(At,{})]})}},3465:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});n(6540);var r=n(8774),a=n(6025),o=n(4586),i=n(6342),l=n(1122),s=n(4848);function u(e){let{logo:t,alt:n,imageClassName:r}=e;const o={light:(0,a.A)(t.src),dark:(0,a.A)(t.srcDark||t.src)},i=(0,s.jsx)(l.A,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?(0,s.jsx)("div",{className:r,children:i}):i}function c(e){const{siteConfig:{title:t}}=(0,o.A)(),{navbar:{title:n,logo:l}}=(0,i.p)(),{imageClassName:c,titleClassName:d,...f}=e,p=(0,a.A)(l?.href||"/"),m=n?"":t,h=l?.alt??m;return(0,s.jsxs)(r.A,{to:p,...f,...l?.target&&{target:l.target},children:[l&&(0,s.jsx)(u,{logo:l,alt:h,imageClassName:c}),null!=n&&(0,s.jsx)("b",{className:d,children:n})]})}},1463:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});n(6540);var r=n(5260),a=n(4848);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return(0,a.jsxs)(r.A,{children:[t&&(0,a.jsx)("meta",{name:"docusaurus_locale",content:t}),n&&(0,a.jsx)("meta",{name:"docusaurus_version",content:n}),o&&(0,a.jsx)("meta",{name:"docusaurus_tag",content:o}),i&&(0,a.jsx)("meta",{name:"docsearch:language",content:i}),n&&(0,a.jsx)("meta",{name:"docsearch:version",content:n}),o&&(0,a.jsx)("meta",{name:"docsearch:docusaurus_tag",content:o})]})}},1122:(e,t,n)=>{"use strict";n.d(t,{A:()=>c});var r=n(6540),a=n(4164),o=n(2303),i=n(5293);const l={themedComponent:"themedComponent_mlkZ","themedComponent--light":"themedComponent--light_NVdE","themedComponent--dark":"themedComponent--dark_xIcU"};var s=n(4848);function u(e){let{className:t,children:n}=e;const u=(0,o.A)(),{colorMode:c}=(0,i.G)();return(0,s.jsx)(s.Fragment,{children:(u?"dark"===c?["dark"]:["light"]:["light","dark"]).map((e=>{const o=n({theme:e,className:(0,a.A)(t,l.themedComponent,l[`themedComponent--${e}`])});return(0,s.jsx)(r.Fragment,{children:o},e)}))})}function c(e){const{sources:t,className:n,alt:r,...a}=e;return(0,s.jsx)(u,{className:n,children:e=>{let{theme:n,className:o}=e;return(0,s.jsx)("img",{src:t[n],alt:r,className:o,...a})}})}},1422:(e,t,n)=>{"use strict";n.d(t,{N:()=>y,u:()=>u});var r=n(6540),a=n(8193),o=n(205),i=n(3109),l=n(4848);const s="ease-in-out";function u(e){let{initialState:t}=e;const[n,a]=(0,r.useState)(t??!1),o=(0,r.useCallback)((()=>{a((e=>!e))}),[]);return{collapsed:n,setCollapsed:a,toggleCollapsed:o}}const c={display:"none",overflow:"hidden",height:"0px"},d={display:"block",overflow:"visible",height:"auto"};function f(e,t){const n=t?c:d;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function p(e){let{collapsibleRef:t,collapsed:n,animation:a}=e;const o=(0,r.useRef)(!1);(0,r.useEffect)((()=>{const e=t.current;function r(){const t=e.scrollHeight,n=a?.duration??function(e){if((0,i.O)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${a?.easing??s}`,height:`${t}px`}}function l(){const t=r();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return f(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(l(),requestAnimationFrame((()=>{e.style.height=c.height,e.style.overflow=c.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{l()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,a])}function m(e){if(!a.A.canUseDOM)return e?c:d}function h(e){let{as:t="div",collapsed:n,children:a,animation:o,onCollapseTransitionEnd:i,className:s,disableSSRStyle:u}=e;const c=(0,r.useRef)(null);return p({collapsibleRef:c,collapsed:n,animation:o}),(0,l.jsx)(t,{ref:c,style:u?void 0:m(n),onTransitionEnd:e=>{"height"===e.propertyName&&(f(c.current,n),i?.(n))},className:s,children:a})}function g(e){let{collapsed:t,...n}=e;const[a,i]=(0,r.useState)(!t),[s,u]=(0,r.useState)(t);return(0,o.A)((()=>{t||i(!0)}),[t]),(0,o.A)((()=>{a&&u(t)}),[a,t]),a?(0,l.jsx)(h,{...n,collapsed:s}):null}function y(e){let{lazy:t,...n}=e;const r=t?g:h;return(0,l.jsx)(r,{...n})}},5041:(e,t,n)=>{"use strict";n.d(t,{Mj:()=>h,oq:()=>m});var r=n(6540),a=n(2303),o=n(9466),i=n(9532),l=n(6342),s=n(4848);const u=(0,o.Wf)("docusaurus.announcement.dismiss"),c=(0,o.Wf)("docusaurus.announcement.id"),d=()=>"true"===u.get(),f=e=>u.set(String(e)),p=r.createContext(null);function m(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.p)(),t=(0,a.A)(),[n,o]=(0,r.useState)((()=>!!t&&d()));(0,r.useEffect)((()=>{o(d())}),[]);const i=(0,r.useCallback)((()=>{f(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=c.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;c.set(t),r&&f(!1),!r&&d()||o(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return(0,s.jsx)(p.Provider,{value:n,children:t})}function h(){const e=(0,r.useContext)(p);if(!e)throw new i.dV("AnnouncementBarProvider");return e}},5293:(e,t,n)=>{"use strict";n.d(t,{G:()=>y,a:()=>g});var r=n(6540),a=n(8193),o=n(9532),i=n(9466),l=n(6342),s=n(4848);const u=r.createContext(void 0),c="theme",d=(0,i.Wf)(c),f={light:"light",dark:"dark"},p=e=>e===f.dark?f.dark:f.light,m=e=>a.A.canUseDOM?p(document.documentElement.getAttribute("data-theme")):p(e),h=e=>{d.set(p(e))};function g(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.p)(),[a,o]=(0,r.useState)(m(e));(0,r.useEffect)((()=>{t&&d.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&h(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?f.dark:f.light:e),d.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",p(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==c)return;const t=d.get();null!==t&&i(p(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===f.dark},setLightTheme(){i(f.light)},setDarkTheme(){i(f.dark)}})),[a,i])}();return(0,s.jsx)(u.Provider,{value:n,children:t})}function y(){const e=(0,r.useContext)(u);if(null==e)throw new o.dV("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},5597:(e,t,n)=>{"use strict";n.d(t,{VQ:()=>y,XK:()=>E,g1:()=>v});var r=n(6540),a=n(4070),o=n(7065),i=n(6342),l=n(4142),s=n(9532),u=n(9466),c=n(4848);const d=e=>`docs-preferred-version-${e}`,f={save:(e,t,n)=>{(0,u.Wf)(d(e),{persistence:t}).set(n)},read:(e,t)=>(0,u.Wf)(d(e),{persistence:t}).get(),clear:(e,t)=>{(0,u.Wf)(d(e),{persistence:t}).del()}},p=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const m=r.createContext(null);function h(){const e=(0,a.Gy)(),t=(0,i.p)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[o,l]=(0,r.useState)((()=>p(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=f.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(f.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){f.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function g(e){let{children:t}=e;const n=h();return(0,c.jsx)(m.Provider,{value:n,children:t})}function y(e){let{children:t}=e;return l.C5?(0,c.jsx)(g,{children:t}):(0,c.jsx)(c.Fragment,{children:t})}function b(){const e=(0,r.useContext)(m);if(!e)throw new s.dV("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=o.W);const t=(0,a.ht)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}function E(){const e=(0,a.Gy)(),[t]=b();function n(n){const r=e[n],{preferredVersionName:a}=t[n];return r.versions.find((e=>e.name===a))??null}const r=Object.keys(e);return Object.fromEntries(r.map((e=>[e,n(e)])))}},6588:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,t:()=>u});var r=n(6540),a=n(9532),o=n(4848);const i=Symbol("EmptyContext"),l=r.createContext(i);function s(e){let{children:t,name:n,items:a}=e;const i=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return(0,o.jsx)(l.Provider,{value:i,children:t})}function u(){const e=(0,r.useContext)(l);if(e===i)throw new a.dV("DocsSidebarProvider");return e}},2252:(e,t,n)=>{"use strict";n.d(t,{n:()=>l,r:()=>s});var r=n(6540),a=n(9532),o=n(4848);const i=r.createContext(null);function l(e){let{children:t,version:n}=e;return(0,o.jsx)(i.Provider,{value:n,children:t})}function s(){const e=(0,r.useContext)(i);if(null===e)throw new a.dV("DocsVersionProvider");return e}},2069:(e,t,n)=>{"use strict";n.d(t,{M:()=>p,e:()=>f});var r=n(6540),a=n(5600),o=n(4581),i=n(7485),l=n(6342),s=n(9532),u=n(4848);const c=r.createContext(void 0);function d(){const e=function(){const e=(0,a.YL)(),{items:t}=(0,l.p)().navbar;return 0===t.length&&!e.component}(),t=(0,o.l)(),n=!e&&"mobile"===t,[s,u]=(0,r.useState)(!1);(0,i.$Z)((()=>{if(s)return u(!1),!1}));const c=(0,r.useCallback)((()=>{u((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&u(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:c,shown:s})),[e,n,c,s])}function f(e){let{children:t}=e;const n=d();return(0,u.jsx)(c.Provider,{value:n,children:t})}function p(){const e=r.useContext(c);if(void 0===e)throw new s.dV("NavbarMobileSidebarProvider");return e}},5600:(e,t,n)=>{"use strict";n.d(t,{GX:()=>u,YL:()=>s,y_:()=>l});var r=n(6540),a=n(9532),o=n(4848);const i=r.createContext(null);function l(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return(0,o.jsx)(i.Provider,{value:n,children:t})}function s(){const e=(0,r.useContext)(i);if(!e)throw new a.dV("NavbarSecondaryMenuContentProvider");return e[0]}function u(e){let{component:t,props:n}=e;const o=(0,r.useContext)(i);if(!o)throw new a.dV("NavbarSecondaryMenuContentProvider");const[,l]=o,s=(0,a.Be)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},4090:(e,t,n)=>{"use strict";n.d(t,{w:()=>a,J:()=>o});var r=n(6540);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},4255:(e,t,n)=>{"use strict";n.d(t,{b:()=>l,w:()=>s});var r=n(6540),a=n(4586),o=n(7485);const i="q";function l(){return(0,o.l)(i)}function s(){const{siteConfig:{baseUrl:e,themeConfig:t}}=(0,a.A)(),{algolia:{searchPagePath:n}}=t;return(0,r.useCallback)((t=>`${e}${n}?${i}=${encodeURIComponent(t)}`),[e,n])}},4581:(e,t,n)=>{"use strict";n.d(t,{l:()=>l});var r=n(6540),a=n(8193);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(e){let{desktopBreakpoint:t=i}=void 0===e?{}:e;const[n,l]=(0,r.useState)((()=>"ssr"));return(0,r.useEffect)((()=>{function e(){l(function(e){if(!a.A.canUseDOM)throw new Error("getWindowSize() should only be called after React hydration");return window.innerWidth>e?o.desktop:o.mobile}(t))}return e(),window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e)}}),[t]),n}},7559:(e,t,n)=>{"use strict";n.d(t,{G:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",unlistedBanner:"theme-unlisted-banner",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{blogFooterTagsRow:"theme-blog-footer-tags-row",blogFooterEditMetaRow:"theme-blog-footer-edit-meta-row"},pages:{pageFooterEditMetaRow:"theme-pages-footer-edit-meta-row"}}},3109:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{O:()=>r})},4142:(e,t,n)=>{"use strict";n.d(t,{B5:()=>k,C5:()=>f,Nr:()=>p,OF:()=>E,QB:()=>w,Vd:()=>S,Y:()=>b,fW:()=>_,w8:()=>g});var r=n(6540),a=n(6347),o=n(2831),i=n(4070),l=n(5597),s=n(2252),u=n(6588),c=n(1682),d=n(9169);const f=!!i.Gy;function p(e){return"link"!==e.type||e.unlisted?"category"===e.type?function(e){if(e.href&&!e.linkUnlisted)return e.href;for(const t of e.items){const e=p(t);if(e)return e}}(e):void 0:e.href}const m=(e,t)=>void 0!==e&&(0,d.ys)(e,t),h=(e,t)=>e.some((e=>g(e,t)));function g(e,t){return"link"===e.type?m(e.href,t):"category"===e.type&&(m(e.href,t)||h(e.items,t))}function y(e,t){switch(e.type){case"category":return g(e,t)||e.items.some((e=>y(e,t)));case"link":return!e.unlisted||g(e,t);default:return!0}}function b(e,t){return(0,r.useMemo)((()=>e.filter((e=>y(e,t)))),[e,t])}function v(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const o of t)if("category"===o.type&&((0,d.ys)(o.href,n)||e(o.items))||"link"===o.type&&(0,d.ys)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function E(){const e=(0,u.t)(),{pathname:t}=(0,a.zy)(),n=(0,i.vT)()?.pluginData.breadcrumbs;return!1!==n&&e?v({sidebarItems:e.items,pathname:t}):null}function S(e){const{activeVersion:t}=(0,i.zK)(e),{preferredVersion:n}=(0,l.g1)(e),a=(0,i.r7)(e);return(0,r.useMemo)((()=>(0,c.s)([t,n,a].filter(Boolean))),[t,n,a])}function _(e,t){const n=S(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function w(e,t){const n=S(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${(0,c.s)(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function k(e){let{route:t}=e;const n=(0,a.zy)(),r=(0,s.r)(),i=t.routes,l=i.find((e=>(0,a.B6)(n.pathname,e)));if(!l)return null;const u=l.sidebar,c=u?r.docsSidebars[u]:void 0;return{docElement:(0,o.v)(i),sidebarName:u,sidebarItems:c}}},481:(e,t,n)=>{"use strict";n.d(t,{s:()=>a});var r=n(4586);function a(e){const{siteConfig:t}=(0,r.A)(),{title:n,titleDelimiter:a}=t;return e?.trim().length?`${e.trim()} ${a} ${n}`:n}},7485:(e,t,n)=>{"use strict";n.d(t,{$Z:()=>i,aZ:()=>s,l:()=>u});var r=n(6540),a=n(6347),o=n(9532);function i(e){!function(e){const t=(0,a.W6)(),n=(0,o._q)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}function l(e){const t=(0,a.W6)();return(0,r.useSyncExternalStore)(t.listen,(()=>e(t)),(()=>e(t)))}function s(e){return l((t=>null===e?null:new URLSearchParams(t.location.search).get(e)))}function u(e){const t=s(e)??"",n=function(e){const t=(0,a.W6)();return(0,r.useCallback)(((n,r)=>{const a=new URLSearchParams(t.location.search);n?a.set(e,n):a.delete(e),(r?.push?t.push:t.replace)({search:a.toString()})}),[e,t])}(e);return[t,n]}},1682:(e,t,n)=>{"use strict";function r(e,t){return void 0===t&&(t=(e,t)=>e===t),e.filter(((n,r)=>e.findIndex((e=>t(e,n)))!==r))}function a(e){return Array.from(new Set(e))}n.d(t,{X:()=>r,s:()=>a})},9024:(e,t,n)=>{"use strict";n.d(t,{e3:()=>p,be:()=>d,Jx:()=>m});var r=n(6540),a=n(4164),o=n(5260),i=n(3102);function l(){const e=r.useContext(i.o);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(6025),u=n(481),c=n(4848);function d(e){let{title:t,description:n,keywords:r,image:a,children:i}=e;const l=(0,u.s)(t),{withBaseUrl:d}=(0,s.h)(),f=a?d(a,{absolute:!0}):void 0;return(0,c.jsxs)(o.A,{children:[t&&(0,c.jsx)("title",{children:l}),t&&(0,c.jsx)("meta",{property:"og:title",content:l}),n&&(0,c.jsx)("meta",{name:"description",content:n}),n&&(0,c.jsx)("meta",{property:"og:description",content:n}),r&&(0,c.jsx)("meta",{name:"keywords",content:Array.isArray(r)?r.join(","):r}),f&&(0,c.jsx)("meta",{property:"og:image",content:f}),f&&(0,c.jsx)("meta",{name:"twitter:image",content:f}),i]})}const f=r.createContext(void 0);function p(e){let{className:t,children:n}=e;const i=r.useContext(f),l=(0,a.A)(i,t);return(0,c.jsxs)(f.Provider,{value:l,children:[(0,c.jsx)(o.A,{children:(0,c.jsx)("html",{className:l})}),n]})}function m(e){let{children:t}=e;const n=l(),r=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const o=`plugin-id-${n.plugin.id}`;return(0,c.jsx)(p,{className:(0,a.A)(r,o),children:t})}},9532:(e,t,n)=>{"use strict";n.d(t,{Be:()=>u,ZC:()=>l,_q:()=>i,dV:()=>s,fM:()=>c});var r=n(6540),a=n(205),o=n(4848);function i(e){const t=(0,r.useRef)(e);return(0,a.A)((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function l(e){const t=(0,r.useRef)();return(0,a.A)((()=>{t.current=e})),t.current}class s extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function u(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function c(e){return t=>{let{children:n}=t;return(0,o.jsx)(o.Fragment,{children:e.reduceRight(((e,t)=>(0,o.jsx)(t,{children:e})),n)})}}},1252:(e,t,n)=>{"use strict";function r(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}n.d(t,{G:()=>r})},9169:(e,t,n)=>{"use strict";n.d(t,{Dt:()=>l,ys:()=>i});var r=n(6540),a=n(8328),o=n(4586);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,o.A)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.A,baseUrl:e})),[e])}},3104:(e,t,n)=>{"use strict";n.d(t,{Mq:()=>p,Tv:()=>c,a_:()=>m,gk:()=>h});var r=n(6540),a=n(8193),o=n(2303),i=n(205),l=n(9532),s=n(4848);const u=r.createContext(void 0);function c(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return(0,s.jsx)(u.Provider,{value:n,children:t})}function d(){const e=(0,r.useContext)(u);if(null==e)throw new l.dV("ScrollControllerProvider");return e}const f=()=>a.A.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function p(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=d(),a=(0,r.useRef)(f()),o=(0,l._q)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=f();o(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}function m(){const e=d(),t=function(){const e=(0,r.useRef)({elem:null,top:0}),t=(0,r.useCallback)((t=>{e.current={elem:t,top:t.getBoundingClientRect().top}}),[]),n=(0,r.useCallback)((()=>{const{current:{elem:t,top:n}}=e;if(!t)return{restored:!1};const r=t.getBoundingClientRect().top-n;return r&&window.scrollBy({left:0,top:r}),e.current={elem:null,top:0},{restored:0!==r}}),[]);return(0,r.useMemo)((()=>({save:t,restore:n})),[n,t])}(),n=(0,r.useRef)(void 0),a=(0,r.useCallback)((r=>{t.save(r),e.disableScrollEvents(),n.current=()=>{const{restored:r}=t.restore();if(n.current=void 0,r){const t=()=>{e.enableScrollEvents(),window.removeEventListener("scroll",t)};window.addEventListener("scroll",t)}else e.enableScrollEvents()}}),[e,t]);return(0,i.A)((()=>{queueMicrotask((()=>n.current?.()))})),{blockElementScrollPositionUntilNextRender:a}}function h(){const e=(0,r.useRef)(null),t=(0,o.A)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},2967:(e,t,n)=>{"use strict";n.d(t,{Cy:()=>i,af:()=>s,tU:()=>l});var r=n(4070),a=n(4586),o=n(5597);const i="default";function l(e,t){return`docs-${e}-${t}`}function s(){const{i18n:e}=(0,a.A)(),t=(0,r.Gy)(),n=(0,r.gk)(),s=(0,o.XK)();const u=[i,...Object.keys(t).map((function(e){const r=n?.activePlugin.pluginId===e?n.activeVersion:void 0,a=s[e],o=t[e].versions.find((e=>e.isLast));return l(e,(r??a??o).name)}))];return{locale:e.currentLocale,tags:u}}},9466:(e,t,n)=>{"use strict";n.d(t,{Dv:()=>c,Eo:()=>d,Wf:()=>u});var r=n(6540);const a="localStorage";function o(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function i(e){if(void 0===e&&(e=a),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,l||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),l=!0),null}var t}let l=!1;const s={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function u(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=i(t?.persistence);return null===n?s:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),o({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),o({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}function c(e,t){const n=(0,r.useRef)((()=>null===e?s:u(e,t))).current(),a=(0,r.useCallback)((e=>"undefined"==typeof window?()=>{}:n.listen(e)),[n]);return[(0,r.useSyncExternalStore)(a,(()=>"undefined"==typeof window?null:n.get()),(()=>null)),n]}function d(e){void 0===e&&(e=a);const t=i(e);if(!t)return[];const n=[];for(let r=0;r<t.length;r+=1){const e=t.key(r);null!==e&&n.push(e)}return n}},2131:(e,t,n)=>{"use strict";n.d(t,{o:()=>i});var r=n(4586),a=n(6347),o=n(440);function i(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:i,currentLocale:l}}=(0,r.A)(),{pathname:s}=(0,a.zy)(),u=(0,o.applyTrailingSlash)(s,{trailingSlash:n,baseUrl:e}),c=l===i?e:e.replace(`/${l}/`,"/"),d=u.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:r}=e;return`${r?t:""}${function(e){return e===i?`${c}`:`${c}${e}/`}(n)}${d}`}}}},5062:(e,t,n)=>{"use strict";n.d(t,{$:()=>i});var r=n(6540),a=n(6347),o=n(9532);function i(e){const t=(0,a.zy)(),n=(0,o.ZC)(t),i=(0,o._q)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6342:(e,t,n)=>{"use strict";n.d(t,{p:()=>a});var r=n(4586);function a(){return(0,r.A)().siteConfig.themeConfig}},8126:(e,t,n)=>{"use strict";n.d(t,{c:()=>a});var r=n(4586);function a(){const{siteConfig:{themeConfig:e}}=(0,r.A)();return e}},1062:(e,t,n)=>{"use strict";n.d(t,{C:()=>l});var r=n(6540),a=n(1252),o=n(6025),i=n(8126);function l(){const{withBaseUrl:e}=(0,o.h)(),{algolia:{externalUrlRegex:t,replaceSearchResultPathname:n}}=(0,i.c)();return(0,r.useCallback)((r=>{const o=new URL(r);if((0,a.G)(t,o.href))return r;const i=`${o.pathname+o.hash}`;return e(function(e,t){return t?e.replaceAll(new RegExp(t.from,"g"),t.to):e}(i,n))}),[e,t,n])}},2983:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.removeTrailingSlash=t.addLeadingSlash=t.addTrailingSlash=void 0;const r=n(2566);function a(e){return e.endsWith("/")?e:`${e}/`}function o(e){return(0,r.removeSuffix)(e,"/")}t.addTrailingSlash=a,t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[i]=e.split(/[#?]/),l="/"===i||i===r?i:(s=i,n?a(s):o(s));var s;return e.replace(i,l)},t.addLeadingSlash=function(e){return(0,r.addPrefix)(e,"/")},t.removeTrailingSlash=o},253:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},440:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.removePrefix=t.addSuffix=t.removeSuffix=t.addPrefix=t.removeTrailingSlash=t.addLeadingSlash=t.addTrailingSlash=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var a=n(2983);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}}),Object.defineProperty(t,"addTrailingSlash",{enumerable:!0,get:function(){return a.addTrailingSlash}}),Object.defineProperty(t,"addLeadingSlash",{enumerable:!0,get:function(){return a.addLeadingSlash}}),Object.defineProperty(t,"removeTrailingSlash",{enumerable:!0,get:function(){return a.removeTrailingSlash}});var o=n(2566);Object.defineProperty(t,"addPrefix",{enumerable:!0,get:function(){return o.addPrefix}}),Object.defineProperty(t,"removeSuffix",{enumerable:!0,get:function(){return o.removeSuffix}}),Object.defineProperty(t,"addSuffix",{enumerable:!0,get:function(){return o.addSuffix}}),Object.defineProperty(t,"removePrefix",{enumerable:!0,get:function(){return o.removePrefix}});var i=n(253);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return i.getErrorCausalChain}})},2566:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.removePrefix=t.addSuffix=t.removeSuffix=t.addPrefix=void 0,t.addPrefix=function(e,t){return e.startsWith(t)?e:`${t}${e}`},t.removeSuffix=function(e,t){return""===t?e:e.endsWith(t)?e.slice(0,-t.length):e},t.addSuffix=function(e,t){return e.endsWith(t)?e:`${e}${t}`},t.removePrefix=function(e,t){return e.startsWith(t)?e.slice(t.length):e}},6094:()=>{Prism.languages.qmake={comment:/#.*/,variable:/(?:(?:^|\s)[a-z_A-Z]\w+(?=\s*(?:=|\+=|-=|\*=|~=))\b|\${2}[a-z_A-Z]\w+\b(?!\()|\${2}{[a-z_A-Z]\w+}|\b(?:QT|TEMPLATE|CONFIG|DEFINES|SOURCES|HEADERS|INCLUDEPATH|LIBS|QMAKE_CXXFLAGS)\b)/,boolean:/\b(?:true|false)\b/,operator:/(=|\+=|-=|\*=|~=)/,number:/\b\d+(?:\.\d+)*\b/,function:/(?:\b[a-z_]\w*(?=\s*\()\b|\${2}[a-z_]\w+(?=\s*\()\b)/i}},1838:(e,t,n)=>{"use strict";n.d(t,{A:()=>a});const r=(0,n(6540).createContext)(void 0);r.displayName="RootFolderContext";const a=r},1513:(e,t,n)=>{"use strict";n.d(t,{zR:()=>E,TM:()=>x,yJ:()=>p,sC:()=>C,AO:()=>f});var r=n(8168);function a(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,r=n+1,a=e.length;r<a;n+=1,r+=1)e[n]=e[r];e.pop()}const i=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],i=t&&t.split("/")||[],l=e&&a(e),s=t&&a(t),u=l||s;if(e&&a(e)?i=r:r.length&&(i.pop(),i=i.concat(r)),!i.length)return"/";if(i.length){var c=i[i.length-1];n="."===c||".."===c||""===c}else n=!1;for(var d=0,f=i.length;f>=0;f--){var p=i[f];"."===p?o(i,f):".."===p?(o(i,f),d++):d&&(o(i,f),d--)}if(!u)for(;d--;d)i.unshift("..");!u||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(1561);function s(e){return"/"===e.charAt(0)?e:"/"+e}function u(e){return"/"===e.charAt(0)?e.substr(1):e}function c(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function p(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.A)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var h=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var y="popstate",b="hashchange";function v(){try{return window.history.state||{}}catch(e){return{}}}function E(e){void 0===e&&(e={}),h||(0,l.A)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,o=!(-1===window.navigator.userAgent.indexOf("Trident")),i=e,u=i.forceRefresh,E=void 0!==u&&u,S=i.getUserConfirmation,_=void 0===S?g:S,w=i.keyLength,k=void 0===w?6:w,T=e.basename?d(s(e.basename)):"";function x(e){var t=e||{},n=t.key,r=t.state,a=window.location,o=a.pathname+a.search+a.hash;return T&&(o=c(o,T)),p(o,r,n)}function A(){return Math.random().toString(36).substr(2,k)}var C=m();function R(e){(0,r.A)(z,e),z.length=n.length,C.notifyListeners(z.location,z.action)}function O(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||L(x(e.state))}function N(){L(x(v()))}var I=!1;function L(e){if(I)I=!1,R();else{C.confirmTransitionTo(e,"POP",_,(function(t){t?R({action:"POP",location:e}):function(e){var t=z.location,n=D.indexOf(t.key);-1===n&&(n=0);var r=D.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(I=!0,j(a))}(e)}))}}var P=x(v()),D=[P.key];function M(e){return T+f(e)}function j(e){n.go(e)}var U=0;function F(e){1===(U+=e)&&1===e?(window.addEventListener(y,O),o&&window.addEventListener(b,N)):0===U&&(window.removeEventListener(y,O),o&&window.removeEventListener(b,N))}var B=!1;var z={length:n.length,action:"POP",location:P,createHref:M,push:function(e,t){var r="PUSH",o=p(e,t,A(),z.location);C.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.pushState({key:i,state:l},null,t),E)window.location.href=t;else{var s=D.indexOf(z.location.key),u=D.slice(0,s+1);u.push(o.key),D=u,R({action:r,location:o})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",o=p(e,t,A(),z.location);C.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.replaceState({key:i,state:l},null,t),E)window.location.replace(t);else{var s=D.indexOf(z.location.key);-1!==s&&(D[s]=o.key),R({action:r,location:o})}else window.location.replace(t)}}))},go:j,goBack:function(){j(-1)},goForward:function(){j(1)},block:function(e){void 0===e&&(e=!1);var t=C.setPrompt(e);return B||(F(1),B=!0),function(){return B&&(B=!1,F(-1)),t()}},listen:function(e){var t=C.appendListener(e);return F(1),function(){F(-1),t()}}};return z}var S="hashchange",_={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+u(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:u,decodePath:s},slash:{encodePath:s,decodePath:s}};function w(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function k(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function T(e){window.location.replace(w(window.location.href)+"#"+e)}function x(e){void 0===e&&(e={}),h||(0,l.A)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,o=void 0===a?g:a,i=n.hashType,u=void 0===i?"slash":i,y=e.basename?d(s(e.basename)):"",b=_[u],v=b.encodePath,E=b.decodePath;function x(){var e=E(k());return y&&(e=c(e,y)),p(e)}var A=m();function C(e){(0,r.A)(B,e),B.length=t.length,A.notifyListeners(B.location,B.action)}var R=!1,O=null;function N(){var e,t,n=k(),r=v(n);if(n!==r)T(r);else{var a=x(),i=B.location;if(!R&&(t=a,(e=i).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(O===f(a))return;O=null,function(e){if(R)R=!1,C();else{var t="POP";A.confirmTransitionTo(e,t,o,(function(n){n?C({action:t,location:e}):function(e){var t=B.location,n=D.lastIndexOf(f(t));-1===n&&(n=0);var r=D.lastIndexOf(f(e));-1===r&&(r=0);var a=n-r;a&&(R=!0,M(a))}(e)}))}}(a)}}var I=k(),L=v(I);I!==L&&T(L);var P=x(),D=[f(P)];function M(e){t.go(e)}var j=0;function U(e){1===(j+=e)&&1===e?window.addEventListener(S,N):0===j&&window.removeEventListener(S,N)}var F=!1;var B={length:t.length,action:"POP",location:P,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=w(window.location.href)),n+"#"+v(y+f(e))},push:function(e,t){var n="PUSH",r=p(e,void 0,void 0,B.location);A.confirmTransitionTo(r,n,o,(function(e){if(e){var t=f(r),a=v(y+t);if(k()!==a){O=t,function(e){window.location.hash=e}(a);var o=D.lastIndexOf(f(B.location)),i=D.slice(0,o+1);i.push(t),D=i,C({action:n,location:r})}else C()}}))},replace:function(e,t){var n="REPLACE",r=p(e,void 0,void 0,B.location);A.confirmTransitionTo(r,n,o,(function(e){if(e){var t=f(r),a=v(y+t);k()!==a&&(O=t,T(a));var o=D.indexOf(f(B.location));-1!==o&&(D[o]=t),C({action:n,location:r})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=A.setPrompt(e);return F||(U(1),F=!0),function(){return F&&(F=!1,U(-1)),t()}},listen:function(e){var t=A.appendListener(e);return U(1),function(){U(-1),t()}}};return B}function A(e,t,n){return Math.min(Math.max(e,t),n)}function C(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,o=void 0===a?["/"]:a,i=t.initialIndex,l=void 0===i?0:i,s=t.keyLength,u=void 0===s?6:s,c=m();function d(e){(0,r.A)(E,e),E.length=E.entries.length,c.notifyListeners(E.location,E.action)}function h(){return Math.random().toString(36).substr(2,u)}var g=A(l,0,o.length-1),y=o.map((function(e){return p(e,void 0,"string"==typeof e?h():e.key||h())})),b=f;function v(e){var t=A(E.index+e,0,E.entries.length-1),r=E.entries[t];c.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var E={length:y.length,action:"POP",location:y[g],index:g,entries:y,createHref:b,push:function(e,t){var r="PUSH",a=p(e,t,h(),E.location);c.confirmTransitionTo(a,r,n,(function(e){if(e){var t=E.index+1,n=E.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=p(e,t,h(),E.location);c.confirmTransitionTo(a,r,n,(function(e){e&&(E.entries[E.index]=a,d({action:r,location:a}))}))},go:v,goBack:function(){v(-1)},goForward:function(){v(1)},canGo:function(e){var t=E.index+e;return t>=0&&t<E.entries.length},block:function(e){return void 0===e&&(e=!1),c.setPrompt(e)},listen:function(e){return c.appendListener(e)}};return E}},4146:(e,t,n)=>{"use strict";var r=n(4363),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var u=Object.defineProperty,c=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=p(n);a&&a!==m&&e(t,a,r)}var i=c(n);d&&(i=i.concat(d(n)));for(var l=s(t),h=s(n),g=0;g<i.length;++g){var y=i[g];if(!(o[y]||r&&r[y]||h&&h[y]||l&&l[y])){var b=f(n,y);try{u(t,y,b)}catch(v){}}}}return t}},311:e=>{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,a,o,i,l],c=0;(s=new Error(t.replace(/%s/g,(function(){return u[c++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},4634:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},119:(e,t,n)=>{"use strict";n.r(t)},1043:(e,t,n)=>{"use strict";n.r(t)},5947:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),u=o.querySelector(r.barSelector),c=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,i(e,c,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+c+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),c)}),c)):setTimeout(t,c)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),u=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&p(a),u!=document.body&&c(u,"nprogress-custom-parent"),u.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function u(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=f(e),r=n+t;u(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);u(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},5302:(e,t,n)=>{var r=n(4634);e.exports=p,e.exports.parse=o,e.exports.compile=function(e,t){return l(o(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=f;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,r=[],o=0,i=0,l="",c=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],f=n[1],p=n.index;if(l+=e.slice(i,p),i=p+d.length,f)l+=f[1];else{var m=e[i],h=n[2],g=n[3],y=n[4],b=n[5],v=n[6],E=n[7];l&&(r.push(l),l="");var S=null!=h&&null!=m&&m!==h,_="+"===v||"*"===v,w="?"===v||"*"===v,k=n[2]||c,T=y||b;r.push({name:g||o++,prefix:h||"",delimiter:k,optional:w,repeat:_,partial:S,asterisk:!!E,pattern:T?u(T):E?".*":"[^"+s(k)+"]+?"})}}return i<e.length&&(l+=e.substr(i)),l&&r.push(l),r}function i(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function l(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var o="",l=t||{},s=(a||{}).pretty?i:encodeURIComponent,u=0;u<e.length;u++){var c=e[u];if("string"!=typeof c){var d,f=l[c.name];if(null==f){if(c.optional){c.partial&&(o+=c.prefix);continue}throw new TypeError('Expected "'+c.name+'" to be defined')}if(r(f)){if(!c.repeat)throw new TypeError('Expected "'+c.name+'" to not repeat, but received `'+JSON.stringify(f)+"`");if(0===f.length){if(c.optional)continue;throw new TypeError('Expected "'+c.name+'" to not be empty')}for(var p=0;p<f.length;p++){if(d=s(f[p]),!n[u].test(d))throw new TypeError('Expected all "'+c.name+'" to match "'+c.pattern+'", but received `'+JSON.stringify(d)+"`");o+=(0===p?c.prefix:c.delimiter)+d}}else{if(d=c.asterisk?encodeURI(f).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):s(f),!n[u].test(d))throw new TypeError('Expected "'+c.name+'" to match "'+c.pattern+'", but received "'+d+'"');o+=c.prefix+d}}else o+=c}return o}}function s(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function u(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function c(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function f(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,o=!1!==n.end,i="",l=0;l<e.length;l++){var u=e[l];if("string"==typeof u)i+=s(u);else{var f=s(u.prefix),p="(?:"+u.pattern+")";t.push(u),u.repeat&&(p+="(?:"+f+p+")*"),i+=p=u.optional?u.partial?f+"("+p+")?":"(?:"+f+"("+p+"))?":f+"("+p+")"}}var m=s(n.delimiter||"/"),h=i.slice(-m.length)===m;return a||(i=(h?i.slice(0,-m.length):i)+"(?:"+m+"(?=$))?"),i+=o?"$":a&&h?"":"(?="+m+"|$)",c(new RegExp("^"+i,d(n)),t)}function p(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return c(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(p(e[a],t,n).source);return c(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return f(o(e,n),t,n)}(e,t,n)}},7022:()=>{!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i<a.length;i++)o[a[i]]=e.languages.bash[a[i]];e.languages.sh=e.languages.bash,e.languages.shell=e.languages.bash}(Prism)},2509:()=>{Prism.languages.cmake={comment:/#.*/,string:{pattern:/"(?:[^\\"]|\\.)*"/,greedy:!0,inside:{interpolation:{pattern:/\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/,inside:{punctuation:/\$\{|\}/,variable:/\w+/}}}},variable:/\b(?:CMAKE_\w+|\w+_(?:(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT|VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_NAME|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE))\b/,property:/\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/,keyword:/\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/,boolean:/\b(?:FALSE|OFF|ON|TRUE)\b/,namespace:/\b(?:INTERFACE|PRIVATE|PROPERTIES|PUBLIC|SHARED|STATIC|TARGET_OBJECTS)\b/,operator:/\b(?:AND|DEFINED|EQUAL|GREATER|LESS|MATCHES|NOT|OR|STREQUAL|STRGREATER|STRLESS|VERSION_EQUAL|VERSION_GREATER|VERSION_LESS)\b/,inserted:{pattern:/\b\w+::\w+\b/,alias:"class-name"},number:/\b\d+(?:\.\d+)*\b/,function:/\b[a-z_]\w*(?=\s*\()\b/i,punctuation:/[()>}]|\$[<{]/}},9700:()=>{!function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s<l.length&&!(a>=o.length);s++){var u=l[s];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=o[a],d=n.tokenStack[c],f="string"==typeof u?u:u.content,p=t(r,c),m=f.indexOf(p);if(m>-1){++a;var h=f.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),y=f.substring(m+p.length),b=[];h&&b.push.apply(b,i([h])),b.push(g),y&&b.push.apply(b,i([y])),"string"==typeof u?l.splice.apply(l,[s,1].concat(b)):u.content=b}}else u.content&&i(u.content)}return l}(n.tokens)}}}})}(Prism)},905:()=>{!function(e){var t=e.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};t.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:t},boolean:t.boolean,variable:t.variable}}(Prism)},652:(e,t,n)=>{var r={"./prism-bash":7022,"./prism-cmake":2509,"./prism-powershell":905};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=652},2694:(e,t,n)=>{"use strict";var r=n(6925);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5556:(e,t,n)=>{e.exports=n(2694)()},6925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},2551:(e,t,n)=>{"use strict";var r=n(6540),a=n(9982);function o(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var i=new Set,l={};function s(e,t){u(e,t),u(e+"Capture",t)}function u(e,t){for(l[e]=t,e=0;e<t.length;e++)i.add(t[e])}var c=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),d=Object.prototype.hasOwnProperty,f=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,p={},m={};function h(e,t,n,r,a,o,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var g={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){g[e]=new h(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];g[t]=new h(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){g[e]=new h(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){g[e]=new h(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){g[e]=new h(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){g[e]=new h(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){g[e]=new h(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){g[e]=new h(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){g[e]=new h(e,5,!1,e.toLowerCase(),null,!1,!1)}));var y=/[\-:]([a-z])/g;function b(e){return e[1].toUpperCase()}function v(e,t,n,r){var a=g.hasOwnProperty(t)?g[t]:null;(null!==a?0!==a.type:r||!(2<t.length)||"o"!==t[0]&&"O"!==t[0]||"n"!==t[1]&&"N"!==t[1])&&(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!d.call(m,e)||!d.call(p,e)&&(f.test(e)?m[e]=!0:(p[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(y,b);g[t]=new h(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(y,b);g[t]=new h(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(y,b);g[t]=new h(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){g[e]=new h(e,1,!1,e.toLowerCase(),null,!1,!1)})),g.xlinkHref=new h("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){g[e]=new h(e,1,!1,e.toLowerCase(),null,!0,!0)}));var E=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,S=Symbol.for("react.element"),_=Symbol.for("react.portal"),w=Symbol.for("react.fragment"),k=Symbol.for("react.strict_mode"),T=Symbol.for("react.profiler"),x=Symbol.for("react.provider"),A=Symbol.for("react.context"),C=Symbol.for("react.forward_ref"),R=Symbol.for("react.suspense"),O=Symbol.for("react.suspense_list"),N=Symbol.for("react.memo"),I=Symbol.for("react.lazy");Symbol.for("react.scope"),Symbol.for("react.debug_trace_mode");var L=Symbol.for("react.offscreen");Symbol.for("react.legacy_hidden"),Symbol.for("react.cache"),Symbol.for("react.tracing_marker");var P=Symbol.iterator;function D(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=P&&e[P]||e["@@iterator"])?e:null}var M,j=Object.assign;function U(e){if(void 0===M)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);M=t&&t[1]||""}return"\n"+M+e}var F=!1;function B(e,t){if(!e||F)return"";F=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(u){var r=u}Reflect.construct(e,[],t)}else{try{t.call()}catch(u){r=u}e.call(t.prototype)}else{try{throw Error()}catch(u){r=u}e()}}catch(u){if(u&&r&&"string"==typeof u.stack){for(var a=u.stack.split("\n"),o=r.stack.split("\n"),i=a.length-1,l=o.length-1;1<=i&&0<=l&&a[i]!==o[l];)l--;for(;1<=i&&0<=l;i--,l--)if(a[i]!==o[l]){if(1!==i||1!==l)do{if(i--,0>--l||a[i]!==o[l]){var s="\n"+a[i].replace(" at new "," at ");return e.displayName&&s.includes("<anonymous>")&&(s=s.replace("<anonymous>",e.displayName)),s}}while(1<=i&&0<=l);break}}}finally{F=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?U(e):""}function z(e){switch(e.tag){case 5:return U(e.type);case 16:return U("Lazy");case 13:return U("Suspense");case 19:return U("SuspenseList");case 0:case 2:case 15:return e=B(e.type,!1);case 11:return e=B(e.type.render,!1);case 1:return e=B(e.type,!0);default:return""}}function $(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case w:return"Fragment";case _:return"Portal";case T:return"Profiler";case k:return"StrictMode";case R:return"Suspense";case O:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case A:return(e.displayName||"Context")+".Consumer";case x:return(e._context.displayName||"Context")+".Provider";case C:var t=e.render;return(e=e.displayName)||(e=""!==(e=t.displayName||t.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case N:return null!==(t=e.displayName||null)?t:$(e.type)||"Memo";case I:t=e._payload,e=e._init;try{return $(e(t))}catch(n){}}return null}function H(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=(e=t.render).displayName||e.name||"",t.displayName||(""!==e?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return $(t);case 8:return t===k?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if("function"==typeof t)return t.displayName||t.name||null;if("string"==typeof t)return t}return null}function G(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":case"object":return e;default:return""}}function V(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function W(e){e._valueTracker||(e._valueTracker=function(e){var t=V(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,o.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function Y(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=V(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function K(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function q(e,t){var n=t.checked;return j({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function X(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=G(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function Q(e,t){null!=(t=t.checked)&&v(e,"checked",t,!1)}function Z(e,t){Q(e,t);var n=G(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?ee(e,t.type,n):t.hasOwnProperty("defaultValue")&&ee(e,t.type,G(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function J(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ee(e,t,n){"number"===t&&K(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var te=Array.isArray;function ne(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+G(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function re(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(o(91));return j({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function ae(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(o(92));if(te(n)){if(1<n.length)throw Error(o(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:G(n)}}function oe(e,t){var n=G(t.value),r=G(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function ie(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}function le(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function se(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?le(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var ue,ce,de=(ce=function(e,t){if("http://www.w3.org/2000/svg"!==e.namespaceURI||"innerHTML"in e)e.innerHTML=t;else{for((ue=ue||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=ue.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return ce(e,t)}))}:ce);function fe(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var pe={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},me=["Webkit","ms","Moz","O"];function he(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||pe.hasOwnProperty(e)&&pe[e]?(""+t).trim():t+"px"}function ge(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=he(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(pe).forEach((function(e){me.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),pe[t]=pe[e]}))}));var ye=j({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function be(e,t){if(t){if(ye[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(o(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(o(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(o(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(o(62))}}function ve(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Ee=null;function Se(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var _e=null,we=null,ke=null;function Te(e){if(e=va(e)){if("function"!=typeof _e)throw Error(o(280));var t=e.stateNode;t&&(t=Sa(t),_e(e.stateNode,e.type,t))}}function xe(e){we?ke?ke.push(e):ke=[e]:we=e}function Ae(){if(we){var e=we,t=ke;if(ke=we=null,Te(e),t)for(e=0;e<t.length;e++)Te(t[e])}}function Ce(e,t){return e(t)}function Re(){}var Oe=!1;function Ne(e,t,n){if(Oe)return e(t,n);Oe=!0;try{return Ce(e,t,n)}finally{Oe=!1,(null!==we||null!==ke)&&(Re(),Ae())}}function Ie(e,t){var n=e.stateNode;if(null===n)return null;var r=Sa(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(o(231,t,typeof n));return n}var Le=!1;if(c)try{var Pe={};Object.defineProperty(Pe,"passive",{get:function(){Le=!0}}),window.addEventListener("test",Pe,Pe),window.removeEventListener("test",Pe,Pe)}catch(ce){Le=!1}function De(e,t,n,r,a,o,i,l,s){var u=Array.prototype.slice.call(arguments,3);try{t.apply(n,u)}catch(c){this.onError(c)}}var Me=!1,je=null,Ue=!1,Fe=null,Be={onError:function(e){Me=!0,je=e}};function ze(e,t,n,r,a,o,i,l,s){Me=!1,je=null,De.apply(Be,arguments)}function $e(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{!!(4098&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function He(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function Ge(e){if($e(e)!==e)throw Error(o(188))}function Ve(e){return null!==(e=function(e){var t=e.alternate;if(!t){if(null===(t=$e(e)))throw Error(o(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var i=a.alternate;if(null===i){if(null!==(r=a.return)){n=r;continue}break}if(a.child===i.child){for(i=a.child;i;){if(i===n)return Ge(a),e;if(i===r)return Ge(a),t;i=i.sibling}throw Error(o(188))}if(n.return!==r.return)n=a,r=i;else{for(var l=!1,s=a.child;s;){if(s===n){l=!0,n=a,r=i;break}if(s===r){l=!0,r=a,n=i;break}s=s.sibling}if(!l){for(s=i.child;s;){if(s===n){l=!0,n=i,r=a;break}if(s===r){l=!0,r=i,n=a;break}s=s.sibling}if(!l)throw Error(o(189))}}if(n.alternate!==r)throw Error(o(190))}if(3!==n.tag)throw Error(o(188));return n.stateNode.current===n?e:t}(e))?We(e):null}function We(e){if(5===e.tag||6===e.tag)return e;for(e=e.child;null!==e;){var t=We(e);if(null!==t)return t;e=e.sibling}return null}var Ye=a.unstable_scheduleCallback,Ke=a.unstable_cancelCallback,qe=a.unstable_shouldYield,Xe=a.unstable_requestPaint,Qe=a.unstable_now,Ze=a.unstable_getCurrentPriorityLevel,Je=a.unstable_ImmediatePriority,et=a.unstable_UserBlockingPriority,tt=a.unstable_NormalPriority,nt=a.unstable_LowPriority,rt=a.unstable_IdlePriority,at=null,ot=null;var it=Math.clz32?Math.clz32:function(e){return e>>>=0,0===e?32:31-(lt(e)/st|0)|0},lt=Math.log,st=Math.LN2;var ut=64,ct=4194304;function dt(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return 4194240&e;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return 130023424&e;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function ft(e,t){var n=e.pendingLanes;if(0===n)return 0;var r=0,a=e.suspendedLanes,o=e.pingedLanes,i=268435455&n;if(0!==i){var l=i&~a;0!==l?r=dt(l):0!==(o&=i)&&(r=dt(o))}else 0!==(i=n&~a)?r=dt(i):0!==o&&(r=dt(o));if(0===r)return 0;if(0!==t&&t!==r&&!(t&a)&&((a=r&-r)>=(o=t&-t)||16===a&&4194240&o))return t;if(4&r&&(r|=16&n),0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)a=1<<(n=31-it(t)),r|=e[n],t&=~a;return r}function pt(e,t){switch(e){case 1:case 2:case 4:return t+250;case 8:case 16:case 32:case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;default:return-1}}function mt(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function ht(){var e=ut;return!(4194240&(ut<<=1))&&(ut=64),e}function gt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function yt(e,t,n){e.pendingLanes|=t,536870912!==t&&(e.suspendedLanes=0,e.pingedLanes=0),(e=e.eventTimes)[t=31-it(t)]=n}function bt(e,t){var n=e.entangledLanes|=t;for(e=e.entanglements;n;){var r=31-it(n),a=1<<r;a&t|e[r]&t&&(e[r]|=t),n&=~a}}var vt=0;function Et(e){return 1<(e&=-e)?4<e?268435455&e?16:536870912:4:1}var St,_t,wt,kt,Tt,xt=!1,At=[],Ct=null,Rt=null,Ot=null,Nt=new Map,It=new Map,Lt=[],Pt="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function Dt(e,t){switch(e){case"focusin":case"focusout":Ct=null;break;case"dragenter":case"dragleave":Rt=null;break;case"mouseover":case"mouseout":Ot=null;break;case"pointerover":case"pointerout":Nt.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":It.delete(t.pointerId)}}function Mt(e,t,n,r,a,o){return null===e||e.nativeEvent!==o?(e={blockedOn:t,domEventName:n,eventSystemFlags:r,nativeEvent:o,targetContainers:[a]},null!==t&&(null!==(t=va(t))&&_t(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==a&&-1===t.indexOf(a)&&t.push(a),e)}function jt(e){var t=ba(e.target);if(null!==t){var n=$e(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=He(n)))return e.blockedOn=t,void Tt(e.priority,(function(){wt(n)}))}else if(3===t&&n.stateNode.current.memoizedState.isDehydrated)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function Ut(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=qt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=va(n))&&_t(t),e.blockedOn=n,!1;var r=new(n=e.nativeEvent).constructor(n.type,n);Ee=r,n.target.dispatchEvent(r),Ee=null,t.shift()}return!0}function Ft(e,t,n){Ut(e)&&n.delete(t)}function Bt(){xt=!1,null!==Ct&&Ut(Ct)&&(Ct=null),null!==Rt&&Ut(Rt)&&(Rt=null),null!==Ot&&Ut(Ot)&&(Ot=null),Nt.forEach(Ft),It.forEach(Ft)}function zt(e,t){e.blockedOn===t&&(e.blockedOn=null,xt||(xt=!0,a.unstable_scheduleCallback(a.unstable_NormalPriority,Bt)))}function $t(e){function t(t){return zt(t,e)}if(0<At.length){zt(At[0],e);for(var n=1;n<At.length;n++){var r=At[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==Ct&&zt(Ct,e),null!==Rt&&zt(Rt,e),null!==Ot&&zt(Ot,e),Nt.forEach(t),It.forEach(t),n=0;n<Lt.length;n++)(r=Lt[n]).blockedOn===e&&(r.blockedOn=null);for(;0<Lt.length&&null===(n=Lt[0]).blockedOn;)jt(n),null===n.blockedOn&&Lt.shift()}var Ht=E.ReactCurrentBatchConfig,Gt=!0;function Vt(e,t,n,r){var a=vt,o=Ht.transition;Ht.transition=null;try{vt=1,Yt(e,t,n,r)}finally{vt=a,Ht.transition=o}}function Wt(e,t,n,r){var a=vt,o=Ht.transition;Ht.transition=null;try{vt=4,Yt(e,t,n,r)}finally{vt=a,Ht.transition=o}}function Yt(e,t,n,r){if(Gt){var a=qt(e,t,n,r);if(null===a)Gr(e,t,r,Kt,n),Dt(e,r);else if(function(e,t,n,r,a){switch(t){case"focusin":return Ct=Mt(Ct,e,t,n,r,a),!0;case"dragenter":return Rt=Mt(Rt,e,t,n,r,a),!0;case"mouseover":return Ot=Mt(Ot,e,t,n,r,a),!0;case"pointerover":var o=a.pointerId;return Nt.set(o,Mt(Nt.get(o)||null,e,t,n,r,a)),!0;case"gotpointercapture":return o=a.pointerId,It.set(o,Mt(It.get(o)||null,e,t,n,r,a)),!0}return!1}(a,e,t,n,r))r.stopPropagation();else if(Dt(e,r),4&t&&-1<Pt.indexOf(e)){for(;null!==a;){var o=va(a);if(null!==o&&St(o),null===(o=qt(e,t,n,r))&&Gr(e,t,r,Kt,n),o===a)break;a=o}null!==a&&r.stopPropagation()}else Gr(e,t,r,null,n)}}var Kt=null;function qt(e,t,n,r){if(Kt=null,null!==(e=ba(e=Se(r))))if(null===(t=$e(e)))e=null;else if(13===(n=t.tag)){if(null!==(e=He(t)))return e;e=null}else if(3===n){if(t.stateNode.current.memoizedState.isDehydrated)return 3===t.tag?t.stateNode.containerInfo:null;e=null}else t!==e&&(e=null);return Kt=e,null}function Xt(e){switch(e){case"cancel":case"click":case"close":case"contextmenu":case"copy":case"cut":case"auxclick":case"dblclick":case"dragend":case"dragstart":case"drop":case"focusin":case"focusout":case"input":case"invalid":case"keydown":case"keypress":case"keyup":case"mousedown":case"mouseup":case"paste":case"pause":case"play":case"pointercancel":case"pointerdown":case"pointerup":case"ratechange":case"reset":case"resize":case"seeked":case"submit":case"touchcancel":case"touchend":case"touchstart":case"volumechange":case"change":case"selectionchange":case"textInput":case"compositionstart":case"compositionend":case"compositionupdate":case"beforeblur":case"afterblur":case"beforeinput":case"blur":case"fullscreenchange":case"focus":case"hashchange":case"popstate":case"select":case"selectstart":return 1;case"drag":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"mousemove":case"mouseout":case"mouseover":case"pointermove":case"pointerout":case"pointerover":case"scroll":case"toggle":case"touchmove":case"wheel":case"mouseenter":case"mouseleave":case"pointerenter":case"pointerleave":return 4;case"message":switch(Ze()){case Je:return 1;case et:return 4;case tt:case nt:return 16;case rt:return 536870912;default:return 16}default:return 16}}var Qt=null,Zt=null,Jt=null;function en(){if(Jt)return Jt;var e,t,n=Zt,r=n.length,a="value"in Qt?Qt.value:Qt.textContent,o=a.length;for(e=0;e<r&&n[e]===a[e];e++);var i=r-e;for(t=1;t<=i&&n[r-t]===a[o-t];t++);return Jt=a.slice(e,1<t?1-t:void 0)}function tn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function nn(){return!0}function rn(){return!1}function an(e){function t(t,n,r,a,o){for(var i in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=a,this.target=o,this.currentTarget=null,e)e.hasOwnProperty(i)&&(t=e[i],this[i]=t?t(a):a[i]);return this.isDefaultPrevented=(null!=a.defaultPrevented?a.defaultPrevented:!1===a.returnValue)?nn:rn,this.isPropagationStopped=rn,this}return j(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=nn)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=nn)},persist:function(){},isPersistent:nn}),t}var on,ln,sn,un={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},cn=an(un),dn=j({},un,{view:0,detail:0}),fn=an(dn),pn=j({},dn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Tn,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==sn&&(sn&&"mousemove"===e.type?(on=e.screenX-sn.screenX,ln=e.screenY-sn.screenY):ln=on=0,sn=e),on)},movementY:function(e){return"movementY"in e?e.movementY:ln}}),mn=an(pn),hn=an(j({},pn,{dataTransfer:0})),gn=an(j({},dn,{relatedTarget:0})),yn=an(j({},un,{animationName:0,elapsedTime:0,pseudoElement:0})),bn=j({},un,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),vn=an(bn),En=an(j({},un,{data:0})),Sn={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},_n={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},wn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function kn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=wn[e])&&!!t[e]}function Tn(){return kn}var xn=j({},dn,{key:function(e){if(e.key){var t=Sn[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=tn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?_n[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:Tn,charCode:function(e){return"keypress"===e.type?tn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?tn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),An=an(xn),Cn=an(j({},pn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Rn=an(j({},dn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:Tn})),On=an(j({},un,{propertyName:0,elapsedTime:0,pseudoElement:0})),Nn=j({},pn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),In=an(Nn),Ln=[9,13,27,32],Pn=c&&"CompositionEvent"in window,Dn=null;c&&"documentMode"in document&&(Dn=document.documentMode);var Mn=c&&"TextEvent"in window&&!Dn,jn=c&&(!Pn||Dn&&8<Dn&&11>=Dn),Un=String.fromCharCode(32),Fn=!1;function Bn(e,t){switch(e){case"keyup":return-1!==Ln.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function zn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var $n=!1;var Hn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Gn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Hn[e.type]:"textarea"===t}function Vn(e,t,n,r){xe(r),0<(t=Wr(t,"onChange")).length&&(n=new cn("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Wn=null,Yn=null;function Kn(e){Ur(e,0)}function qn(e){if(Y(Ea(e)))return e}function Xn(e,t){if("change"===e)return t}var Qn=!1;if(c){var Zn;if(c){var Jn="oninput"in document;if(!Jn){var er=document.createElement("div");er.setAttribute("oninput","return;"),Jn="function"==typeof er.oninput}Zn=Jn}else Zn=!1;Qn=Zn&&(!document.documentMode||9<document.documentMode)}function tr(){Wn&&(Wn.detachEvent("onpropertychange",nr),Yn=Wn=null)}function nr(e){if("value"===e.propertyName&&qn(Yn)){var t=[];Vn(t,Yn,e,Se(e)),Ne(Kn,t)}}function rr(e,t,n){"focusin"===e?(tr(),Yn=n,(Wn=t).attachEvent("onpropertychange",nr)):"focusout"===e&&tr()}function ar(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return qn(Yn)}function or(e,t){if("click"===e)return qn(t)}function ir(e,t){if("input"===e||"change"===e)return qn(t)}var lr="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t};function sr(e,t){if(lr(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++){var a=n[r];if(!d.call(t,a)||!lr(e[a],t[a]))return!1}return!0}function ur(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function cr(e,t){var n,r=ur(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=ur(r)}}function dr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?dr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function fr(){for(var e=window,t=K();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=K((e=t.contentWindow).document)}return t}function pr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}function mr(e){var t=fr(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&dr(n.ownerDocument.documentElement,n)){if(null!==r&&pr(n))if(t=r.start,void 0===(e=r.end)&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if((e=(t=n.ownerDocument||document)&&t.defaultView||window).getSelection){e=e.getSelection();var a=n.textContent.length,o=Math.min(r.start,a);r=void 0===r.end?o:Math.min(r.end,a),!e.extend&&o>r&&(a=r,r=o,o=a),a=cr(n,o);var i=cr(n,r);a&&i&&(1!==e.rangeCount||e.anchorNode!==a.node||e.anchorOffset!==a.offset||e.focusNode!==i.node||e.focusOffset!==i.offset)&&((t=t.createRange()).setStart(a.node,a.offset),e.removeAllRanges(),o>r?(e.addRange(t),e.extend(i.node,i.offset)):(t.setEnd(i.node,i.offset),e.addRange(t)))}for(t=[],e=n;e=e.parentNode;)1===e.nodeType&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for("function"==typeof n.focus&&n.focus(),n=0;n<t.length;n++)(e=t[n]).element.scrollLeft=e.left,e.element.scrollTop=e.top}}var hr=c&&"documentMode"in document&&11>=document.documentMode,gr=null,yr=null,br=null,vr=!1;function Er(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;vr||null==gr||gr!==K(r)||("selectionStart"in(r=gr)&&pr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},br&&sr(br,r)||(br=r,0<(r=Wr(yr,"onSelect")).length&&(t=new cn("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=gr)))}function Sr(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var _r={animationend:Sr("Animation","AnimationEnd"),animationiteration:Sr("Animation","AnimationIteration"),animationstart:Sr("Animation","AnimationStart"),transitionend:Sr("Transition","TransitionEnd")},wr={},kr={};function Tr(e){if(wr[e])return wr[e];if(!_r[e])return e;var t,n=_r[e];for(t in n)if(n.hasOwnProperty(t)&&t in kr)return wr[e]=n[t];return e}c&&(kr=document.createElement("div").style,"AnimationEvent"in window||(delete _r.animationend.animation,delete _r.animationiteration.animation,delete _r.animationstart.animation),"TransitionEvent"in window||delete _r.transitionend.transition);var xr=Tr("animationend"),Ar=Tr("animationiteration"),Cr=Tr("animationstart"),Rr=Tr("transitionend"),Or=new Map,Nr="abort auxClick cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");function Ir(e,t){Or.set(e,t),s(t,[e])}for(var Lr=0;Lr<Nr.length;Lr++){var Pr=Nr[Lr];Ir(Pr.toLowerCase(),"on"+(Pr[0].toUpperCase()+Pr.slice(1)))}Ir(xr,"onAnimationEnd"),Ir(Ar,"onAnimationIteration"),Ir(Cr,"onAnimationStart"),Ir("dblclick","onDoubleClick"),Ir("focusin","onFocus"),Ir("focusout","onBlur"),Ir(Rr,"onTransitionEnd"),u("onMouseEnter",["mouseout","mouseover"]),u("onMouseLeave",["mouseout","mouseover"]),u("onPointerEnter",["pointerout","pointerover"]),u("onPointerLeave",["pointerout","pointerover"]),s("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),s("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),s("onBeforeInput",["compositionend","keypress","textInput","paste"]),s("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),s("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),s("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var Dr="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Mr=new Set("cancel close invalid load scroll toggle".split(" ").concat(Dr));function jr(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,a,i,l,s,u){if(ze.apply(this,arguments),Me){if(!Me)throw Error(o(198));var c=je;Me=!1,je=null,Ue||(Ue=!0,Fe=c)}}(r,t,void 0,e),e.currentTarget=null}function Ur(e,t){t=!!(4&t);for(var n=0;n<e.length;n++){var r=e[n],a=r.event;r=r.listeners;e:{var o=void 0;if(t)for(var i=r.length-1;0<=i;i--){var l=r[i],s=l.instance,u=l.currentTarget;if(l=l.listener,s!==o&&a.isPropagationStopped())break e;jr(a,l,u),o=s}else for(i=0;i<r.length;i++){if(s=(l=r[i]).instance,u=l.currentTarget,l=l.listener,s!==o&&a.isPropagationStopped())break e;jr(a,l,u),o=s}}}if(Ue)throw e=Fe,Ue=!1,Fe=null,e}function Fr(e,t){var n=t[ha];void 0===n&&(n=t[ha]=new Set);var r=e+"__bubble";n.has(r)||(Hr(t,e,2,!1),n.add(r))}function Br(e,t,n){var r=0;t&&(r|=4),Hr(n,e,r,t)}var zr="_reactListening"+Math.random().toString(36).slice(2);function $r(e){if(!e[zr]){e[zr]=!0,i.forEach((function(t){"selectionchange"!==t&&(Mr.has(t)||Br(t,!1,e),Br(t,!0,e))}));var t=9===e.nodeType?e:e.ownerDocument;null===t||t[zr]||(t[zr]=!0,Br("selectionchange",!1,t))}}function Hr(e,t,n,r){switch(Xt(t)){case 1:var a=Vt;break;case 4:a=Wt;break;default:a=Yt}n=a.bind(null,t,n,e),a=void 0,!Le||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(a=!0),r?void 0!==a?e.addEventListener(t,n,{capture:!0,passive:a}):e.addEventListener(t,n,!0):void 0!==a?e.addEventListener(t,n,{passive:a}):e.addEventListener(t,n,!1)}function Gr(e,t,n,r,a){var o=r;if(!(1&t||2&t||null===r))e:for(;;){if(null===r)return;var i=r.tag;if(3===i||4===i){var l=r.stateNode.containerInfo;if(l===a||8===l.nodeType&&l.parentNode===a)break;if(4===i)for(i=r.return;null!==i;){var s=i.tag;if((3===s||4===s)&&((s=i.stateNode.containerInfo)===a||8===s.nodeType&&s.parentNode===a))return;i=i.return}for(;null!==l;){if(null===(i=ba(l)))return;if(5===(s=i.tag)||6===s){r=o=i;continue e}l=l.parentNode}}r=r.return}Ne((function(){var r=o,a=Se(n),i=[];e:{var l=Or.get(e);if(void 0!==l){var s=cn,u=e;switch(e){case"keypress":if(0===tn(n))break e;case"keydown":case"keyup":s=An;break;case"focusin":u="focus",s=gn;break;case"focusout":u="blur",s=gn;break;case"beforeblur":case"afterblur":s=gn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":s=mn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":s=hn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":s=Rn;break;case xr:case Ar:case Cr:s=yn;break;case Rr:s=On;break;case"scroll":s=fn;break;case"wheel":s=In;break;case"copy":case"cut":case"paste":s=vn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":s=Cn}var c=!!(4&t),d=!c&&"scroll"===e,f=c?null!==l?l+"Capture":null:l;c=[];for(var p,m=r;null!==m;){var h=(p=m).stateNode;if(5===p.tag&&null!==h&&(p=h,null!==f&&(null!=(h=Ie(m,f))&&c.push(Vr(m,h,p)))),d)break;m=m.return}0<c.length&&(l=new s(l,u,null,n,a),i.push({event:l,listeners:c}))}}if(!(7&t)){if(s="mouseout"===e||"pointerout"===e,(!(l="mouseover"===e||"pointerover"===e)||n===Ee||!(u=n.relatedTarget||n.fromElement)||!ba(u)&&!u[ma])&&(s||l)&&(l=a.window===a?a:(l=a.ownerDocument)?l.defaultView||l.parentWindow:window,s?(s=r,null!==(u=(u=n.relatedTarget||n.toElement)?ba(u):null)&&(u!==(d=$e(u))||5!==u.tag&&6!==u.tag)&&(u=null)):(s=null,u=r),s!==u)){if(c=mn,h="onMouseLeave",f="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(c=Cn,h="onPointerLeave",f="onPointerEnter",m="pointer"),d=null==s?l:Ea(s),p=null==u?l:Ea(u),(l=new c(h,m+"leave",s,n,a)).target=d,l.relatedTarget=p,h=null,ba(a)===r&&((c=new c(f,m+"enter",u,n,a)).target=p,c.relatedTarget=d,h=c),d=h,s&&u)e:{for(f=u,m=0,p=c=s;p;p=Yr(p))m++;for(p=0,h=f;h;h=Yr(h))p++;for(;0<m-p;)c=Yr(c),m--;for(;0<p-m;)f=Yr(f),p--;for(;m--;){if(c===f||null!==f&&c===f.alternate)break e;c=Yr(c),f=Yr(f)}c=null}else c=null;null!==s&&Kr(i,l,s,c,!1),null!==u&&null!==d&&Kr(i,d,u,c,!0)}if("select"===(s=(l=r?Ea(r):window).nodeName&&l.nodeName.toLowerCase())||"input"===s&&"file"===l.type)var g=Xn;else if(Gn(l))if(Qn)g=ir;else{g=ar;var y=rr}else(s=l.nodeName)&&"input"===s.toLowerCase()&&("checkbox"===l.type||"radio"===l.type)&&(g=or);switch(g&&(g=g(e,r))?Vn(i,g,n,a):(y&&y(e,l,r),"focusout"===e&&(y=l._wrapperState)&&y.controlled&&"number"===l.type&&ee(l,"number",l.value)),y=r?Ea(r):window,e){case"focusin":(Gn(y)||"true"===y.contentEditable)&&(gr=y,yr=r,br=null);break;case"focusout":br=yr=gr=null;break;case"mousedown":vr=!0;break;case"contextmenu":case"mouseup":case"dragend":vr=!1,Er(i,n,a);break;case"selectionchange":if(hr)break;case"keydown":case"keyup":Er(i,n,a)}var b;if(Pn)e:{switch(e){case"compositionstart":var v="onCompositionStart";break e;case"compositionend":v="onCompositionEnd";break e;case"compositionupdate":v="onCompositionUpdate";break e}v=void 0}else $n?Bn(e,n)&&(v="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(v="onCompositionStart");v&&(jn&&"ko"!==n.locale&&($n||"onCompositionStart"!==v?"onCompositionEnd"===v&&$n&&(b=en()):(Zt="value"in(Qt=a)?Qt.value:Qt.textContent,$n=!0)),0<(y=Wr(r,v)).length&&(v=new En(v,e,null,n,a),i.push({event:v,listeners:y}),b?v.data=b:null!==(b=zn(n))&&(v.data=b))),(b=Mn?function(e,t){switch(e){case"compositionend":return zn(t);case"keypress":return 32!==t.which?null:(Fn=!0,Un);case"textInput":return(e=t.data)===Un&&Fn?null:e;default:return null}}(e,n):function(e,t){if($n)return"compositionend"===e||!Pn&&Bn(e,t)?(e=en(),Jt=Zt=Qt=null,$n=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return jn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Wr(r,"onBeforeInput")).length&&(a=new En("onBeforeInput","beforeinput",null,n,a),i.push({event:a,listeners:r}),a.data=b))}Ur(i,t)}))}function Vr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Wr(e,t){for(var n=t+"Capture",r=[];null!==e;){var a=e,o=a.stateNode;5===a.tag&&null!==o&&(a=o,null!=(o=Ie(e,n))&&r.unshift(Vr(e,o,a)),null!=(o=Ie(e,t))&&r.push(Vr(e,o,a))),e=e.return}return r}function Yr(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Kr(e,t,n,r,a){for(var o=t._reactName,i=[];null!==n&&n!==r;){var l=n,s=l.alternate,u=l.stateNode;if(null!==s&&s===r)break;5===l.tag&&null!==u&&(l=u,a?null!=(s=Ie(n,o))&&i.unshift(Vr(n,s,l)):a||null!=(s=Ie(n,o))&&i.push(Vr(n,s,l))),n=n.return}0!==i.length&&e.push({event:t,listeners:i})}var qr=/\r\n?/g,Xr=/\u0000|\uFFFD/g;function Qr(e){return("string"==typeof e?e:""+e).replace(qr,"\n").replace(Xr,"")}function Zr(e,t,n){if(t=Qr(t),Qr(e)!==t&&n)throw Error(o(425))}function Jr(){}var ea=null,ta=null;function na(e,t){return"textarea"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var ra="function"==typeof setTimeout?setTimeout:void 0,aa="function"==typeof clearTimeout?clearTimeout:void 0,oa="function"==typeof Promise?Promise:void 0,ia="function"==typeof queueMicrotask?queueMicrotask:void 0!==oa?function(e){return oa.resolve(null).then(e).catch(la)}:ra;function la(e){setTimeout((function(){throw e}))}function sa(e,t){var n=t,r=0;do{var a=n.nextSibling;if(e.removeChild(n),a&&8===a.nodeType)if("/$"===(n=a.data)){if(0===r)return e.removeChild(a),void $t(t);r--}else"$"!==n&&"$?"!==n&&"$!"!==n||r++;n=a}while(n);$t(t)}function ua(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break;if(8===t){if("$"===(t=e.data)||"$!"===t||"$?"===t)break;if("/$"===t)return null}}return e}function ca(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var da=Math.random().toString(36).slice(2),fa="__reactFiber$"+da,pa="__reactProps$"+da,ma="__reactContainer$"+da,ha="__reactEvents$"+da,ga="__reactListeners$"+da,ya="__reactHandles$"+da;function ba(e){var t=e[fa];if(t)return t;for(var n=e.parentNode;n;){if(t=n[ma]||n[fa]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=ca(e);null!==e;){if(n=e[fa])return n;e=ca(e)}return t}n=(e=n).parentNode}return null}function va(e){return!(e=e[fa]||e[ma])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function Ea(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(o(33))}function Sa(e){return e[pa]||null}var _a=[],wa=-1;function ka(e){return{current:e}}function Ta(e){0>wa||(e.current=_a[wa],_a[wa]=null,wa--)}function xa(e,t){wa++,_a[wa]=e.current,e.current=t}var Aa={},Ca=ka(Aa),Ra=ka(!1),Oa=Aa;function Na(e,t){var n=e.type.contextTypes;if(!n)return Aa;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,o={};for(a in n)o[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Ia(e){return null!=(e=e.childContextTypes)}function La(){Ta(Ra),Ta(Ca)}function Pa(e,t,n){if(Ca.current!==Aa)throw Error(o(168));xa(Ca,t),xa(Ra,n)}function Da(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var a in r=r.getChildContext())if(!(a in t))throw Error(o(108,H(e)||"Unknown",a));return j({},n,r)}function Ma(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Aa,Oa=Ca.current,xa(Ca,e),xa(Ra,Ra.current),!0}function ja(e,t,n){var r=e.stateNode;if(!r)throw Error(o(169));n?(e=Da(e,t,Oa),r.__reactInternalMemoizedMergedChildContext=e,Ta(Ra),Ta(Ca),xa(Ca,e)):Ta(Ra),xa(Ra,n)}var Ua=null,Fa=!1,Ba=!1;function za(e){null===Ua?Ua=[e]:Ua.push(e)}function $a(){if(!Ba&&null!==Ua){Ba=!0;var e=0,t=vt;try{var n=Ua;for(vt=1;e<n.length;e++){var r=n[e];do{r=r(!0)}while(null!==r)}Ua=null,Fa=!1}catch(a){throw null!==Ua&&(Ua=Ua.slice(e+1)),Ye(Je,$a),a}finally{vt=t,Ba=!1}}return null}var Ha=[],Ga=0,Va=null,Wa=0,Ya=[],Ka=0,qa=null,Xa=1,Qa="";function Za(e,t){Ha[Ga++]=Wa,Ha[Ga++]=Va,Va=e,Wa=t}function Ja(e,t,n){Ya[Ka++]=Xa,Ya[Ka++]=Qa,Ya[Ka++]=qa,qa=e;var r=Xa;e=Qa;var a=32-it(r)-1;r&=~(1<<a),n+=1;var o=32-it(t)+a;if(30<o){var i=a-a%5;o=(r&(1<<i)-1).toString(32),r>>=i,a-=i,Xa=1<<32-it(t)+a|n<<a|r,Qa=o+e}else Xa=1<<o|n<<a|r,Qa=e}function eo(e){null!==e.return&&(Za(e,1),Ja(e,1,0))}function to(e){for(;e===Va;)Va=Ha[--Ga],Ha[Ga]=null,Wa=Ha[--Ga],Ha[Ga]=null;for(;e===qa;)qa=Ya[--Ka],Ya[Ka]=null,Qa=Ya[--Ka],Ya[Ka]=null,Xa=Ya[--Ka],Ya[Ka]=null}var no=null,ro=null,ao=!1,oo=null;function io(e,t){var n=Nu(5,null,null,0);n.elementType="DELETED",n.stateNode=t,n.return=e,null===(t=e.deletions)?(e.deletions=[n],e.flags|=16):t.push(n)}function lo(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,no=e,ro=ua(t.firstChild),!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,no=e,ro=null,!0);case 13:return null!==(t=8!==t.nodeType?null:t)&&(n=null!==qa?{id:Xa,overflow:Qa}:null,e.memoizedState={dehydrated:t,treeContext:n,retryLane:1073741824},(n=Nu(18,null,null,0)).stateNode=t,n.return=e,e.child=n,no=e,ro=null,!0);default:return!1}}function so(e){return!(!(1&e.mode)||128&e.flags)}function uo(e){if(ao){var t=ro;if(t){var n=t;if(!lo(e,t)){if(so(e))throw Error(o(418));t=ua(n.nextSibling);var r=no;t&&lo(e,t)?io(r,n):(e.flags=-4097&e.flags|2,ao=!1,no=e)}}else{if(so(e))throw Error(o(418));e.flags=-4097&e.flags|2,ao=!1,no=e}}}function co(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;no=e}function fo(e){if(e!==no)return!1;if(!ao)return co(e),ao=!0,!1;var t;if((t=3!==e.tag)&&!(t=5!==e.tag)&&(t="head"!==(t=e.type)&&"body"!==t&&!na(e.type,e.memoizedProps)),t&&(t=ro)){if(so(e))throw po(),Error(o(418));for(;t;)io(e,t),t=ua(t.nextSibling)}if(co(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(o(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){ro=ua(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}ro=null}}else ro=no?ua(e.stateNode.nextSibling):null;return!0}function po(){for(var e=ro;e;)e=ua(e.nextSibling)}function mo(){ro=no=null,ao=!1}function ho(e){null===oo?oo=[e]:oo.push(e)}var go=E.ReactCurrentBatchConfig;function yo(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(o(309));var r=n.stateNode}if(!r)throw Error(o(147,e));var a=r,i=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===i?t.ref:(t=function(e){var t=a.refs;null===e?delete t[i]:t[i]=e},t._stringRef=i,t)}if("string"!=typeof e)throw Error(o(284));if(!n._owner)throw Error(o(290,e))}return e}function bo(e,t){throw e=Object.prototype.toString.call(t),Error(o(31,"[object Object]"===e?"object with keys {"+Object.keys(t).join(", ")+"}":e))}function vo(e){return(0,e._init)(e._payload)}function Eo(e){function t(t,n){if(e){var r=t.deletions;null===r?(t.deletions=[n],t.flags|=16):r.push(n)}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Lu(e,t)).index=0,e.sibling=null,e}function i(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags|=2,n):r:(t.flags|=2,n):(t.flags|=1048576,n)}function l(t){return e&&null===t.alternate&&(t.flags|=2),t}function s(e,t,n,r){return null===t||6!==t.tag?((t=ju(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function u(e,t,n,r){var o=n.type;return o===w?d(e,t,n.props.children,r,n.key):null!==t&&(t.elementType===o||"object"==typeof o&&null!==o&&o.$$typeof===I&&vo(o)===t.type)?((r=a(t,n.props)).ref=yo(e,t,n),r.return=e,r):((r=Pu(n.type,n.key,n.props,null,e.mode,r)).ref=yo(e,t,n),r.return=e,r)}function c(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=Uu(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,o){return null===t||7!==t.tag?((t=Du(n,e.mode,r,o)).return=e,t):((t=a(t,n)).return=e,t)}function f(e,t,n){if("string"==typeof t&&""!==t||"number"==typeof t)return(t=ju(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case S:return(n=Pu(t.type,t.key,t.props,null,e.mode,n)).ref=yo(e,null,t),n.return=e,n;case _:return(t=Uu(t,e.mode,n)).return=e,t;case I:return f(e,(0,t._init)(t._payload),n)}if(te(t)||D(t))return(t=Du(t,e.mode,n,null)).return=e,t;bo(e,t)}return null}function p(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n&&""!==n||"number"==typeof n)return null!==a?null:s(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case S:return n.key===a?u(e,t,n,r):null;case _:return n.key===a?c(e,t,n,r):null;case I:return p(e,t,(a=n._init)(n._payload),r)}if(te(n)||D(n))return null!==a?null:d(e,t,n,r,null);bo(e,n)}return null}function m(e,t,n,r,a){if("string"==typeof r&&""!==r||"number"==typeof r)return s(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case S:return u(t,e=e.get(null===r.key?n:r.key)||null,r,a);case _:return c(t,e=e.get(null===r.key?n:r.key)||null,r,a);case I:return m(e,t,n,(0,r._init)(r._payload),a)}if(te(r)||D(r))return d(t,e=e.get(n)||null,r,a,null);bo(t,r)}return null}function h(a,o,l,s){for(var u=null,c=null,d=o,h=o=0,g=null;null!==d&&h<l.length;h++){d.index>h?(g=d,d=null):g=d.sibling;var y=p(a,d,l[h],s);if(null===y){null===d&&(d=g);break}e&&d&&null===y.alternate&&t(a,d),o=i(y,o,h),null===c?u=y:c.sibling=y,c=y,d=g}if(h===l.length)return n(a,d),ao&&Za(a,h),u;if(null===d){for(;h<l.length;h++)null!==(d=f(a,l[h],s))&&(o=i(d,o,h),null===c?u=d:c.sibling=d,c=d);return ao&&Za(a,h),u}for(d=r(a,d);h<l.length;h++)null!==(g=m(d,a,h,l[h],s))&&(e&&null!==g.alternate&&d.delete(null===g.key?h:g.key),o=i(g,o,h),null===c?u=g:c.sibling=g,c=g);return e&&d.forEach((function(e){return t(a,e)})),ao&&Za(a,h),u}function g(a,l,s,u){var c=D(s);if("function"!=typeof c)throw Error(o(150));if(null==(s=c.call(s)))throw Error(o(151));for(var d=c=null,h=l,g=l=0,y=null,b=s.next();null!==h&&!b.done;g++,b=s.next()){h.index>g?(y=h,h=null):y=h.sibling;var v=p(a,h,b.value,u);if(null===v){null===h&&(h=y);break}e&&h&&null===v.alternate&&t(a,h),l=i(v,l,g),null===d?c=v:d.sibling=v,d=v,h=y}if(b.done)return n(a,h),ao&&Za(a,g),c;if(null===h){for(;!b.done;g++,b=s.next())null!==(b=f(a,b.value,u))&&(l=i(b,l,g),null===d?c=b:d.sibling=b,d=b);return ao&&Za(a,g),c}for(h=r(a,h);!b.done;g++,b=s.next())null!==(b=m(h,a,g,b.value,u))&&(e&&null!==b.alternate&&h.delete(null===b.key?g:b.key),l=i(b,l,g),null===d?c=b:d.sibling=b,d=b);return e&&h.forEach((function(e){return t(a,e)})),ao&&Za(a,g),c}return function e(r,o,i,s){if("object"==typeof i&&null!==i&&i.type===w&&null===i.key&&(i=i.props.children),"object"==typeof i&&null!==i){switch(i.$$typeof){case S:e:{for(var u=i.key,c=o;null!==c;){if(c.key===u){if((u=i.type)===w){if(7===c.tag){n(r,c.sibling),(o=a(c,i.props.children)).return=r,r=o;break e}}else if(c.elementType===u||"object"==typeof u&&null!==u&&u.$$typeof===I&&vo(u)===c.type){n(r,c.sibling),(o=a(c,i.props)).ref=yo(r,c,i),o.return=r,r=o;break e}n(r,c);break}t(r,c),c=c.sibling}i.type===w?((o=Du(i.props.children,r.mode,s,i.key)).return=r,r=o):((s=Pu(i.type,i.key,i.props,null,r.mode,s)).ref=yo(r,o,i),s.return=r,r=s)}return l(r);case _:e:{for(c=i.key;null!==o;){if(o.key===c){if(4===o.tag&&o.stateNode.containerInfo===i.containerInfo&&o.stateNode.implementation===i.implementation){n(r,o.sibling),(o=a(o,i.children||[])).return=r,r=o;break e}n(r,o);break}t(r,o),o=o.sibling}(o=Uu(i,r.mode,s)).return=r,r=o}return l(r);case I:return e(r,o,(c=i._init)(i._payload),s)}if(te(i))return h(r,o,i,s);if(D(i))return g(r,o,i,s);bo(r,i)}return"string"==typeof i&&""!==i||"number"==typeof i?(i=""+i,null!==o&&6===o.tag?(n(r,o.sibling),(o=a(o,i)).return=r,r=o):(n(r,o),(o=ju(i,r.mode,s)).return=r,r=o),l(r)):n(r,o)}}var So=Eo(!0),_o=Eo(!1),wo=ka(null),ko=null,To=null,xo=null;function Ao(){xo=To=ko=null}function Co(e){var t=wo.current;Ta(wo),e._currentValue=t}function Ro(e,t,n){for(;null!==e;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,null!==r&&(r.childLanes|=t)):null!==r&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Oo(e,t){ko=e,xo=To=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(!!(e.lanes&t)&&(vl=!0),e.firstContext=null)}function No(e){var t=e._currentValue;if(xo!==e)if(e={context:e,memoizedValue:t,next:null},null===To){if(null===ko)throw Error(o(308));To=e,ko.dependencies={lanes:0,firstContext:e}}else To=To.next=e;return t}var Io=null;function Lo(e){null===Io?Io=[e]:Io.push(e)}function Po(e,t,n,r){var a=t.interleaved;return null===a?(n.next=n,Lo(t)):(n.next=a.next,a.next=n),t.interleaved=n,Do(e,r)}function Do(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}var Mo=!1;function jo(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Uo(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Fo(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function Bo(e,t,n){var r=e.updateQueue;if(null===r)return null;if(r=r.shared,2&Cs){var a=r.pending;return null===a?t.next=t:(t.next=a.next,a.next=t),r.pending=t,Do(e,n)}return null===(a=r.interleaved)?(t.next=t,Lo(r)):(t.next=a.next,a.next=t),r.interleaved=t,Do(e,n)}function zo(e,t,n){if(null!==(t=t.updateQueue)&&(t=t.shared,4194240&n)){var r=t.lanes;n|=r&=e.pendingLanes,t.lanes=n,bt(e,n)}}function $o(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var a=null,o=null;if(null!==(n=n.firstBaseUpdate)){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===o?a=o=i:o=o.next=i,n=n.next}while(null!==n);null===o?a=o=t:o=o.next=t}else a=o=t;return n={baseState:r.baseState,firstBaseUpdate:a,lastBaseUpdate:o,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Ho(e,t,n,r){var a=e.updateQueue;Mo=!1;var o=a.firstBaseUpdate,i=a.lastBaseUpdate,l=a.shared.pending;if(null!==l){a.shared.pending=null;var s=l,u=s.next;s.next=null,null===i?o=u:i.next=u,i=s;var c=e.alternate;null!==c&&((l=(c=c.updateQueue).lastBaseUpdate)!==i&&(null===l?c.firstBaseUpdate=u:l.next=u,c.lastBaseUpdate=s))}if(null!==o){var d=a.baseState;for(i=0,c=u=s=null,l=o;;){var f=l.lane,p=l.eventTime;if((r&f)===f){null!==c&&(c=c.next={eventTime:p,lane:0,tag:l.tag,payload:l.payload,callback:l.callback,next:null});e:{var m=e,h=l;switch(f=t,p=n,h.tag){case 1:if("function"==typeof(m=h.payload)){d=m.call(p,d,f);break e}d=m;break e;case 3:m.flags=-65537&m.flags|128;case 0:if(null==(f="function"==typeof(m=h.payload)?m.call(p,d,f):m))break e;d=j({},d,f);break e;case 2:Mo=!0}}null!==l.callback&&0!==l.lane&&(e.flags|=64,null===(f=a.effects)?a.effects=[l]:f.push(l))}else p={eventTime:p,lane:f,tag:l.tag,payload:l.payload,callback:l.callback,next:null},null===c?(u=c=p,s=d):c=c.next=p,i|=f;if(null===(l=l.next)){if(null===(l=a.shared.pending))break;l=(f=l).next,f.next=null,a.lastBaseUpdate=f,a.shared.pending=null}}if(null===c&&(s=d),a.baseState=s,a.firstBaseUpdate=u,a.lastBaseUpdate=c,null!==(t=a.shared.interleaved)){a=t;do{i|=a.lane,a=a.next}while(a!==t)}else null===o&&(a.shared.lanes=0);Ms|=i,e.lanes=i,e.memoizedState=d}}function Go(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=n,"function"!=typeof a)throw Error(o(191,a));a.call(r)}}}var Vo={},Wo=ka(Vo),Yo=ka(Vo),Ko=ka(Vo);function qo(e){if(e===Vo)throw Error(o(174));return e}function Xo(e,t){switch(xa(Ko,t),xa(Yo,e),xa(Wo,Vo),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:se(null,"");break;default:t=se(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}Ta(Wo),xa(Wo,t)}function Qo(){Ta(Wo),Ta(Yo),Ta(Ko)}function Zo(e){qo(Ko.current);var t=qo(Wo.current),n=se(t,e.type);t!==n&&(xa(Yo,e),xa(Wo,n))}function Jo(e){Yo.current===e&&(Ta(Wo),Ta(Yo))}var ei=ka(0);function ti(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(128&t.flags)return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var ni=[];function ri(){for(var e=0;e<ni.length;e++)ni[e]._workInProgressVersionPrimary=null;ni.length=0}var ai=E.ReactCurrentDispatcher,oi=E.ReactCurrentBatchConfig,ii=0,li=null,si=null,ui=null,ci=!1,di=!1,fi=0,pi=0;function mi(){throw Error(o(321))}function hi(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!lr(e[n],t[n]))return!1;return!0}function gi(e,t,n,r,a,i){if(ii=i,li=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,ai.current=null===e||null===e.memoizedState?Ji:el,e=n(r,a),di){i=0;do{if(di=!1,fi=0,25<=i)throw Error(o(301));i+=1,ui=si=null,t.updateQueue=null,ai.current=tl,e=n(r,a)}while(di)}if(ai.current=Zi,t=null!==si&&null!==si.next,ii=0,ui=si=li=null,ci=!1,t)throw Error(o(300));return e}function yi(){var e=0!==fi;return fi=0,e}function bi(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===ui?li.memoizedState=ui=e:ui=ui.next=e,ui}function vi(){if(null===si){var e=li.alternate;e=null!==e?e.memoizedState:null}else e=si.next;var t=null===ui?li.memoizedState:ui.next;if(null!==t)ui=t,si=e;else{if(null===e)throw Error(o(310));e={memoizedState:(si=e).memoizedState,baseState:si.baseState,baseQueue:si.baseQueue,queue:si.queue,next:null},null===ui?li.memoizedState=ui=e:ui=ui.next=e}return ui}function Ei(e,t){return"function"==typeof t?t(e):t}function Si(e){var t=vi(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=si,a=r.baseQueue,i=n.pending;if(null!==i){if(null!==a){var l=a.next;a.next=i.next,i.next=l}r.baseQueue=a=i,n.pending=null}if(null!==a){i=a.next,r=r.baseState;var s=l=null,u=null,c=i;do{var d=c.lane;if((ii&d)===d)null!==u&&(u=u.next={lane:0,action:c.action,hasEagerState:c.hasEagerState,eagerState:c.eagerState,next:null}),r=c.hasEagerState?c.eagerState:e(r,c.action);else{var f={lane:d,action:c.action,hasEagerState:c.hasEagerState,eagerState:c.eagerState,next:null};null===u?(s=u=f,l=r):u=u.next=f,li.lanes|=d,Ms|=d}c=c.next}while(null!==c&&c!==i);null===u?l=r:u.next=s,lr(r,t.memoizedState)||(vl=!0),t.memoizedState=r,t.baseState=l,t.baseQueue=u,n.lastRenderedState=r}if(null!==(e=n.interleaved)){a=e;do{i=a.lane,li.lanes|=i,Ms|=i,a=a.next}while(a!==e)}else null===a&&(n.lanes=0);return[t.memoizedState,n.dispatch]}function _i(e){var t=vi(),n=t.queue;if(null===n)throw Error(o(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,i=t.memoizedState;if(null!==a){n.pending=null;var l=a=a.next;do{i=e(i,l.action),l=l.next}while(l!==a);lr(i,t.memoizedState)||(vl=!0),t.memoizedState=i,null===t.baseQueue&&(t.baseState=i),n.lastRenderedState=i}return[i,r]}function wi(){}function ki(e,t){var n=li,r=vi(),a=t(),i=!lr(r.memoizedState,a);if(i&&(r.memoizedState=a,vl=!0),r=r.queue,Mi(Ai.bind(null,n,r,e),[e]),r.getSnapshot!==t||i||null!==ui&&1&ui.memoizedState.tag){if(n.flags|=2048,Ni(9,xi.bind(null,n,r,a,t),void 0,null),null===Rs)throw Error(o(349));30&ii||Ti(n,t,a)}return a}function Ti(e,t,n){e.flags|=16384,e={getSnapshot:t,value:n},null===(t=li.updateQueue)?(t={lastEffect:null,stores:null},li.updateQueue=t,t.stores=[e]):null===(n=t.stores)?t.stores=[e]:n.push(e)}function xi(e,t,n,r){t.value=n,t.getSnapshot=r,Ci(t)&&Ri(e)}function Ai(e,t,n){return n((function(){Ci(t)&&Ri(e)}))}function Ci(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!lr(e,n)}catch(r){return!0}}function Ri(e){var t=Do(e,1);null!==t&&nu(t,e,1,-1)}function Oi(e){var t=bi();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:Ei,lastRenderedState:e},t.queue=e,e=e.dispatch=Ki.bind(null,li,e),[t.memoizedState,e]}function Ni(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=li.updateQueue)?(t={lastEffect:null,stores:null},li.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function Ii(){return vi().memoizedState}function Li(e,t,n,r){var a=bi();li.flags|=e,a.memoizedState=Ni(1|t,n,void 0,void 0===r?null:r)}function Pi(e,t,n,r){var a=vi();r=void 0===r?null:r;var o=void 0;if(null!==si){var i=si.memoizedState;if(o=i.destroy,null!==r&&hi(r,i.deps))return void(a.memoizedState=Ni(t,n,o,r))}li.flags|=e,a.memoizedState=Ni(1|t,n,o,r)}function Di(e,t){return Li(8390656,8,e,t)}function Mi(e,t){return Pi(2048,8,e,t)}function ji(e,t){return Pi(4,2,e,t)}function Ui(e,t){return Pi(4,4,e,t)}function Fi(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function Bi(e,t,n){return n=null!=n?n.concat([e]):null,Pi(4,4,Fi.bind(null,t,e),n)}function zi(){}function $i(e,t){var n=vi();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&hi(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Hi(e,t){var n=vi();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&hi(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Gi(e,t,n){return 21&ii?(lr(n,t)||(n=ht(),li.lanes|=n,Ms|=n,e.baseState=!0),t):(e.baseState&&(e.baseState=!1,vl=!0),e.memoizedState=n)}function Vi(e,t){var n=vt;vt=0!==n&&4>n?n:4,e(!0);var r=oi.transition;oi.transition={};try{e(!1),t()}finally{vt=n,oi.transition=r}}function Wi(){return vi().memoizedState}function Yi(e,t,n){var r=tu(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},qi(e))Xi(t,n);else if(null!==(n=Po(e,t,n,r))){nu(n,e,r,eu()),Qi(n,t,r)}}function Ki(e,t,n){var r=tu(e),a={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(qi(e))Xi(t,a);else{var o=e.alternate;if(0===e.lanes&&(null===o||0===o.lanes)&&null!==(o=t.lastRenderedReducer))try{var i=t.lastRenderedState,l=o(i,n);if(a.hasEagerState=!0,a.eagerState=l,lr(l,i)){var s=t.interleaved;return null===s?(a.next=a,Lo(t)):(a.next=s.next,s.next=a),void(t.interleaved=a)}}catch(u){}null!==(n=Po(e,t,a,r))&&(nu(n,e,r,a=eu()),Qi(n,t,r))}}function qi(e){var t=e.alternate;return e===li||null!==t&&t===li}function Xi(e,t){di=ci=!0;var n=e.pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Qi(e,t,n){if(4194240&n){var r=t.lanes;n|=r&=e.pendingLanes,t.lanes=n,bt(e,n)}}var Zi={readContext:No,useCallback:mi,useContext:mi,useEffect:mi,useImperativeHandle:mi,useInsertionEffect:mi,useLayoutEffect:mi,useMemo:mi,useReducer:mi,useRef:mi,useState:mi,useDebugValue:mi,useDeferredValue:mi,useTransition:mi,useMutableSource:mi,useSyncExternalStore:mi,useId:mi,unstable_isNewReconciler:!1},Ji={readContext:No,useCallback:function(e,t){return bi().memoizedState=[e,void 0===t?null:t],e},useContext:No,useEffect:Di,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,Li(4194308,4,Fi.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Li(4194308,4,e,t)},useInsertionEffect:function(e,t){return Li(4,2,e,t)},useMemo:function(e,t){var n=bi();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=bi();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Yi.bind(null,li,e),[r.memoizedState,e]},useRef:function(e){return e={current:e},bi().memoizedState=e},useState:Oi,useDebugValue:zi,useDeferredValue:function(e){return bi().memoizedState=e},useTransition:function(){var e=Oi(!1),t=e[0];return e=Vi.bind(null,e[1]),bi().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=li,a=bi();if(ao){if(void 0===n)throw Error(o(407));n=n()}else{if(n=t(),null===Rs)throw Error(o(349));30&ii||Ti(r,t,n)}a.memoizedState=n;var i={value:n,getSnapshot:t};return a.queue=i,Di(Ai.bind(null,r,i,e),[e]),r.flags|=2048,Ni(9,xi.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=bi(),t=Rs.identifierPrefix;if(ao){var n=Qa;t=":"+t+"R"+(n=(Xa&~(1<<32-it(Xa)-1)).toString(32)+n),0<(n=fi++)&&(t+="H"+n.toString(32)),t+=":"}else t=":"+t+"r"+(n=pi++).toString(32)+":";return e.memoizedState=t},unstable_isNewReconciler:!1},el={readContext:No,useCallback:$i,useContext:No,useEffect:Mi,useImperativeHandle:Bi,useInsertionEffect:ji,useLayoutEffect:Ui,useMemo:Hi,useReducer:Si,useRef:Ii,useState:function(){return Si(Ei)},useDebugValue:zi,useDeferredValue:function(e){return Gi(vi(),si.memoizedState,e)},useTransition:function(){return[Si(Ei)[0],vi().memoizedState]},useMutableSource:wi,useSyncExternalStore:ki,useId:Wi,unstable_isNewReconciler:!1},tl={readContext:No,useCallback:$i,useContext:No,useEffect:Mi,useImperativeHandle:Bi,useInsertionEffect:ji,useLayoutEffect:Ui,useMemo:Hi,useReducer:_i,useRef:Ii,useState:function(){return _i(Ei)},useDebugValue:zi,useDeferredValue:function(e){var t=vi();return null===si?t.memoizedState=e:Gi(t,si.memoizedState,e)},useTransition:function(){return[_i(Ei)[0],vi().memoizedState]},useMutableSource:wi,useSyncExternalStore:ki,useId:Wi,unstable_isNewReconciler:!1};function nl(e,t){if(e&&e.defaultProps){for(var n in t=j({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}function rl(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:j({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var al={isMounted:function(e){return!!(e=e._reactInternals)&&$e(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=eu(),a=tu(e),o=Fo(r,a);o.payload=t,null!=n&&(o.callback=n),null!==(t=Bo(e,o,a))&&(nu(t,e,a,r),zo(t,e,a))},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=eu(),a=tu(e),o=Fo(r,a);o.tag=1,o.payload=t,null!=n&&(o.callback=n),null!==(t=Bo(e,o,a))&&(nu(t,e,a,r),zo(t,e,a))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=eu(),r=tu(e),a=Fo(n,r);a.tag=2,null!=t&&(a.callback=t),null!==(t=Bo(e,a,r))&&(nu(t,e,r,n),zo(t,e,r))}};function ol(e,t,n,r,a,o,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,o,i):!t.prototype||!t.prototype.isPureReactComponent||(!sr(n,r)||!sr(a,o))}function il(e,t,n){var r=!1,a=Aa,o=t.contextType;return"object"==typeof o&&null!==o?o=No(o):(a=Ia(t)?Oa:Ca.current,o=(r=null!=(r=t.contextTypes))?Na(e,a):Aa),t=new t(n,o),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=al,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=o),t}function ll(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&al.enqueueReplaceState(t,t.state,null)}function sl(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs={},jo(e);var o=t.contextType;"object"==typeof o&&null!==o?a.context=No(o):(o=Ia(t)?Oa:Ca.current,a.context=Na(e,o)),a.state=e.memoizedState,"function"==typeof(o=t.getDerivedStateFromProps)&&(rl(e,t,o,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&al.enqueueReplaceState(a,a.state,null),Ho(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.flags|=4194308)}function ul(e,t){try{var n="",r=t;do{n+=z(r),r=r.return}while(r);var a=n}catch(o){a="\nError generating stack: "+o.message+"\n"+o.stack}return{value:e,source:t,stack:a,digest:null}}function cl(e,t,n){return{value:e,source:null,stack:null!=n?n:null,digest:null!=t?t:null}}function dl(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}var fl="function"==typeof WeakMap?WeakMap:Map;function pl(e,t,n){(n=Fo(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Gs||(Gs=!0,Vs=r),dl(0,t)},n}function ml(e,t,n){(n=Fo(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return r(a)},n.callback=function(){dl(0,t)}}var o=e.stateNode;return null!==o&&"function"==typeof o.componentDidCatch&&(n.callback=function(){dl(0,t),"function"!=typeof r&&(null===Ws?Ws=new Set([this]):Ws.add(this));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}function hl(e,t,n){var r=e.pingCache;if(null===r){r=e.pingCache=new fl;var a=new Set;r.set(t,a)}else void 0===(a=r.get(t))&&(a=new Set,r.set(t,a));a.has(n)||(a.add(n),e=Tu.bind(null,e,t,n),t.then(e,e))}function gl(e){do{var t;if((t=13===e.tag)&&(t=null===(t=e.memoizedState)||null!==t.dehydrated),t)return e;e=e.return}while(null!==e);return null}function yl(e,t,n,r,a){return 1&e.mode?(e.flags|=65536,e.lanes=a,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,1===n.tag&&(null===n.alternate?n.tag=17:((t=Fo(-1,1)).tag=2,Bo(n,t,1))),n.lanes|=1),e)}var bl=E.ReactCurrentOwner,vl=!1;function El(e,t,n,r){t.child=null===e?_o(t,null,n,r):So(t,e.child,n,r)}function Sl(e,t,n,r,a){n=n.render;var o=t.ref;return Oo(t,a),r=gi(e,t,n,r,o,a),n=yi(),null===e||vl?(ao&&n&&eo(t),t.flags|=1,El(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~a,Gl(e,t,a))}function _l(e,t,n,r,a){if(null===e){var o=n.type;return"function"!=typeof o||Iu(o)||void 0!==o.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Pu(n.type,null,r,t,t.mode,a)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=o,wl(e,t,o,r,a))}if(o=e.child,!(e.lanes&a)){var i=o.memoizedProps;if((n=null!==(n=n.compare)?n:sr)(i,r)&&e.ref===t.ref)return Gl(e,t,a)}return t.flags|=1,(e=Lu(o,r)).ref=t.ref,e.return=t,t.child=e}function wl(e,t,n,r,a){if(null!==e){var o=e.memoizedProps;if(sr(o,r)&&e.ref===t.ref){if(vl=!1,t.pendingProps=r=o,!(e.lanes&a))return t.lanes=e.lanes,Gl(e,t,a);131072&e.flags&&(vl=!0)}}return xl(e,t,n,r,a)}function kl(e,t,n){var r=t.pendingProps,a=r.children,o=null!==e?e.memoizedState:null;if("hidden"===r.mode)if(1&t.mode){if(!(1073741824&n))return e=null!==o?o.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,xa(Ls,Is),Is|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=null!==o?o.baseLanes:n,xa(Ls,Is),Is|=r}else t.memoizedState={baseLanes:0,cachePool:null,transitions:null},xa(Ls,Is),Is|=n;else null!==o?(r=o.baseLanes|n,t.memoizedState=null):r=n,xa(Ls,Is),Is|=r;return El(e,t,a,n),t.child}function Tl(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function xl(e,t,n,r,a){var o=Ia(n)?Oa:Ca.current;return o=Na(t,o),Oo(t,a),n=gi(e,t,n,r,o,a),r=yi(),null===e||vl?(ao&&r&&eo(t),t.flags|=1,El(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~a,Gl(e,t,a))}function Al(e,t,n,r,a){if(Ia(n)){var o=!0;Ma(t)}else o=!1;if(Oo(t,a),null===t.stateNode)Hl(e,t),il(t,n,r),sl(t,n,r,a),r=!0;else if(null===e){var i=t.stateNode,l=t.memoizedProps;i.props=l;var s=i.context,u=n.contextType;"object"==typeof u&&null!==u?u=No(u):u=Na(t,u=Ia(n)?Oa:Ca.current);var c=n.getDerivedStateFromProps,d="function"==typeof c||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==r||s!==u)&&ll(t,i,r,u),Mo=!1;var f=t.memoizedState;i.state=f,Ho(t,r,i,a),s=t.memoizedState,l!==r||f!==s||Ra.current||Mo?("function"==typeof c&&(rl(t,n,c,r),s=t.memoizedState),(l=Mo||ol(t,n,l,r,f,s,u))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(t.flags|=4194308)):("function"==typeof i.componentDidMount&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=s),i.props=r,i.state=s,i.context=u,r=l):("function"==typeof i.componentDidMount&&(t.flags|=4194308),r=!1)}else{i=t.stateNode,Uo(e,t),l=t.memoizedProps,u=t.type===t.elementType?l:nl(t.type,l),i.props=u,d=t.pendingProps,f=i.context,"object"==typeof(s=n.contextType)&&null!==s?s=No(s):s=Na(t,s=Ia(n)?Oa:Ca.current);var p=n.getDerivedStateFromProps;(c="function"==typeof p||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==d||f!==s)&&ll(t,i,r,s),Mo=!1,f=t.memoizedState,i.state=f,Ho(t,r,i,a);var m=t.memoizedState;l!==d||f!==m||Ra.current||Mo?("function"==typeof p&&(rl(t,n,p,r),m=t.memoizedState),(u=Mo||ol(t,n,u,r,f,m,s)||!1)?(c||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,m,s),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,m,s)),"function"==typeof i.componentDidUpdate&&(t.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(t.flags|=1024)):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=m),i.props=r,i.state=m,i.context=s,r=u):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=1024),r=!1)}return Cl(e,t,n,r,o,a)}function Cl(e,t,n,r,a,o){Tl(e,t);var i=!!(128&t.flags);if(!r&&!i)return a&&ja(t,n,!1),Gl(e,t,o);r=t.stateNode,bl.current=t;var l=i&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&i?(t.child=So(t,e.child,null,o),t.child=So(t,null,l,o)):El(e,t,l,o),t.memoizedState=r.state,a&&ja(t,n,!0),t.child}function Rl(e){var t=e.stateNode;t.pendingContext?Pa(0,t.pendingContext,t.pendingContext!==t.context):t.context&&Pa(0,t.context,!1),Xo(e,t.containerInfo)}function Ol(e,t,n,r,a){return mo(),ho(a),t.flags|=256,El(e,t,n,r),t.child}var Nl,Il,Ll,Pl,Dl={dehydrated:null,treeContext:null,retryLane:0};function Ml(e){return{baseLanes:e,cachePool:null,transitions:null}}function jl(e,t,n){var r,a=t.pendingProps,i=ei.current,l=!1,s=!!(128&t.flags);if((r=s)||(r=(null===e||null!==e.memoizedState)&&!!(2&i)),r?(l=!0,t.flags&=-129):null!==e&&null===e.memoizedState||(i|=1),xa(ei,1&i),null===e)return uo(t),null!==(e=t.memoizedState)&&null!==(e=e.dehydrated)?(1&t.mode?"$!"===e.data?t.lanes=8:t.lanes=1073741824:t.lanes=1,null):(s=a.children,e=a.fallback,l?(a=t.mode,l=t.child,s={mode:"hidden",children:s},1&a||null===l?l=Mu(s,a,0,null):(l.childLanes=0,l.pendingProps=s),e=Du(e,a,n,null),l.return=t,e.return=t,l.sibling=e,t.child=l,t.child.memoizedState=Ml(n),t.memoizedState=Dl,e):Ul(t,s));if(null!==(i=e.memoizedState)&&null!==(r=i.dehydrated))return function(e,t,n,r,a,i,l){if(n)return 256&t.flags?(t.flags&=-257,Fl(e,t,l,r=cl(Error(o(422))))):null!==t.memoizedState?(t.child=e.child,t.flags|=128,null):(i=r.fallback,a=t.mode,r=Mu({mode:"visible",children:r.children},a,0,null),(i=Du(i,a,l,null)).flags|=2,r.return=t,i.return=t,r.sibling=i,t.child=r,1&t.mode&&So(t,e.child,null,l),t.child.memoizedState=Ml(l),t.memoizedState=Dl,i);if(!(1&t.mode))return Fl(e,t,l,null);if("$!"===a.data){if(r=a.nextSibling&&a.nextSibling.dataset)var s=r.dgst;return r=s,Fl(e,t,l,r=cl(i=Error(o(419)),r,void 0))}if(s=!!(l&e.childLanes),vl||s){if(null!==(r=Rs)){switch(l&-l){case 4:a=2;break;case 16:a=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:a=32;break;case 536870912:a=268435456;break;default:a=0}0!==(a=a&(r.suspendedLanes|l)?0:a)&&a!==i.retryLane&&(i.retryLane=a,Do(e,a),nu(r,e,a,-1))}return hu(),Fl(e,t,l,r=cl(Error(o(421))))}return"$?"===a.data?(t.flags|=128,t.child=e.child,t=Au.bind(null,e),a._reactRetry=t,null):(e=i.treeContext,ro=ua(a.nextSibling),no=t,ao=!0,oo=null,null!==e&&(Ya[Ka++]=Xa,Ya[Ka++]=Qa,Ya[Ka++]=qa,Xa=e.id,Qa=e.overflow,qa=t),t=Ul(t,r.children),t.flags|=4096,t)}(e,t,s,a,r,i,n);if(l){l=a.fallback,s=t.mode,r=(i=e.child).sibling;var u={mode:"hidden",children:a.children};return 1&s||t.child===i?(a=Lu(i,u)).subtreeFlags=14680064&i.subtreeFlags:((a=t.child).childLanes=0,a.pendingProps=u,t.deletions=null),null!==r?l=Lu(r,l):(l=Du(l,s,n,null)).flags|=2,l.return=t,a.return=t,a.sibling=l,t.child=a,a=l,l=t.child,s=null===(s=e.child.memoizedState)?Ml(n):{baseLanes:s.baseLanes|n,cachePool:null,transitions:s.transitions},l.memoizedState=s,l.childLanes=e.childLanes&~n,t.memoizedState=Dl,a}return e=(l=e.child).sibling,a=Lu(l,{mode:"visible",children:a.children}),!(1&t.mode)&&(a.lanes=n),a.return=t,a.sibling=null,null!==e&&(null===(n=t.deletions)?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=a,t.memoizedState=null,a}function Ul(e,t){return(t=Mu({mode:"visible",children:t},e.mode,0,null)).return=e,e.child=t}function Fl(e,t,n,r){return null!==r&&ho(r),So(t,e.child,null,n),(e=Ul(t,t.pendingProps.children)).flags|=2,t.memoizedState=null,e}function Bl(e,t,n){e.lanes|=t;var r=e.alternate;null!==r&&(r.lanes|=t),Ro(e.return,t,n)}function zl(e,t,n,r,a){var o=e.memoizedState;null===o?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a}:(o.isBackwards=t,o.rendering=null,o.renderingStartTime=0,o.last=r,o.tail=n,o.tailMode=a)}function $l(e,t,n){var r=t.pendingProps,a=r.revealOrder,o=r.tail;if(El(e,t,r.children,n),2&(r=ei.current))r=1&r|2,t.flags|=128;else{if(null!==e&&128&e.flags)e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&Bl(e,n,t);else if(19===e.tag)Bl(e,n,t);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(xa(ei,r),1&t.mode)switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===ti(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),zl(t,!1,a,n,o);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===ti(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}zl(t,!0,n,null,o);break;case"together":zl(t,!1,null,null,void 0);break;default:t.memoizedState=null}else t.memoizedState=null;return t.child}function Hl(e,t){!(1&t.mode)&&null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2)}function Gl(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),Ms|=t.lanes,!(n&t.childLanes))return null;if(null!==e&&t.child!==e.child)throw Error(o(153));if(null!==t.child){for(n=Lu(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Lu(e,e.pendingProps)).return=t;n.sibling=null}return t.child}function Vl(e,t){if(!ao)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function Wl(e){var t=null!==e.alternate&&e.alternate.child===e.child,n=0,r=0;if(t)for(var a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=14680064&a.subtreeFlags,r|=14680064&a.flags,a.return=e,a=a.sibling;else for(a=e.child;null!==a;)n|=a.lanes|a.childLanes,r|=a.subtreeFlags,r|=a.flags,a.return=e,a=a.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function Yl(e,t,n){var r=t.pendingProps;switch(to(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Wl(t),null;case 1:case 17:return Ia(t.type)&&La(),Wl(t),null;case 3:return r=t.stateNode,Qo(),Ta(Ra),Ta(Ca),ri(),r.pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(fo(t)?t.flags|=4:null===e||e.memoizedState.isDehydrated&&!(256&t.flags)||(t.flags|=1024,null!==oo&&(iu(oo),oo=null))),Il(e,t),Wl(t),null;case 5:Jo(t);var a=qo(Ko.current);if(n=t.type,null!==e&&null!=t.stateNode)Ll(e,t,n,r,a),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!r){if(null===t.stateNode)throw Error(o(166));return Wl(t),null}if(e=qo(Wo.current),fo(t)){r=t.stateNode,n=t.type;var i=t.memoizedProps;switch(r[fa]=t,r[pa]=i,e=!!(1&t.mode),n){case"dialog":Fr("cancel",r),Fr("close",r);break;case"iframe":case"object":case"embed":Fr("load",r);break;case"video":case"audio":for(a=0;a<Dr.length;a++)Fr(Dr[a],r);break;case"source":Fr("error",r);break;case"img":case"image":case"link":Fr("error",r),Fr("load",r);break;case"details":Fr("toggle",r);break;case"input":X(r,i),Fr("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!i.multiple},Fr("invalid",r);break;case"textarea":ae(r,i),Fr("invalid",r)}for(var s in be(n,i),a=null,i)if(i.hasOwnProperty(s)){var u=i[s];"children"===s?"string"==typeof u?r.textContent!==u&&(!0!==i.suppressHydrationWarning&&Zr(r.textContent,u,e),a=["children",u]):"number"==typeof u&&r.textContent!==""+u&&(!0!==i.suppressHydrationWarning&&Zr(r.textContent,u,e),a=["children",""+u]):l.hasOwnProperty(s)&&null!=u&&"onScroll"===s&&Fr("scroll",r)}switch(n){case"input":W(r),J(r,i,!0);break;case"textarea":W(r),ie(r);break;case"select":case"option":break;default:"function"==typeof i.onClick&&(r.onclick=Jr)}r=a,t.updateQueue=r,null!==r&&(t.flags|=4)}else{s=9===a.nodeType?a:a.ownerDocument,"http://www.w3.org/1999/xhtml"===e&&(e=le(n)),"http://www.w3.org/1999/xhtml"===e?"script"===n?((e=s.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=s.createElement(n,{is:r.is}):(e=s.createElement(n),"select"===n&&(s=e,r.multiple?s.multiple=!0:r.size&&(s.size=r.size))):e=s.createElementNS(e,n),e[fa]=t,e[pa]=r,Nl(e,t,!1,!1),t.stateNode=e;e:{switch(s=ve(n,r),n){case"dialog":Fr("cancel",e),Fr("close",e),a=r;break;case"iframe":case"object":case"embed":Fr("load",e),a=r;break;case"video":case"audio":for(a=0;a<Dr.length;a++)Fr(Dr[a],e);a=r;break;case"source":Fr("error",e),a=r;break;case"img":case"image":case"link":Fr("error",e),Fr("load",e),a=r;break;case"details":Fr("toggle",e),a=r;break;case"input":X(e,r),a=q(e,r),Fr("invalid",e);break;case"option":default:a=r;break;case"select":e._wrapperState={wasMultiple:!!r.multiple},a=j({},r,{value:void 0}),Fr("invalid",e);break;case"textarea":ae(e,r),a=re(e,r),Fr("invalid",e)}for(i in be(n,a),u=a)if(u.hasOwnProperty(i)){var c=u[i];"style"===i?ge(e,c):"dangerouslySetInnerHTML"===i?null!=(c=c?c.__html:void 0)&&de(e,c):"children"===i?"string"==typeof c?("textarea"!==n||""!==c)&&fe(e,c):"number"==typeof c&&fe(e,""+c):"suppressContentEditableWarning"!==i&&"suppressHydrationWarning"!==i&&"autoFocus"!==i&&(l.hasOwnProperty(i)?null!=c&&"onScroll"===i&&Fr("scroll",e):null!=c&&v(e,i,c,s))}switch(n){case"input":W(e),J(e,r,!1);break;case"textarea":W(e),ie(e);break;case"option":null!=r.value&&e.setAttribute("value",""+G(r.value));break;case"select":e.multiple=!!r.multiple,null!=(i=r.value)?ne(e,!!r.multiple,i,!1):null!=r.defaultValue&&ne(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof a.onClick&&(e.onclick=Jr)}switch(n){case"button":case"input":case"select":case"textarea":r=!!r.autoFocus;break e;case"img":r=!0;break e;default:r=!1}}r&&(t.flags|=4)}null!==t.ref&&(t.flags|=512,t.flags|=2097152)}return Wl(t),null;case 6:if(e&&null!=t.stateNode)Pl(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(o(166));if(n=qo(Ko.current),qo(Wo.current),fo(t)){if(r=t.stateNode,n=t.memoizedProps,r[fa]=t,(i=r.nodeValue!==n)&&null!==(e=no))switch(e.tag){case 3:Zr(r.nodeValue,n,!!(1&e.mode));break;case 5:!0!==e.memoizedProps.suppressHydrationWarning&&Zr(r.nodeValue,n,!!(1&e.mode))}i&&(t.flags|=4)}else(r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[fa]=t,t.stateNode=r}return Wl(t),null;case 13:if(Ta(ei),r=t.memoizedState,null===e||null!==e.memoizedState&&null!==e.memoizedState.dehydrated){if(ao&&null!==ro&&1&t.mode&&!(128&t.flags))po(),mo(),t.flags|=98560,i=!1;else if(i=fo(t),null!==r&&null!==r.dehydrated){if(null===e){if(!i)throw Error(o(318));if(!(i=null!==(i=t.memoizedState)?i.dehydrated:null))throw Error(o(317));i[fa]=t}else mo(),!(128&t.flags)&&(t.memoizedState=null),t.flags|=4;Wl(t),i=!1}else null!==oo&&(iu(oo),oo=null),i=!0;if(!i)return 65536&t.flags?t:null}return 128&t.flags?(t.lanes=n,t):((r=null!==r)!==(null!==e&&null!==e.memoizedState)&&r&&(t.child.flags|=8192,1&t.mode&&(null===e||1&ei.current?0===Ps&&(Ps=3):hu())),null!==t.updateQueue&&(t.flags|=4),Wl(t),null);case 4:return Qo(),Il(e,t),null===e&&$r(t.stateNode.containerInfo),Wl(t),null;case 10:return Co(t.type._context),Wl(t),null;case 19:if(Ta(ei),null===(i=t.memoizedState))return Wl(t),null;if(r=!!(128&t.flags),null===(s=i.rendering))if(r)Vl(i,!1);else{if(0!==Ps||null!==e&&128&e.flags)for(e=t.child;null!==e;){if(null!==(s=ti(e))){for(t.flags|=128,Vl(i,!1),null!==(r=s.updateQueue)&&(t.updateQueue=r,t.flags|=4),t.subtreeFlags=0,r=n,n=t.child;null!==n;)e=r,(i=n).flags&=14680066,null===(s=i.alternate)?(i.childLanes=0,i.lanes=e,i.child=null,i.subtreeFlags=0,i.memoizedProps=null,i.memoizedState=null,i.updateQueue=null,i.dependencies=null,i.stateNode=null):(i.childLanes=s.childLanes,i.lanes=s.lanes,i.child=s.child,i.subtreeFlags=0,i.deletions=null,i.memoizedProps=s.memoizedProps,i.memoizedState=s.memoizedState,i.updateQueue=s.updateQueue,i.type=s.type,e=s.dependencies,i.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return xa(ei,1&ei.current|2),t.child}e=e.sibling}null!==i.tail&&Qe()>$s&&(t.flags|=128,r=!0,Vl(i,!1),t.lanes=4194304)}else{if(!r)if(null!==(e=ti(s))){if(t.flags|=128,r=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),Vl(i,!0),null===i.tail&&"hidden"===i.tailMode&&!s.alternate&&!ao)return Wl(t),null}else 2*Qe()-i.renderingStartTime>$s&&1073741824!==n&&(t.flags|=128,r=!0,Vl(i,!1),t.lanes=4194304);i.isBackwards?(s.sibling=t.child,t.child=s):(null!==(n=i.last)?n.sibling=s:t.child=s,i.last=s)}return null!==i.tail?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=Qe(),t.sibling=null,n=ei.current,xa(ei,r?1&n|2:1&n),t):(Wl(t),null);case 22:case 23:return du(),r=null!==t.memoizedState,null!==e&&null!==e.memoizedState!==r&&(t.flags|=8192),r&&1&t.mode?!!(1073741824&Is)&&(Wl(t),6&t.subtreeFlags&&(t.flags|=8192)):Wl(t),null;case 24:case 25:return null}throw Error(o(156,t.tag))}function Kl(e,t){switch(to(t),t.tag){case 1:return Ia(t.type)&&La(),65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 3:return Qo(),Ta(Ra),Ta(Ca),ri(),65536&(e=t.flags)&&!(128&e)?(t.flags=-65537&e|128,t):null;case 5:return Jo(t),null;case 13:if(Ta(ei),null!==(e=t.memoizedState)&&null!==e.dehydrated){if(null===t.alternate)throw Error(o(340));mo()}return 65536&(e=t.flags)?(t.flags=-65537&e|128,t):null;case 19:return Ta(ei),null;case 4:return Qo(),null;case 10:return Co(t.type._context),null;case 22:case 23:return du(),null;default:return null}}Nl=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Il=function(){},Ll=function(e,t,n,r){var a=e.memoizedProps;if(a!==r){e=t.stateNode,qo(Wo.current);var o,i=null;switch(n){case"input":a=q(e,a),r=q(e,r),i=[];break;case"select":a=j({},a,{value:void 0}),r=j({},r,{value:void 0}),i=[];break;case"textarea":a=re(e,a),r=re(e,r),i=[];break;default:"function"!=typeof a.onClick&&"function"==typeof r.onClick&&(e.onclick=Jr)}for(c in be(n,r),n=null,a)if(!r.hasOwnProperty(c)&&a.hasOwnProperty(c)&&null!=a[c])if("style"===c){var s=a[c];for(o in s)s.hasOwnProperty(o)&&(n||(n={}),n[o]="")}else"dangerouslySetInnerHTML"!==c&&"children"!==c&&"suppressContentEditableWarning"!==c&&"suppressHydrationWarning"!==c&&"autoFocus"!==c&&(l.hasOwnProperty(c)?i||(i=[]):(i=i||[]).push(c,null));for(c in r){var u=r[c];if(s=null!=a?a[c]:void 0,r.hasOwnProperty(c)&&u!==s&&(null!=u||null!=s))if("style"===c)if(s){for(o in s)!s.hasOwnProperty(o)||u&&u.hasOwnProperty(o)||(n||(n={}),n[o]="");for(o in u)u.hasOwnProperty(o)&&s[o]!==u[o]&&(n||(n={}),n[o]=u[o])}else n||(i||(i=[]),i.push(c,n)),n=u;else"dangerouslySetInnerHTML"===c?(u=u?u.__html:void 0,s=s?s.__html:void 0,null!=u&&s!==u&&(i=i||[]).push(c,u)):"children"===c?"string"!=typeof u&&"number"!=typeof u||(i=i||[]).push(c,""+u):"suppressContentEditableWarning"!==c&&"suppressHydrationWarning"!==c&&(l.hasOwnProperty(c)?(null!=u&&"onScroll"===c&&Fr("scroll",e),i||s===u||(i=[])):(i=i||[]).push(c,u))}n&&(i=i||[]).push("style",n);var c=i;(t.updateQueue=c)&&(t.flags|=4)}},Pl=function(e,t,n,r){n!==r&&(t.flags|=4)};var ql=!1,Xl=!1,Ql="function"==typeof WeakSet?WeakSet:Set,Zl=null;function Jl(e,t){var n=e.ref;if(null!==n)if("function"==typeof n)try{n(null)}catch(r){ku(e,t,r)}else n.current=null}function es(e,t,n){try{n()}catch(r){ku(e,t,r)}}var ts=!1;function ns(e,t,n){var r=t.updateQueue;if(null!==(r=null!==r?r.lastEffect:null)){var a=r=r.next;do{if((a.tag&e)===e){var o=a.destroy;a.destroy=void 0,void 0!==o&&es(t,n,o)}a=a.next}while(a!==r)}}function rs(e,t){if(null!==(t=null!==(t=t.updateQueue)?t.lastEffect:null)){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function as(e){var t=e.ref;if(null!==t){var n=e.stateNode;e.tag,e=n,"function"==typeof t?t(e):t.current=e}}function os(e){var t=e.alternate;null!==t&&(e.alternate=null,os(t)),e.child=null,e.deletions=null,e.sibling=null,5===e.tag&&(null!==(t=e.stateNode)&&(delete t[fa],delete t[pa],delete t[ha],delete t[ga],delete t[ya])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function is(e){return 5===e.tag||3===e.tag||4===e.tag}function ls(e){e:for(;;){for(;null===e.sibling;){if(null===e.return||is(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;5!==e.tag&&6!==e.tag&&18!==e.tag;){if(2&e.flags)continue e;if(null===e.child||4===e.tag)continue e;e.child.return=e,e=e.child}if(!(2&e.flags))return e.stateNode}}function ss(e,t,n){var r=e.tag;if(5===r||6===r)e=e.stateNode,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=Jr));else if(4!==r&&null!==(e=e.child))for(ss(e,t,n),e=e.sibling;null!==e;)ss(e,t,n),e=e.sibling}function us(e,t,n){var r=e.tag;if(5===r||6===r)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(us(e,t,n),e=e.sibling;null!==e;)us(e,t,n),e=e.sibling}var cs=null,ds=!1;function fs(e,t,n){for(n=n.child;null!==n;)ps(e,t,n),n=n.sibling}function ps(e,t,n){if(ot&&"function"==typeof ot.onCommitFiberUnmount)try{ot.onCommitFiberUnmount(at,n)}catch(l){}switch(n.tag){case 5:Xl||Jl(n,t);case 6:var r=cs,a=ds;cs=null,fs(e,t,n),ds=a,null!==(cs=r)&&(ds?(e=cs,n=n.stateNode,8===e.nodeType?e.parentNode.removeChild(n):e.removeChild(n)):cs.removeChild(n.stateNode));break;case 18:null!==cs&&(ds?(e=cs,n=n.stateNode,8===e.nodeType?sa(e.parentNode,n):1===e.nodeType&&sa(e,n),$t(e)):sa(cs,n.stateNode));break;case 4:r=cs,a=ds,cs=n.stateNode.containerInfo,ds=!0,fs(e,t,n),cs=r,ds=a;break;case 0:case 11:case 14:case 15:if(!Xl&&(null!==(r=n.updateQueue)&&null!==(r=r.lastEffect))){a=r=r.next;do{var o=a,i=o.destroy;o=o.tag,void 0!==i&&(2&o||4&o)&&es(n,t,i),a=a.next}while(a!==r)}fs(e,t,n);break;case 1:if(!Xl&&(Jl(n,t),"function"==typeof(r=n.stateNode).componentWillUnmount))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(l){ku(n,t,l)}fs(e,t,n);break;case 21:fs(e,t,n);break;case 22:1&n.mode?(Xl=(r=Xl)||null!==n.memoizedState,fs(e,t,n),Xl=r):fs(e,t,n);break;default:fs(e,t,n)}}function ms(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new Ql),t.forEach((function(t){var r=Cu.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function hs(e,t){var n=t.deletions;if(null!==n)for(var r=0;r<n.length;r++){var a=n[r];try{var i=e,l=t,s=l;e:for(;null!==s;){switch(s.tag){case 5:cs=s.stateNode,ds=!1;break e;case 3:case 4:cs=s.stateNode.containerInfo,ds=!0;break e}s=s.return}if(null===cs)throw Error(o(160));ps(i,l,a),cs=null,ds=!1;var u=a.alternate;null!==u&&(u.return=null),a.return=null}catch(c){ku(a,t,c)}}if(12854&t.subtreeFlags)for(t=t.child;null!==t;)gs(t,e),t=t.sibling}function gs(e,t){var n=e.alternate,r=e.flags;switch(e.tag){case 0:case 11:case 14:case 15:if(hs(t,e),ys(e),4&r){try{ns(3,e,e.return),rs(3,e)}catch(g){ku(e,e.return,g)}try{ns(5,e,e.return)}catch(g){ku(e,e.return,g)}}break;case 1:hs(t,e),ys(e),512&r&&null!==n&&Jl(n,n.return);break;case 5:if(hs(t,e),ys(e),512&r&&null!==n&&Jl(n,n.return),32&e.flags){var a=e.stateNode;try{fe(a,"")}catch(g){ku(e,e.return,g)}}if(4&r&&null!=(a=e.stateNode)){var i=e.memoizedProps,l=null!==n?n.memoizedProps:i,s=e.type,u=e.updateQueue;if(e.updateQueue=null,null!==u)try{"input"===s&&"radio"===i.type&&null!=i.name&&Q(a,i),ve(s,l);var c=ve(s,i);for(l=0;l<u.length;l+=2){var d=u[l],f=u[l+1];"style"===d?ge(a,f):"dangerouslySetInnerHTML"===d?de(a,f):"children"===d?fe(a,f):v(a,d,f,c)}switch(s){case"input":Z(a,i);break;case"textarea":oe(a,i);break;case"select":var p=a._wrapperState.wasMultiple;a._wrapperState.wasMultiple=!!i.multiple;var m=i.value;null!=m?ne(a,!!i.multiple,m,!1):p!==!!i.multiple&&(null!=i.defaultValue?ne(a,!!i.multiple,i.defaultValue,!0):ne(a,!!i.multiple,i.multiple?[]:"",!1))}a[pa]=i}catch(g){ku(e,e.return,g)}}break;case 6:if(hs(t,e),ys(e),4&r){if(null===e.stateNode)throw Error(o(162));a=e.stateNode,i=e.memoizedProps;try{a.nodeValue=i}catch(g){ku(e,e.return,g)}}break;case 3:if(hs(t,e),ys(e),4&r&&null!==n&&n.memoizedState.isDehydrated)try{$t(t.containerInfo)}catch(g){ku(e,e.return,g)}break;case 4:default:hs(t,e),ys(e);break;case 13:hs(t,e),ys(e),8192&(a=e.child).flags&&(i=null!==a.memoizedState,a.stateNode.isHidden=i,!i||null!==a.alternate&&null!==a.alternate.memoizedState||(zs=Qe())),4&r&&ms(e);break;case 22:if(d=null!==n&&null!==n.memoizedState,1&e.mode?(Xl=(c=Xl)||d,hs(t,e),Xl=c):hs(t,e),ys(e),8192&r){if(c=null!==e.memoizedState,(e.stateNode.isHidden=c)&&!d&&1&e.mode)for(Zl=e,d=e.child;null!==d;){for(f=Zl=d;null!==Zl;){switch(m=(p=Zl).child,p.tag){case 0:case 11:case 14:case 15:ns(4,p,p.return);break;case 1:Jl(p,p.return);var h=p.stateNode;if("function"==typeof h.componentWillUnmount){r=p,n=p.return;try{t=r,h.props=t.memoizedProps,h.state=t.memoizedState,h.componentWillUnmount()}catch(g){ku(r,n,g)}}break;case 5:Jl(p,p.return);break;case 22:if(null!==p.memoizedState){Ss(f);continue}}null!==m?(m.return=p,Zl=m):Ss(f)}d=d.sibling}e:for(d=null,f=e;;){if(5===f.tag){if(null===d){d=f;try{a=f.stateNode,c?"function"==typeof(i=a.style).setProperty?i.setProperty("display","none","important"):i.display="none":(s=f.stateNode,l=null!=(u=f.memoizedProps.style)&&u.hasOwnProperty("display")?u.display:null,s.style.display=he("display",l))}catch(g){ku(e,e.return,g)}}}else if(6===f.tag){if(null===d)try{f.stateNode.nodeValue=c?"":f.memoizedProps}catch(g){ku(e,e.return,g)}}else if((22!==f.tag&&23!==f.tag||null===f.memoizedState||f===e)&&null!==f.child){f.child.return=f,f=f.child;continue}if(f===e)break e;for(;null===f.sibling;){if(null===f.return||f.return===e)break e;d===f&&(d=null),f=f.return}d===f&&(d=null),f.sibling.return=f.return,f=f.sibling}}break;case 19:hs(t,e),ys(e),4&r&&ms(e);case 21:}}function ys(e){var t=e.flags;if(2&t){try{e:{for(var n=e.return;null!==n;){if(is(n)){var r=n;break e}n=n.return}throw Error(o(160))}switch(r.tag){case 5:var a=r.stateNode;32&r.flags&&(fe(a,""),r.flags&=-33),us(e,ls(e),a);break;case 3:case 4:var i=r.stateNode.containerInfo;ss(e,ls(e),i);break;default:throw Error(o(161))}}catch(l){ku(e,e.return,l)}e.flags&=-3}4096&t&&(e.flags&=-4097)}function bs(e,t,n){Zl=e,vs(e,t,n)}function vs(e,t,n){for(var r=!!(1&e.mode);null!==Zl;){var a=Zl,o=a.child;if(22===a.tag&&r){var i=null!==a.memoizedState||ql;if(!i){var l=a.alternate,s=null!==l&&null!==l.memoizedState||Xl;l=ql;var u=Xl;if(ql=i,(Xl=s)&&!u)for(Zl=a;null!==Zl;)s=(i=Zl).child,22===i.tag&&null!==i.memoizedState?_s(a):null!==s?(s.return=i,Zl=s):_s(a);for(;null!==o;)Zl=o,vs(o,t,n),o=o.sibling;Zl=a,ql=l,Xl=u}Es(e)}else 8772&a.subtreeFlags&&null!==o?(o.return=a,Zl=o):Es(e)}}function Es(e){for(;null!==Zl;){var t=Zl;if(8772&t.flags){var n=t.alternate;try{if(8772&t.flags)switch(t.tag){case 0:case 11:case 15:Xl||rs(5,t);break;case 1:var r=t.stateNode;if(4&t.flags&&!Xl)if(null===n)r.componentDidMount();else{var a=t.elementType===t.type?n.memoizedProps:nl(t.type,n.memoizedProps);r.componentDidUpdate(a,n.memoizedState,r.__reactInternalSnapshotBeforeUpdate)}var i=t.updateQueue;null!==i&&Go(t,i,r);break;case 3:var l=t.updateQueue;if(null!==l){if(n=null,null!==t.child)switch(t.child.tag){case 5:case 1:n=t.child.stateNode}Go(t,l,n)}break;case 5:var s=t.stateNode;if(null===n&&4&t.flags){n=s;var u=t.memoizedProps;switch(t.type){case"button":case"input":case"select":case"textarea":u.autoFocus&&n.focus();break;case"img":u.src&&(n.src=u.src)}}break;case 6:case 4:case 12:case 19:case 17:case 21:case 22:case 23:case 25:break;case 13:if(null===t.memoizedState){var c=t.alternate;if(null!==c){var d=c.memoizedState;if(null!==d){var f=d.dehydrated;null!==f&&$t(f)}}}break;default:throw Error(o(163))}Xl||512&t.flags&&as(t)}catch(p){ku(t,t.return,p)}}if(t===e){Zl=null;break}if(null!==(n=t.sibling)){n.return=t.return,Zl=n;break}Zl=t.return}}function Ss(e){for(;null!==Zl;){var t=Zl;if(t===e){Zl=null;break}var n=t.sibling;if(null!==n){n.return=t.return,Zl=n;break}Zl=t.return}}function _s(e){for(;null!==Zl;){var t=Zl;try{switch(t.tag){case 0:case 11:case 15:var n=t.return;try{rs(4,t)}catch(s){ku(t,n,s)}break;case 1:var r=t.stateNode;if("function"==typeof r.componentDidMount){var a=t.return;try{r.componentDidMount()}catch(s){ku(t,a,s)}}var o=t.return;try{as(t)}catch(s){ku(t,o,s)}break;case 5:var i=t.return;try{as(t)}catch(s){ku(t,i,s)}}}catch(s){ku(t,t.return,s)}if(t===e){Zl=null;break}var l=t.sibling;if(null!==l){l.return=t.return,Zl=l;break}Zl=t.return}}var ws,ks=Math.ceil,Ts=E.ReactCurrentDispatcher,xs=E.ReactCurrentOwner,As=E.ReactCurrentBatchConfig,Cs=0,Rs=null,Os=null,Ns=0,Is=0,Ls=ka(0),Ps=0,Ds=null,Ms=0,js=0,Us=0,Fs=null,Bs=null,zs=0,$s=1/0,Hs=null,Gs=!1,Vs=null,Ws=null,Ys=!1,Ks=null,qs=0,Xs=0,Qs=null,Zs=-1,Js=0;function eu(){return 6&Cs?Qe():-1!==Zs?Zs:Zs=Qe()}function tu(e){return 1&e.mode?2&Cs&&0!==Ns?Ns&-Ns:null!==go.transition?(0===Js&&(Js=ht()),Js):0!==(e=vt)?e:e=void 0===(e=window.event)?16:Xt(e.type):1}function nu(e,t,n,r){if(50<Xs)throw Xs=0,Qs=null,Error(o(185));yt(e,n,r),2&Cs&&e===Rs||(e===Rs&&(!(2&Cs)&&(js|=n),4===Ps&&lu(e,Ns)),ru(e,r),1===n&&0===Cs&&!(1&t.mode)&&($s=Qe()+500,Fa&&$a()))}function ru(e,t){var n=e.callbackNode;!function(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,a=e.expirationTimes,o=e.pendingLanes;0<o;){var i=31-it(o),l=1<<i,s=a[i];-1===s?l&n&&!(l&r)||(a[i]=pt(l,t)):s<=t&&(e.expiredLanes|=l),o&=~l}}(e,t);var r=ft(e,e===Rs?Ns:0);if(0===r)null!==n&&Ke(n),e.callbackNode=null,e.callbackPriority=0;else if(t=r&-r,e.callbackPriority!==t){if(null!=n&&Ke(n),1===t)0===e.tag?function(e){Fa=!0,za(e)}(su.bind(null,e)):za(su.bind(null,e)),ia((function(){!(6&Cs)&&$a()})),n=null;else{switch(Et(r)){case 1:n=Je;break;case 4:n=et;break;case 16:default:n=tt;break;case 536870912:n=rt}n=Ru(n,au.bind(null,e))}e.callbackPriority=t,e.callbackNode=n}}function au(e,t){if(Zs=-1,Js=0,6&Cs)throw Error(o(327));var n=e.callbackNode;if(_u()&&e.callbackNode!==n)return null;var r=ft(e,e===Rs?Ns:0);if(0===r)return null;if(30&r||r&e.expiredLanes||t)t=gu(e,r);else{t=r;var a=Cs;Cs|=2;var i=mu();for(Rs===e&&Ns===t||(Hs=null,$s=Qe()+500,fu(e,t));;)try{bu();break}catch(s){pu(e,s)}Ao(),Ts.current=i,Cs=a,null!==Os?t=0:(Rs=null,Ns=0,t=Ps)}if(0!==t){if(2===t&&(0!==(a=mt(e))&&(r=a,t=ou(e,a))),1===t)throw n=Ds,fu(e,0),lu(e,r),ru(e,Qe()),n;if(6===t)lu(e,r);else{if(a=e.current.alternate,!(30&r||function(e){for(var t=e;;){if(16384&t.flags){var n=t.updateQueue;if(null!==n&&null!==(n=n.stores))for(var r=0;r<n.length;r++){var a=n[r],o=a.getSnapshot;a=a.value;try{if(!lr(o(),a))return!1}catch(l){return!1}}}if(n=t.child,16384&t.subtreeFlags&&null!==n)n.return=t,t=n;else{if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return!0;t=t.return}t.sibling.return=t.return,t=t.sibling}}return!0}(a)||(t=gu(e,r),2===t&&(i=mt(e),0!==i&&(r=i,t=ou(e,i))),1!==t)))throw n=Ds,fu(e,0),lu(e,r),ru(e,Qe()),n;switch(e.finishedWork=a,e.finishedLanes=r,t){case 0:case 1:throw Error(o(345));case 2:case 5:Su(e,Bs,Hs);break;case 3:if(lu(e,r),(130023424&r)===r&&10<(t=zs+500-Qe())){if(0!==ft(e,0))break;if(((a=e.suspendedLanes)&r)!==r){eu(),e.pingedLanes|=e.suspendedLanes&a;break}e.timeoutHandle=ra(Su.bind(null,e,Bs,Hs),t);break}Su(e,Bs,Hs);break;case 4:if(lu(e,r),(4194240&r)===r)break;for(t=e.eventTimes,a=-1;0<r;){var l=31-it(r);i=1<<l,(l=t[l])>a&&(a=l),r&=~i}if(r=a,10<(r=(120>(r=Qe()-r)?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*ks(r/1960))-r)){e.timeoutHandle=ra(Su.bind(null,e,Bs,Hs),r);break}Su(e,Bs,Hs);break;default:throw Error(o(329))}}}return ru(e,Qe()),e.callbackNode===n?au.bind(null,e):null}function ou(e,t){var n=Fs;return e.current.memoizedState.isDehydrated&&(fu(e,t).flags|=256),2!==(e=gu(e,t))&&(t=Bs,Bs=n,null!==t&&iu(t)),e}function iu(e){null===Bs?Bs=e:Bs.push.apply(Bs,e)}function lu(e,t){for(t&=~Us,t&=~js,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-it(t),r=1<<n;e[n]=-1,t&=~r}}function su(e){if(6&Cs)throw Error(o(327));_u();var t=ft(e,0);if(!(1&t))return ru(e,Qe()),null;var n=gu(e,t);if(0!==e.tag&&2===n){var r=mt(e);0!==r&&(t=r,n=ou(e,r))}if(1===n)throw n=Ds,fu(e,0),lu(e,t),ru(e,Qe()),n;if(6===n)throw Error(o(345));return e.finishedWork=e.current.alternate,e.finishedLanes=t,Su(e,Bs,Hs),ru(e,Qe()),null}function uu(e,t){var n=Cs;Cs|=1;try{return e(t)}finally{0===(Cs=n)&&($s=Qe()+500,Fa&&$a())}}function cu(e){null!==Ks&&0===Ks.tag&&!(6&Cs)&&_u();var t=Cs;Cs|=1;var n=As.transition,r=vt;try{if(As.transition=null,vt=1,e)return e()}finally{vt=r,As.transition=n,!(6&(Cs=t))&&$a()}}function du(){Is=Ls.current,Ta(Ls)}function fu(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,aa(n)),null!==Os)for(n=Os.return;null!==n;){var r=n;switch(to(r),r.tag){case 1:null!=(r=r.type.childContextTypes)&&La();break;case 3:Qo(),Ta(Ra),Ta(Ca),ri();break;case 5:Jo(r);break;case 4:Qo();break;case 13:case 19:Ta(ei);break;case 10:Co(r.type._context);break;case 22:case 23:du()}n=n.return}if(Rs=e,Os=e=Lu(e.current,null),Ns=Is=t,Ps=0,Ds=null,Us=js=Ms=0,Bs=Fs=null,null!==Io){for(t=0;t<Io.length;t++)if(null!==(r=(n=Io[t]).interleaved)){n.interleaved=null;var a=r.next,o=n.pending;if(null!==o){var i=o.next;o.next=a,r.next=i}n.pending=r}Io=null}return e}function pu(e,t){for(;;){var n=Os;try{if(Ao(),ai.current=Zi,ci){for(var r=li.memoizedState;null!==r;){var a=r.queue;null!==a&&(a.pending=null),r=r.next}ci=!1}if(ii=0,ui=si=li=null,di=!1,fi=0,xs.current=null,null===n||null===n.return){Ps=1,Ds=t,Os=null;break}e:{var i=e,l=n.return,s=n,u=t;if(t=Ns,s.flags|=32768,null!==u&&"object"==typeof u&&"function"==typeof u.then){var c=u,d=s,f=d.tag;if(!(1&d.mode||0!==f&&11!==f&&15!==f)){var p=d.alternate;p?(d.updateQueue=p.updateQueue,d.memoizedState=p.memoizedState,d.lanes=p.lanes):(d.updateQueue=null,d.memoizedState=null)}var m=gl(l);if(null!==m){m.flags&=-257,yl(m,l,s,0,t),1&m.mode&&hl(i,c,t),u=c;var h=(t=m).updateQueue;if(null===h){var g=new Set;g.add(u),t.updateQueue=g}else h.add(u);break e}if(!(1&t)){hl(i,c,t),hu();break e}u=Error(o(426))}else if(ao&&1&s.mode){var y=gl(l);if(null!==y){!(65536&y.flags)&&(y.flags|=256),yl(y,l,s,0,t),ho(ul(u,s));break e}}i=u=ul(u,s),4!==Ps&&(Ps=2),null===Fs?Fs=[i]:Fs.push(i),i=l;do{switch(i.tag){case 3:i.flags|=65536,t&=-t,i.lanes|=t,$o(i,pl(0,u,t));break e;case 1:s=u;var b=i.type,v=i.stateNode;if(!(128&i.flags||"function"!=typeof b.getDerivedStateFromError&&(null===v||"function"!=typeof v.componentDidCatch||null!==Ws&&Ws.has(v)))){i.flags|=65536,t&=-t,i.lanes|=t,$o(i,ml(i,s,t));break e}}i=i.return}while(null!==i)}Eu(n)}catch(E){t=E,Os===n&&null!==n&&(Os=n=n.return);continue}break}}function mu(){var e=Ts.current;return Ts.current=Zi,null===e?Zi:e}function hu(){0!==Ps&&3!==Ps&&2!==Ps||(Ps=4),null===Rs||!(268435455&Ms)&&!(268435455&js)||lu(Rs,Ns)}function gu(e,t){var n=Cs;Cs|=2;var r=mu();for(Rs===e&&Ns===t||(Hs=null,fu(e,t));;)try{yu();break}catch(a){pu(e,a)}if(Ao(),Cs=n,Ts.current=r,null!==Os)throw Error(o(261));return Rs=null,Ns=0,Ps}function yu(){for(;null!==Os;)vu(Os)}function bu(){for(;null!==Os&&!qe();)vu(Os)}function vu(e){var t=ws(e.alternate,e,Is);e.memoizedProps=e.pendingProps,null===t?Eu(e):Os=t,xs.current=null}function Eu(e){var t=e;do{var n=t.alternate;if(e=t.return,32768&t.flags){if(null!==(n=Kl(n,t)))return n.flags&=32767,void(Os=n);if(null===e)return Ps=6,void(Os=null);e.flags|=32768,e.subtreeFlags=0,e.deletions=null}else if(null!==(n=Yl(n,t,Is)))return void(Os=n);if(null!==(t=t.sibling))return void(Os=t);Os=t=e}while(null!==t);0===Ps&&(Ps=5)}function Su(e,t,n){var r=vt,a=As.transition;try{As.transition=null,vt=1,function(e,t,n,r){do{_u()}while(null!==Ks);if(6&Cs)throw Error(o(327));n=e.finishedWork;var a=e.finishedLanes;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(o(177));e.callbackNode=null,e.callbackPriority=0;var i=n.lanes|n.childLanes;if(function(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0<n;){var a=31-it(n),o=1<<a;t[a]=0,r[a]=-1,e[a]=-1,n&=~o}}(e,i),e===Rs&&(Os=Rs=null,Ns=0),!(2064&n.subtreeFlags)&&!(2064&n.flags)||Ys||(Ys=!0,Ru(tt,(function(){return _u(),null}))),i=!!(15990&n.flags),!!(15990&n.subtreeFlags)||i){i=As.transition,As.transition=null;var l=vt;vt=1;var s=Cs;Cs|=4,xs.current=null,function(e,t){if(ea=Gt,pr(e=fr())){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{var r=(n=(n=e.ownerDocument)&&n.defaultView||window).getSelection&&n.getSelection();if(r&&0!==r.rangeCount){n=r.anchorNode;var a=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch(S){n=null;break e}var l=0,s=-1,u=-1,c=0,d=0,f=e,p=null;t:for(;;){for(var m;f!==n||0!==a&&3!==f.nodeType||(s=l+a),f!==i||0!==r&&3!==f.nodeType||(u=l+r),3===f.nodeType&&(l+=f.nodeValue.length),null!==(m=f.firstChild);)p=f,f=m;for(;;){if(f===e)break t;if(p===n&&++c===a&&(s=l),p===i&&++d===r&&(u=l),null!==(m=f.nextSibling))break;p=(f=p).parentNode}f=m}n=-1===s||-1===u?null:{start:s,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(ta={focusedElem:e,selectionRange:n},Gt=!1,Zl=t;null!==Zl;)if(e=(t=Zl).child,1028&t.subtreeFlags&&null!==e)e.return=t,Zl=e;else for(;null!==Zl;){t=Zl;try{var h=t.alternate;if(1024&t.flags)switch(t.tag){case 0:case 11:case 15:case 5:case 6:case 4:case 17:break;case 1:if(null!==h){var g=h.memoizedProps,y=h.memoizedState,b=t.stateNode,v=b.getSnapshotBeforeUpdate(t.elementType===t.type?g:nl(t.type,g),y);b.__reactInternalSnapshotBeforeUpdate=v}break;case 3:var E=t.stateNode.containerInfo;1===E.nodeType?E.textContent="":9===E.nodeType&&E.documentElement&&E.removeChild(E.documentElement);break;default:throw Error(o(163))}}catch(S){ku(t,t.return,S)}if(null!==(e=t.sibling)){e.return=t.return,Zl=e;break}Zl=t.return}h=ts,ts=!1}(e,n),gs(n,e),mr(ta),Gt=!!ea,ta=ea=null,e.current=n,bs(n,e,a),Xe(),Cs=s,vt=l,As.transition=i}else e.current=n;if(Ys&&(Ys=!1,Ks=e,qs=a),i=e.pendingLanes,0===i&&(Ws=null),function(e){if(ot&&"function"==typeof ot.onCommitFiberRoot)try{ot.onCommitFiberRoot(at,e,void 0,!(128&~e.current.flags))}catch(t){}}(n.stateNode),ru(e,Qe()),null!==t)for(r=e.onRecoverableError,n=0;n<t.length;n++)a=t[n],r(a.value,{componentStack:a.stack,digest:a.digest});if(Gs)throw Gs=!1,e=Vs,Vs=null,e;!!(1&qs)&&0!==e.tag&&_u(),i=e.pendingLanes,1&i?e===Qs?Xs++:(Xs=0,Qs=e):Xs=0,$a()}(e,t,n,r)}finally{As.transition=a,vt=r}return null}function _u(){if(null!==Ks){var e=Et(qs),t=As.transition,n=vt;try{if(As.transition=null,vt=16>e?16:e,null===Ks)var r=!1;else{if(e=Ks,Ks=null,qs=0,6&Cs)throw Error(o(331));var a=Cs;for(Cs|=4,Zl=e.current;null!==Zl;){var i=Zl,l=i.child;if(16&Zl.flags){var s=i.deletions;if(null!==s){for(var u=0;u<s.length;u++){var c=s[u];for(Zl=c;null!==Zl;){var d=Zl;switch(d.tag){case 0:case 11:case 15:ns(8,d,i)}var f=d.child;if(null!==f)f.return=d,Zl=f;else for(;null!==Zl;){var p=(d=Zl).sibling,m=d.return;if(os(d),d===c){Zl=null;break}if(null!==p){p.return=m,Zl=p;break}Zl=m}}}var h=i.alternate;if(null!==h){var g=h.child;if(null!==g){h.child=null;do{var y=g.sibling;g.sibling=null,g=y}while(null!==g)}}Zl=i}}if(2064&i.subtreeFlags&&null!==l)l.return=i,Zl=l;else e:for(;null!==Zl;){if(2048&(i=Zl).flags)switch(i.tag){case 0:case 11:case 15:ns(9,i,i.return)}var b=i.sibling;if(null!==b){b.return=i.return,Zl=b;break e}Zl=i.return}}var v=e.current;for(Zl=v;null!==Zl;){var E=(l=Zl).child;if(2064&l.subtreeFlags&&null!==E)E.return=l,Zl=E;else e:for(l=v;null!==Zl;){if(2048&(s=Zl).flags)try{switch(s.tag){case 0:case 11:case 15:rs(9,s)}}catch(_){ku(s,s.return,_)}if(s===l){Zl=null;break e}var S=s.sibling;if(null!==S){S.return=s.return,Zl=S;break e}Zl=s.return}}if(Cs=a,$a(),ot&&"function"==typeof ot.onPostCommitFiberRoot)try{ot.onPostCommitFiberRoot(at,e)}catch(_){}r=!0}return r}finally{vt=n,As.transition=t}}return!1}function wu(e,t,n){e=Bo(e,t=pl(0,t=ul(n,t),1),1),t=eu(),null!==e&&(yt(e,1,t),ru(e,t))}function ku(e,t,n){if(3===e.tag)wu(e,e,n);else for(;null!==t;){if(3===t.tag){wu(t,e,n);break}if(1===t.tag){var r=t.stateNode;if("function"==typeof t.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Ws||!Ws.has(r))){t=Bo(t,e=ml(t,e=ul(n,e),1),1),e=eu(),null!==t&&(yt(t,1,e),ru(t,e));break}}t=t.return}}function Tu(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=eu(),e.pingedLanes|=e.suspendedLanes&n,Rs===e&&(Ns&n)===n&&(4===Ps||3===Ps&&(130023424&Ns)===Ns&&500>Qe()-zs?fu(e,0):Us|=n),ru(e,t)}function xu(e,t){0===t&&(1&e.mode?(t=ct,!(130023424&(ct<<=1))&&(ct=4194304)):t=1);var n=eu();null!==(e=Do(e,t))&&(yt(e,t,n),ru(e,n))}function Au(e){var t=e.memoizedState,n=0;null!==t&&(n=t.retryLane),xu(e,n)}function Cu(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,a=e.memoizedState;null!==a&&(n=a.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(o(314))}null!==r&&r.delete(t),xu(e,n)}function Ru(e,t){return Ye(e,t)}function Ou(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Nu(e,t,n,r){return new Ou(e,t,n,r)}function Iu(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Lu(e,t){var n=e.alternate;return null===n?((n=Nu(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=14680064&e.flags,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Pu(e,t,n,r,a,i){var l=2;if(r=e,"function"==typeof e)Iu(e)&&(l=1);else if("string"==typeof e)l=5;else e:switch(e){case w:return Du(n.children,a,i,t);case k:l=8,a|=8;break;case T:return(e=Nu(12,n,t,2|a)).elementType=T,e.lanes=i,e;case R:return(e=Nu(13,n,t,a)).elementType=R,e.lanes=i,e;case O:return(e=Nu(19,n,t,a)).elementType=O,e.lanes=i,e;case L:return Mu(n,a,i,t);default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case x:l=10;break e;case A:l=9;break e;case C:l=11;break e;case N:l=14;break e;case I:l=16,r=null;break e}throw Error(o(130,null==e?e:typeof e,""))}return(t=Nu(l,n,t,a)).elementType=e,t.type=r,t.lanes=i,t}function Du(e,t,n,r){return(e=Nu(7,e,r,t)).lanes=n,e}function Mu(e,t,n,r){return(e=Nu(22,e,r,t)).elementType=L,e.lanes=n,e.stateNode={isHidden:!1},e}function ju(e,t,n){return(e=Nu(6,e,null,t)).lanes=n,e}function Uu(e,t,n){return(t=Nu(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Fu(e,t,n,r,a){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=gt(0),this.expirationTimes=gt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=gt(0),this.identifierPrefix=r,this.onRecoverableError=a,this.mutableSourceEagerHydrationData=null}function Bu(e,t,n,r,a,o,i,l,s){return e=new Fu(e,t,n,l,s),1===t?(t=1,!0===o&&(t|=8)):t=0,o=Nu(3,null,null,t),e.current=o,o.stateNode=e,o.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},jo(o),e}function zu(e){if(!e)return Aa;e:{if($e(e=e._reactInternals)!==e||1!==e.tag)throw Error(o(170));var t=e;do{switch(t.tag){case 3:t=t.stateNode.context;break e;case 1:if(Ia(t.type)){t=t.stateNode.__reactInternalMemoizedMergedChildContext;break e}}t=t.return}while(null!==t);throw Error(o(171))}if(1===e.tag){var n=e.type;if(Ia(n))return Da(e,n,t)}return t}function $u(e,t,n,r,a,o,i,l,s){return(e=Bu(n,r,!0,e,0,o,0,l,s)).context=zu(null),n=e.current,(o=Fo(r=eu(),a=tu(n))).callback=null!=t?t:null,Bo(n,o,a),e.current.lanes=a,yt(e,a,r),ru(e,r),e}function Hu(e,t,n,r){var a=t.current,o=eu(),i=tu(a);return n=zu(n),null===t.context?t.context=n:t.pendingContext=n,(t=Fo(o,i)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),null!==(e=Bo(a,t,i))&&(nu(e,a,i,o),zo(e,a,i)),i}function Gu(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function Vu(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function Wu(e,t){Vu(e,t),(e=e.alternate)&&Vu(e,t)}ws=function(e,t,n){if(null!==e)if(e.memoizedProps!==t.pendingProps||Ra.current)vl=!0;else{if(!(e.lanes&n||128&t.flags))return vl=!1,function(e,t,n){switch(t.tag){case 3:Rl(t),mo();break;case 5:Zo(t);break;case 1:Ia(t.type)&&Ma(t);break;case 4:Xo(t,t.stateNode.containerInfo);break;case 10:var r=t.type._context,a=t.memoizedProps.value;xa(wo,r._currentValue),r._currentValue=a;break;case 13:if(null!==(r=t.memoizedState))return null!==r.dehydrated?(xa(ei,1&ei.current),t.flags|=128,null):n&t.child.childLanes?jl(e,t,n):(xa(ei,1&ei.current),null!==(e=Gl(e,t,n))?e.sibling:null);xa(ei,1&ei.current);break;case 19:if(r=!!(n&t.childLanes),128&e.flags){if(r)return $l(e,t,n);t.flags|=128}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),xa(ei,ei.current),r)break;return null;case 22:case 23:return t.lanes=0,kl(e,t,n)}return Gl(e,t,n)}(e,t,n);vl=!!(131072&e.flags)}else vl=!1,ao&&1048576&t.flags&&Ja(t,Wa,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Hl(e,t),e=t.pendingProps;var a=Na(t,Ca.current);Oo(t,n),a=gi(null,t,r,e,a,n);var i=yi();return t.flags|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Ia(r)?(i=!0,Ma(t)):i=!1,t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,jo(t),a.updater=al,t.stateNode=a,a._reactInternals=t,sl(t,r,e,n),t=Cl(null,t,r,!0,i,n)):(t.tag=0,ao&&i&&eo(t),El(null,t,a,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Hl(e,t),e=t.pendingProps,r=(a=r._init)(r._payload),t.type=r,a=t.tag=function(e){if("function"==typeof e)return Iu(e)?1:0;if(null!=e){if((e=e.$$typeof)===C)return 11;if(e===N)return 14}return 2}(r),e=nl(r,e),a){case 0:t=xl(null,t,r,e,n);break e;case 1:t=Al(null,t,r,e,n);break e;case 11:t=Sl(null,t,r,e,n);break e;case 14:t=_l(null,t,r,nl(r.type,e),n);break e}throw Error(o(306,r,""))}return t;case 0:return r=t.type,a=t.pendingProps,xl(e,t,r,a=t.elementType===r?a:nl(r,a),n);case 1:return r=t.type,a=t.pendingProps,Al(e,t,r,a=t.elementType===r?a:nl(r,a),n);case 3:e:{if(Rl(t),null===e)throw Error(o(387));r=t.pendingProps,a=(i=t.memoizedState).element,Uo(e,t),Ho(t,r,null,n);var l=t.memoizedState;if(r=l.element,i.isDehydrated){if(i={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=i,t.memoizedState=i,256&t.flags){t=Ol(e,t,r,n,a=ul(Error(o(423)),t));break e}if(r!==a){t=Ol(e,t,r,n,a=ul(Error(o(424)),t));break e}for(ro=ua(t.stateNode.containerInfo.firstChild),no=t,ao=!0,oo=null,n=_o(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|4096,n=n.sibling}else{if(mo(),r===a){t=Gl(e,t,n);break e}El(e,t,r,n)}t=t.child}return t;case 5:return Zo(t),null===e&&uo(t),r=t.type,a=t.pendingProps,i=null!==e?e.memoizedProps:null,l=a.children,na(r,a)?l=null:null!==i&&na(r,i)&&(t.flags|=32),Tl(e,t),El(e,t,l,n),t.child;case 6:return null===e&&uo(t),null;case 13:return jl(e,t,n);case 4:return Xo(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=So(t,null,r,n):El(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,Sl(e,t,r,a=t.elementType===r?a:nl(r,a),n);case 7:return El(e,t,t.pendingProps,n),t.child;case 8:case 12:return El(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,a=t.pendingProps,i=t.memoizedProps,l=a.value,xa(wo,r._currentValue),r._currentValue=l,null!==i)if(lr(i.value,l)){if(i.children===a.children&&!Ra.current){t=Gl(e,t,n);break e}}else for(null!==(i=t.child)&&(i.return=t);null!==i;){var s=i.dependencies;if(null!==s){l=i.child;for(var u=s.firstContext;null!==u;){if(u.context===r){if(1===i.tag){(u=Fo(-1,n&-n)).tag=2;var c=i.updateQueue;if(null!==c){var d=(c=c.shared).pending;null===d?u.next=u:(u.next=d.next,d.next=u),c.pending=u}}i.lanes|=n,null!==(u=i.alternate)&&(u.lanes|=n),Ro(i.return,n,t),s.lanes|=n;break}u=u.next}}else if(10===i.tag)l=i.type===t.type?null:i.child;else if(18===i.tag){if(null===(l=i.return))throw Error(o(341));l.lanes|=n,null!==(s=l.alternate)&&(s.lanes|=n),Ro(l,n,t),l=i.sibling}else l=i.child;if(null!==l)l.return=i;else for(l=i;null!==l;){if(l===t){l=null;break}if(null!==(i=l.sibling)){i.return=l.return,l=i;break}l=l.return}i=l}El(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=t.pendingProps.children,Oo(t,n),r=r(a=No(a)),t.flags|=1,El(e,t,r,n),t.child;case 14:return a=nl(r=t.type,t.pendingProps),_l(e,t,r,a=nl(r.type,a),n);case 15:return wl(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:nl(r,a),Hl(e,t),t.tag=1,Ia(r)?(e=!0,Ma(t)):e=!1,Oo(t,n),il(t,r,a),sl(t,r,a,n),Cl(null,t,r,!0,e,n);case 19:return $l(e,t,n);case 22:return kl(e,t,n)}throw Error(o(156,t.tag))};var Yu="function"==typeof reportError?reportError:function(e){console.error(e)};function Ku(e){this._internalRoot=e}function qu(e){this._internalRoot=e}function Xu(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType)}function Qu(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function Zu(){}function Ju(e,t,n,r,a){var o=n._reactRootContainer;if(o){var i=o;if("function"==typeof a){var l=a;a=function(){var e=Gu(i);l.call(e)}}Hu(t,i,e,a)}else i=function(e,t,n,r,a){if(a){if("function"==typeof r){var o=r;r=function(){var e=Gu(i);o.call(e)}}var i=$u(t,r,e,0,null,!1,0,"",Zu);return e._reactRootContainer=i,e[ma]=i.current,$r(8===e.nodeType?e.parentNode:e),cu(),i}for(;a=e.lastChild;)e.removeChild(a);if("function"==typeof r){var l=r;r=function(){var e=Gu(s);l.call(e)}}var s=Bu(e,0,!1,null,0,!1,0,"",Zu);return e._reactRootContainer=s,e[ma]=s.current,$r(8===e.nodeType?e.parentNode:e),cu((function(){Hu(t,s,n,r)})),s}(n,t,e,a,r);return Gu(i)}qu.prototype.render=Ku.prototype.render=function(e){var t=this._internalRoot;if(null===t)throw Error(o(409));Hu(e,t,null,null)},qu.prototype.unmount=Ku.prototype.unmount=function(){var e=this._internalRoot;if(null!==e){this._internalRoot=null;var t=e.containerInfo;cu((function(){Hu(null,e,null,null)})),t[ma]=null}},qu.prototype.unstable_scheduleHydration=function(e){if(e){var t=kt();e={blockedOn:null,target:e,priority:t};for(var n=0;n<Lt.length&&0!==t&&t<Lt[n].priority;n++);Lt.splice(n,0,e),0===n&&jt(e)}},St=function(e){switch(e.tag){case 3:var t=e.stateNode;if(t.current.memoizedState.isDehydrated){var n=dt(t.pendingLanes);0!==n&&(bt(t,1|n),ru(t,Qe()),!(6&Cs)&&($s=Qe()+500,$a()))}break;case 13:cu((function(){var t=Do(e,1);if(null!==t){var n=eu();nu(t,e,1,n)}})),Wu(e,1)}},_t=function(e){if(13===e.tag){var t=Do(e,134217728);if(null!==t)nu(t,e,134217728,eu());Wu(e,134217728)}},wt=function(e){if(13===e.tag){var t=tu(e),n=Do(e,t);if(null!==n)nu(n,e,t,eu());Wu(e,t)}},kt=function(){return vt},Tt=function(e,t){var n=vt;try{return vt=e,t()}finally{vt=n}},_e=function(e,t,n){switch(t){case"input":if(Z(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=Sa(r);if(!a)throw Error(o(90));Y(r),Z(r,a)}}}break;case"textarea":oe(e,n);break;case"select":null!=(t=n.value)&&ne(e,!!n.multiple,t,!1)}},Ce=uu,Re=cu;var ec={usingClientEntryPoint:!1,Events:[va,Ea,Sa,xe,Ae,uu]},tc={findFiberByHostInstance:ba,bundleType:0,version:"18.3.1",rendererPackageName:"react-dom"},nc={bundleType:tc.bundleType,version:tc.version,rendererPackageName:tc.rendererPackageName,rendererConfig:tc.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setErrorHandler:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:E.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=Ve(e))?null:e.stateNode},findFiberByHostInstance:tc.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null,reconcilerVersion:"18.3.1-next-f1338f8080-20240426"};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var rc=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!rc.isDisabled&&rc.supportsFiber)try{at=rc.inject(nc),ot=rc}catch(ce){}}t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=ec,t.createPortal=function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!Xu(t))throw Error(o(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:_,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)},t.createRoot=function(e,t){if(!Xu(e))throw Error(o(299));var n=!1,r="",a=Yu;return null!=t&&(!0===t.unstable_strictMode&&(n=!0),void 0!==t.identifierPrefix&&(r=t.identifierPrefix),void 0!==t.onRecoverableError&&(a=t.onRecoverableError)),t=Bu(e,1,!1,null,0,n,0,r,a),e[ma]=t.current,$r(8===e.nodeType?e.parentNode:e),new Ku(t)},t.findDOMNode=function(e){if(null==e)return null;if(1===e.nodeType)return e;var t=e._reactInternals;if(void 0===t){if("function"==typeof e.render)throw Error(o(188));throw e=Object.keys(e).join(","),Error(o(268,e))}return e=null===(e=Ve(t))?null:e.stateNode},t.flushSync=function(e){return cu(e)},t.hydrate=function(e,t,n){if(!Qu(t))throw Error(o(200));return Ju(null,e,t,!0,n)},t.hydrateRoot=function(e,t,n){if(!Xu(e))throw Error(o(405));var r=null!=n&&n.hydratedSources||null,a=!1,i="",l=Yu;if(null!=n&&(!0===n.unstable_strictMode&&(a=!0),void 0!==n.identifierPrefix&&(i=n.identifierPrefix),void 0!==n.onRecoverableError&&(l=n.onRecoverableError)),t=$u(t,null,e,1,null!=n?n:null,a,0,i,l),e[ma]=t.current,$r(e),r)for(e=0;e<r.length;e++)a=(a=(n=r[e])._getVersion)(n._source),null==t.mutableSourceEagerHydrationData?t.mutableSourceEagerHydrationData=[n,a]:t.mutableSourceEagerHydrationData.push(n,a);return new qu(t)},t.render=function(e,t,n){if(!Qu(t))throw Error(o(200));return Ju(null,e,t,!1,n)},t.unmountComponentAtNode=function(e){if(!Qu(e))throw Error(o(40));return!!e._reactRootContainer&&(cu((function(){Ju(null,null,e,!1,(function(){e._reactRootContainer=null,e[ma]=null}))})),!0)},t.unstable_batchedUpdates=uu,t.unstable_renderSubtreeIntoContainer=function(e,t,n,r){if(!Qu(n))throw Error(o(200));if(null==e||void 0===e._reactInternals)throw Error(o(38));return Ju(e,t,n,!1,r)},t.version="18.3.1-next-f1338f8080-20240426"},5338:(e,t,n)=>{"use strict";var r=n(961);t.createRoot=r.createRoot,t.hydrateRoot=r.hydrateRoot},961:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(2551)},115:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function o(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var l,s,u,c;if(Array.isArray(e)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(!o(e[s],i[s]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;for(c=e.entries();!(s=c.next()).done;)if(!o(s.value[1],i.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(e[s]!==i[s])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof i.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof i.toString)return e.toString()===i.toString();if((l=(u=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(s=l;0!=s--;)if(!Object.prototype.hasOwnProperty.call(i,u[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!=s--;)if(("_owner"!==u[s]&&"__v"!==u[s]&&"__o"!==u[s]||!e.$$typeof)&&!o(e[u[s]],i[u[s]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return o(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},545:(e,t,n)=>{"use strict";n.d(t,{mg:()=>J,vd:()=>V});var r=n(6540),a=n(5556),o=n.n(a),i=n(115),l=n.n(i),s=n(311),u=n.n(s),c=n(2833),d=n.n(c);function f(){return f=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},f.apply(this,arguments)}function p(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function h(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t.indexOf(n=o[r])>=0||(a[n]=e[n]);return a}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},y={rel:["amphtml","canonical","alternate"]},b={type:["application/ld+json"]},v={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},E=Object.keys(g).map((function(e){return g[e]})),S={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},_=Object.keys(S).reduce((function(e,t){return e[S[t]]=t,e}),{}),w=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},k=function(e){var t=w(e,g.TITLE),n=w(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=w(e,"defaultTitle");return t||r||void 0},T=function(e){return w(e,"onChangeClientState")||function(){}},x=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return f({},e,t)}),{})},A=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var o=r[a].toLowerCase();if(-1!==e.indexOf(o)&&n[o])return t.concat(n)}return t}),[])},C=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,o=Object.keys(e),i=0;i<o.length;i+=1){var l=o[i],s=l.toLowerCase();-1===t.indexOf(s)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===s&&"stylesheet"===e[s].toLowerCase()||(n=s),-1===t.indexOf(l)||"innerHTML"!==l&&"cssText"!==l&&"itemprop"!==l||(n=l)}if(!n||!e[n])return!1;var u=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][u]&&(a[n][u]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var o=Object.keys(a),i=0;i<o.length;i+=1){var l=o[i],s=f({},r[l],a[l]);r[l]=s}return e}),[]).reverse()},R=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},O=function(e){return Array.isArray(e)?e.join(""):e},N=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},I=function(e,t){var n;return f({},e,((n={})[t]=void 0,n))},L=[g.NOSCRIPT,g.SCRIPT,g.STYLE],P=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},D=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[S[n]||n]=e[n],t}),t)},j=function(e,t){return t.map((function(t,n){var a,o=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=S[e]||e;"innerHTML"===n||"cssText"===n?o.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:o[n]=t[e]})),r.createElement(e,o)}))},U=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,o=M(n,a),[r.createElement(g.TITLE,o,e)];var e,n,a,o},toString:function(){return function(e,t,n,r){var a=D(n),o=O(t);return a?"<"+e+' data-rh="true" '+a+">"+P(o,r)+"</"+e+">":"<"+e+' data-rh="true">'+P(o,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return D(t)}};default:return{toComponent:function(){return j(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+P(r[t],n)+'"';return e?e+" "+a:a}),""),o=r.innerHTML||r.cssText||"",i=-1===L.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(i?"/>":">"+o+"</"+e+">")}),"")}(e,t,n)}}}},F=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,o=e.noscriptTags,i=e.styleTags,l=e.title,s=void 0===l?"":l,u=e.titleAttributes,c=e.linkTags,d=e.metaTags,f=e.scriptTags,p={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=N(e.metaTags,v),o=N(t,y),i=N(n,b);return{priorityMethods:{toComponent:function(){return[].concat(j(g.META,a.priority),j(g.LINK,o.priority),j(g.SCRIPT,i.priority))},toString:function(){return U(g.META,a.priority,r)+" "+U(g.LINK,o.priority,r)+" "+U(g.SCRIPT,i.priority,r)}},metaTags:a.default,linkTags:o.default,scriptTags:i.default}}(e);p=m.priorityMethods,c=m.linkTags,d=m.metaTags,f=m.scriptTags}return{priority:p,base:U(g.BASE,t,r),bodyAttributes:U("bodyAttributes",n,r),htmlAttributes:U("htmlAttributes",a,r),link:U(g.LINK,c,r),meta:U(g.META,d,r),noscript:U(g.NOSCRIPT,o,r),script:U(g.SCRIPT,f,r),style:U(g.STYLE,i,r),title:U(g.TITLE,{title:s,titleAttributes:u},r)}},B=[],z=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?B:n.instances},add:function(e){(n.canUseDOM?B:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?B:n.instances).indexOf(e);(n.canUseDOM?B:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=F({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},$=r.createContext({}),H=o().shape({setHelmet:o().func,helmetInstances:o().shape({get:o().func,add:o().func,remove:o().func})}),G="undefined"!=typeof document,V=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new z(r.props.context,t.canUseDOM),r}return p(t,e),t.prototype.render=function(){return r.createElement($.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);V.canUseDOM=G,V.propTypes={context:o().shape({helmet:o().shape()}),children:o().node.isRequired},V.defaultProps={context:{}},V.displayName="HelmetProvider";var W=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),a=r.querySelectorAll(e+"[data-rh]"),o=[].slice.call(a),i=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),o.some((function(e,t){return n=t,r.isEqualNode(e)}))?o.splice(n,1):i.push(r)})),o.forEach((function(e){return e.parentNode.removeChild(e)})),i.forEach((function(e){return r.appendChild(e)})),{oldTags:o,newTags:i}},Y=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],o=[].concat(a),i=Object.keys(t),l=0;l<i.length;l+=1){var s=i[l],u=t[s]||"";n.getAttribute(s)!==u&&n.setAttribute(s,u),-1===a.indexOf(s)&&a.push(s);var c=o.indexOf(s);-1!==c&&o.splice(c,1)}for(var d=o.length-1;d>=0;d-=1)n.removeAttribute(o[d]);a.length===o.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},K=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,o=e.metaTags,i=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,u=e.styleTags,c=e.title,d=e.titleAttributes;Y(g.BODY,e.bodyAttributes),Y(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=O(e)),Y(g.TITLE,t)}(c,d);var f={baseTag:W(g.BASE,n),linkTags:W(g.LINK,a),metaTags:W(g.META,o),noscriptTags:W(g.NOSCRIPT,i),scriptTags:W(g.SCRIPT,s),styleTags:W(g.STYLE,u)},p={},m={};Object.keys(f).forEach((function(e){var t=f[e],n=t.newTags,r=t.oldTags;n.length&&(p[e]=n),r.length&&(m[e]=f[e].oldTags)})),t&&t(),l(e,p,m)},q=null,X=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}p(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,o=(e=n.helmetInstances.get().map((function(e){var t=f({},e.props);return delete t.context,t})),{baseTag:A(["href"],e),bodyAttributes:x("bodyAttributes",e),defer:w(e,"defer"),encode:w(e,"encodeSpecialCharacters"),htmlAttributes:x("htmlAttributes",e),linkTags:C(g.LINK,["rel","href"],e),metaTags:C(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:C(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:T(e),scriptTags:C(g.SCRIPT,["src","innerHTML"],e),styleTags:C(g.STYLE,["cssText"],e),title:k(e),titleAttributes:x("titleAttributes",e),prioritizeSeoTags:R(e,"prioritizeSeoTags")});V.canUseDOM?(t=o,q&&cancelAnimationFrame(q),t.defer?q=requestAnimationFrame((function(){K(t,(function(){q=null}))})):(K(t),q=null)):F&&(a=F(o)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);X.propTypes={context:H.isRequired},X.displayName="HelmetDispatcher";var Q=["children"],Z=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}p(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!l()(I(this.props,"helmetData"),I(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return f({},r,((t={})[n.type]=[].concat(r[n.type]||[],[f({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,o=e.newChildProps,i=e.nestedChildren;switch(r.type){case g.TITLE:return f({},a,((t={})[r.type]=i,t.titleAttributes=f({},o),t));case g.BODY:return f({},a,{bodyAttributes:f({},o)});case g.HTML:return f({},a,{htmlAttributes:f({},o)});default:return f({},a,((n={})[r.type]=f({},o),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=f({},t);return Object.keys(e).forEach((function(t){var r;n=f({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return u()(E.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+E.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),u()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,o=r.children,i=h(r,Q),l=Object.keys(i).reduce((function(e,t){return e[_[t]||t]=i[t],e}),{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,o),s){case g.FRAGMENT:t=n.mapChildrenToProps(o,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:o});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:o})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,Z),a=f({},n),o=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!o||o instanceof z||(o=new z(o.context,o.instances)),o?r.createElement(X,f({},a,{context:o.value,helmetData:void 0})):r.createElement($.Consumer,null,(function(e){return r.createElement(X,f({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:o().object,bodyAttributes:o().object,children:o().oneOfType([o().arrayOf(o().node),o().node]),defaultTitle:o().string,defer:o().bool,encodeSpecialCharacters:o().bool,htmlAttributes:o().object,link:o().arrayOf(o().object),meta:o().arrayOf(o().object),noscript:o().arrayOf(o().object),onChangeClientState:o().func,script:o().arrayOf(o().object),style:o().arrayOf(o().object),title:o().string,titleAttributes:o().object,titleTemplate:o().string,prioritizeSeoTags:o().bool,helmetData:o().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},2799:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,o=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,u=n?Symbol.for("react.context"):60110,c=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,f=n?Symbol.for("react.forward_ref"):60112,p=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,y=n?Symbol.for("react.block"):60121,b=n?Symbol.for("react.fundamental"):60117,v=n?Symbol.for("react.responder"):60118,E=n?Symbol.for("react.scope"):60119;function S(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case c:case d:case o:case l:case i:case p:return e;default:switch(e=e&&e.$$typeof){case u:case f:case g:case h:case s:return e;default:return t}}case a:return t}}}function _(e){return S(e)===d}t.AsyncMode=c,t.ConcurrentMode=d,t.ContextConsumer=u,t.ContextProvider=s,t.Element=r,t.ForwardRef=f,t.Fragment=o,t.Lazy=g,t.Memo=h,t.Portal=a,t.Profiler=l,t.StrictMode=i,t.Suspense=p,t.isAsyncMode=function(e){return _(e)||S(e)===c},t.isConcurrentMode=_,t.isContextConsumer=function(e){return S(e)===u},t.isContextProvider=function(e){return S(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return S(e)===f},t.isFragment=function(e){return S(e)===o},t.isLazy=function(e){return S(e)===g},t.isMemo=function(e){return S(e)===h},t.isPortal=function(e){return S(e)===a},t.isProfiler=function(e){return S(e)===l},t.isStrictMode=function(e){return S(e)===i},t.isSuspense=function(e){return S(e)===p},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===o||e===d||e===l||e===i||e===p||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===h||e.$$typeof===s||e.$$typeof===u||e.$$typeof===f||e.$$typeof===b||e.$$typeof===v||e.$$typeof===E||e.$$typeof===y)},t.typeOf=S},4363:(e,t,n)=>{"use strict";e.exports=n(2799)},3259:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i.apply(this,arguments)}var l=n(6540),s=[],u=[];var c=l.createContext(null);function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function f(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function p(e,t){return l.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,f;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=i({loader:null,loading:null,delay:200,timeout:null,render:p,webpack:null,modules:null},t),h=null;function g(){return h||(h=e(m.loader)),h.promise}return s.push(g),"function"==typeof m.webpack&&u.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),f=d=function(t){function n(n){var r;return o(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),h=e(m.loader),r._loadModule()})),g(),r.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},r}r(n,t),n.preload=function(){return g()};var i=n.prototype;return i.UNSAFE_componentWillMount=function(){this._loadModule()},i.componentDidMount=function(){this._mounted=!0},i._loadModule=function(){var e=this;if(this.context&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.report(t)})),h.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:h.error,loaded:h.loaded,loading:h.loading}),e._clearTimeouts()};h.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},i.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},i._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},i.render=function(){return this.state.loading||this.state.error?l.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(l.Component),o(d,"contextType",c),f}function h(e){return m(d,e)}h.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(f,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(){return l.createElement(c.Provider,{value:{report:this.props.report}},l.Children.only(this.props.children))},t}(l.Component);function y(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return y(e)}))}h.Capture=g,h.preloadAll=function(){return new Promise((function(e,t){y(s).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){y(u).then(e,e)}))},e.exports=h},2831:(e,t,n)=>{"use strict";n.d(t,{u:()=>i,v:()=>l});var r=n(6347),a=n(8168),o=n(6540);function i(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.B6)(t,e):n.length?n[n.length-1].match:r.Ix.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&i(e.routes,t,n)),a})),n}function l(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?o.createElement(r.dO,n,e.map((function(e,n){return o.createElement(r.qh,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.A)({},n,{},t,{route:e})):o.createElement(e.component,(0,a.A)({},n,t,{route:e}))}})}))):null}},4625:(e,t,n)=>{"use strict";n.d(t,{Kd:()=>c,N_:()=>g,k2:()=>v});var r=n(6347),a=n(2892),o=n(6540),i=n(1513),l=n(8168),s=n(8587),u=n(1561),c=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,i.zR)(t.props),t}return(0,a.A)(t,e),t.prototype.render=function(){return o.createElement(r.Ix,{history:this.history,children:this.props.children})},t}(o.Component);o.Component;var d=function(e,t){return"function"==typeof e?e(t):e},f=function(e,t){return"string"==typeof e?(0,i.yJ)(e,null,null,t):e},p=function(e){return e},m=o.forwardRef;void 0===m&&(m=p);var h=m((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,i=(0,s.A)(e,["innerRef","navigate","onClick"]),u=i.target,c=(0,l.A)({},i,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||u&&"_self"!==u||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return c.ref=p!==m&&t||n,o.createElement("a",c)}));var g=m((function(e,t){var n=e.component,a=void 0===n?h:n,c=e.replace,g=e.to,y=e.innerRef,b=(0,s.A)(e,["component","replace","to","innerRef"]);return o.createElement(r.XZ.Consumer,null,(function(e){e||(0,u.A)(!1);var n=e.history,r=f(d(g,e.location),e.location),s=r?n.createHref(r):"",h=(0,l.A)({},b,{href:s,navigate:function(){var t=d(g,e.location),r=(0,i.AO)(e.location)===(0,i.AO)(f(t));(c||r?n.replace:n.push)(t)}});return p!==m?h.ref=t||y:h.innerRef=y,o.createElement(a,h)}))})),y=function(e){return e},b=o.forwardRef;void 0===b&&(b=y);var v=b((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,i=e.activeClassName,c=void 0===i?"active":i,p=e.activeStyle,m=e.className,h=e.exact,v=e.isActive,E=e.location,S=e.sensitive,_=e.strict,w=e.style,k=e.to,T=e.innerRef,x=(0,s.A)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return o.createElement(r.XZ.Consumer,null,(function(e){e||(0,u.A)(!1);var n=E||e.location,i=f(d(k,n),n),s=i.pathname,A=s&&s.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),C=A?(0,r.B6)(n.pathname,{path:A,exact:h,sensitive:S,strict:_}):null,R=!!(v?v(C,n):C),O="function"==typeof m?m(R):m,N="function"==typeof w?w(R):w;R&&(O=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(O,c),N=(0,l.A)({},N,p));var I=(0,l.A)({"aria-current":R&&a||null,className:O,style:N,to:i},x);return y!==b?I.ref=t||T:I.innerRef=T,o.createElement(g,I)}))}))},6347:(e,t,n)=>{"use strict";n.d(t,{B6:()=>w,Ix:()=>v,W6:()=>I,XZ:()=>b,dO:()=>O,qh:()=>k,zy:()=>L});var r=n(2892),a=n(6540),o=n(5556),i=n.n(o),l=n(1513),s=n(1561),u=n(8168),c=n(5302),d=n.n(c),f=(n(4363),n(8587)),p=(n(4146),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var h=a.createContext||function(e,t){var n,o,l="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",s=function(e){function n(){for(var t,n,r,a=arguments.length,o=new Array(a),i=0;i<a;i++)o[i]=arguments[i];return(t=e.call.apply(e,[this].concat(o))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.A)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[l]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((o=r)===(i=a)?0!==o||1/o==1/i:o!=o&&i!=i)?n=0:(n="function"==typeof t?t(r,a):p,0!==(n|=0)&&this.emitter.set(e.value,n))}var o,i},a.render=function(){return this.props.children},n}(a.Component);s.childContextTypes=((n={})[l]=i().object.isRequired,n);var u=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){(0|e.observedBits)&n&&e.setState({value:e.getValue()})},e}(0,r.A)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?p:t},a.componentDidMount=function(){this.context[l]&&this.context[l].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?p:e},a.componentWillUnmount=function(){this.context[l]&&this.context[l].off(this.onUpdate)},a.getValue=function(){return this.context[l]?this.context[l].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return u.contextTypes=((o={})[l]=i().object,o),{Provider:s,Consumer:u}},g=function(e){var t=h();return t.displayName=e,t},y=g("Router-History"),b=g("Router"),v=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.A)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(b.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(y.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var E={},S=1e4,_=0;function w(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,o=void 0!==a&&a,i=n.strict,l=void 0!==i&&i,s=n.sensitive,u=void 0!==s&&s;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=E[n]||(E[n]={});if(r[e])return r[e];var a=[],o={regexp:d()(e,a,t),keys:a};return _<S&&(r[e]=o,_++),o}(n,{end:o,strict:l,sensitive:u}),a=r.regexp,i=r.keys,s=a.exec(e);if(!s)return null;var c=s[0],f=s.slice(1),p=e===c;return o&&!p?null:{path:n,url:"/"===n&&""===c?"/":c,isExact:p,params:i.reduce((function(e,t,n){return e[t.name]=f[n],e}),{})}}),null)}var k=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.A)(t,e),t.prototype.render=function(){var e=this;return a.createElement(b.Consumer,null,(function(t){t||(0,s.A)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?w(n.pathname,e.props):t.match,o=(0,u.A)({},t,{location:n,match:r}),i=e.props,l=i.children,c=i.component,d=i.render;return Array.isArray(l)&&function(e){return 0===a.Children.count(e)}(l)&&(l=null),a.createElement(b.Provider,{value:o},o.match?l?"function"==typeof l?l(o):l:c?a.createElement(c,o):d?d(o):null:"function"==typeof l?l(o):null)}))},t}(a.Component);function T(e){return"/"===e.charAt(0)?e:"/"+e}function x(e,t){if(!e)return t;var n=T(e);return 0!==t.pathname.indexOf(n)?t:(0,u.A)({},t,{pathname:t.pathname.substr(n.length)})}function A(e){return"string"==typeof e?e:(0,l.AO)(e)}function C(e){return function(){(0,s.A)(!1)}}function R(){}a.Component;var O=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.A)(t,e),t.prototype.render=function(){var e=this;return a.createElement(b.Consumer,null,(function(t){t||(0,s.A)(!1);var n,r,o=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var i=e.props.path||e.props.from;r=i?w(o.pathname,(0,u.A)({},e.props,{path:i})):t.match}})),r?a.cloneElement(n,{location:o,computedMatch:r}):null}))},t}(a.Component);var N=a.useContext;function I(){return N(y)}function L(){return N(b).location}},1020:(e,t,n)=>{"use strict";var r=n(6540),a=Symbol.for("react.element"),o=Symbol.for("react.fragment"),i=Object.prototype.hasOwnProperty,l=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,s={key:!0,ref:!0,__self:!0,__source:!0};function u(e,t,n){var r,o={},u=null,c=null;for(r in void 0!==n&&(u=""+n),void 0!==t.key&&(u=""+t.key),void 0!==t.ref&&(c=t.ref),t)i.call(t,r)&&!s.hasOwnProperty(r)&&(o[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===o[r]&&(o[r]=t[r]);return{$$typeof:a,type:e,key:u,ref:c,props:o,_owner:l.current}}t.Fragment=o,t.jsx=u,t.jsxs=u},5287:(e,t)=>{"use strict";var n=Symbol.for("react.element"),r=Symbol.for("react.portal"),a=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),l=Symbol.for("react.provider"),s=Symbol.for("react.context"),u=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),f=Symbol.for("react.lazy"),p=Symbol.iterator;var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}function b(){}function v(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}y.prototype.isReactComponent={},y.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},y.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=y.prototype;var E=v.prototype=new b;E.constructor=v,h(E,y.prototype),E.isPureReactComponent=!0;var S=Array.isArray,_=Object.prototype.hasOwnProperty,w={current:null},k={key:!0,ref:!0,__self:!0,__source:!0};function T(e,t,r){var a,o={},i=null,l=null;if(null!=t)for(a in void 0!==t.ref&&(l=t.ref),void 0!==t.key&&(i=""+t.key),t)_.call(t,a)&&!k.hasOwnProperty(a)&&(o[a]=t[a]);var s=arguments.length-2;if(1===s)o.children=r;else if(1<s){for(var u=Array(s),c=0;c<s;c++)u[c]=arguments[c+2];o.children=u}if(e&&e.defaultProps)for(a in s=e.defaultProps)void 0===o[a]&&(o[a]=s[a]);return{$$typeof:n,type:e,key:i,ref:l,props:o,_owner:w.current}}function x(e){return"object"==typeof e&&null!==e&&e.$$typeof===n}var A=/\/+/g;function C(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function R(e,t,a,o,i){var l=typeof e;"undefined"!==l&&"boolean"!==l||(e=null);var s=!1;if(null===e)s=!0;else switch(l){case"string":case"number":s=!0;break;case"object":switch(e.$$typeof){case n:case r:s=!0}}if(s)return i=i(s=e),e=""===o?"."+C(s,0):o,S(i)?(a="",null!=e&&(a=e.replace(A,"$&/")+"/"),R(i,t,a,"",(function(e){return e}))):null!=i&&(x(i)&&(i=function(e,t){return{$$typeof:n,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(i,a+(!i.key||s&&s.key===i.key?"":(""+i.key).replace(A,"$&/")+"/")+e)),t.push(i)),1;if(s=0,o=""===o?".":o+":",S(e))for(var u=0;u<e.length;u++){var c=o+C(l=e[u],u);s+=R(l,t,a,c,i)}else if(c=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=p&&e[p]||e["@@iterator"])?e:null}(e),"function"==typeof c)for(e=c.call(e),u=0;!(l=e.next()).done;)s+=R(l=l.value,t,a,c=o+C(l,u++),i);else if("object"===l)throw t=String(e),Error("Objects are not valid as a React child (found: "+("[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return s}function O(e,t,n){if(null==e)return e;var r=[],a=0;return R(e,r,"","",(function(e){return t.call(n,e,a++)})),r}function N(e){if(-1===e._status){var t=e._result;(t=t()).then((function(t){0!==e._status&&-1!==e._status||(e._status=1,e._result=t)}),(function(t){0!==e._status&&-1!==e._status||(e._status=2,e._result=t)})),-1===e._status&&(e._status=0,e._result=t)}if(1===e._status)return e._result.default;throw e._result}var I={current:null},L={transition:null},P={ReactCurrentDispatcher:I,ReactCurrentBatchConfig:L,ReactCurrentOwner:w};function D(){throw Error("act(...) is not supported in production builds of React.")}t.Children={map:O,forEach:function(e,t,n){O(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return O(e,(function(){t++})),t},toArray:function(e){return O(e,(function(e){return e}))||[]},only:function(e){if(!x(e))throw Error("React.Children.only expected to receive a single React element child.");return e}},t.Component=y,t.Fragment=a,t.Profiler=i,t.PureComponent=v,t.StrictMode=o,t.Suspense=c,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=P,t.act=D,t.cloneElement=function(e,t,r){if(null==e)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var a=h({},e.props),o=e.key,i=e.ref,l=e._owner;if(null!=t){if(void 0!==t.ref&&(i=t.ref,l=w.current),void 0!==t.key&&(o=""+t.key),e.type&&e.type.defaultProps)var s=e.type.defaultProps;for(u in t)_.call(t,u)&&!k.hasOwnProperty(u)&&(a[u]=void 0===t[u]&&void 0!==s?s[u]:t[u])}var u=arguments.length-2;if(1===u)a.children=r;else if(1<u){s=Array(u);for(var c=0;c<u;c++)s[c]=arguments[c+2];a.children=s}return{$$typeof:n,type:e.type,key:o,ref:i,props:a,_owner:l}},t.createContext=function(e){return(e={$$typeof:s,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null}).Provider={$$typeof:l,_context:e},e.Consumer=e},t.createElement=T,t.createFactory=function(e){var t=T.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:u,render:e}},t.isValidElement=x,t.lazy=function(e){return{$$typeof:f,_payload:{_status:-1,_result:e},_init:N}},t.memo=function(e,t){return{$$typeof:d,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=L.transition;L.transition={};try{e()}finally{L.transition=t}},t.unstable_act=D,t.useCallback=function(e,t){return I.current.useCallback(e,t)},t.useContext=function(e){return I.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return I.current.useDeferredValue(e)},t.useEffect=function(e,t){return I.current.useEffect(e,t)},t.useId=function(){return I.current.useId()},t.useImperativeHandle=function(e,t,n){return I.current.useImperativeHandle(e,t,n)},t.useInsertionEffect=function(e,t){return I.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return I.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return I.current.useMemo(e,t)},t.useReducer=function(e,t,n){return I.current.useReducer(e,t,n)},t.useRef=function(e){return I.current.useRef(e)},t.useState=function(e){return I.current.useState(e)},t.useSyncExternalStore=function(e,t,n){return I.current.useSyncExternalStore(e,t,n)},t.useTransition=function(){return I.current.useTransition()},t.version="18.3.1"},6540:(e,t,n)=>{"use strict";e.exports=n(5287)},4848:(e,t,n)=>{"use strict";e.exports=n(1020)},7463:(e,t)=>{"use strict";function n(e,t){var n=e.length;e.push(t);e:for(;0<n;){var r=n-1>>>1,a=e[r];if(!(0<o(a,t)))break e;e[r]=t,e[n]=a,n=r}}function r(e){return 0===e.length?null:e[0]}function a(e){if(0===e.length)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length,i=a>>>1;r<i;){var l=2*(r+1)-1,s=e[l],u=l+1,c=e[u];if(0>o(s,n))u<a&&0>o(c,s)?(e[r]=c,e[u]=n,r=u):(e[r]=s,e[l]=n,r=l);else{if(!(u<a&&0>o(c,n)))break e;e[r]=c,e[u]=n,r=u}}}return t}function o(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}if("object"==typeof performance&&"function"==typeof performance.now){var i=performance;t.unstable_now=function(){return i.now()}}else{var l=Date,s=l.now();t.unstable_now=function(){return l.now()-s}}var u=[],c=[],d=1,f=null,p=3,m=!1,h=!1,g=!1,y="function"==typeof setTimeout?setTimeout:null,b="function"==typeof clearTimeout?clearTimeout:null,v="undefined"!=typeof setImmediate?setImmediate:null;function E(e){for(var t=r(c);null!==t;){if(null===t.callback)a(c);else{if(!(t.startTime<=e))break;a(c),t.sortIndex=t.expirationTime,n(u,t)}t=r(c)}}function S(e){if(g=!1,E(e),!h)if(null!==r(u))h=!0,L(_);else{var t=r(c);null!==t&&P(S,t.startTime-e)}}function _(e,n){h=!1,g&&(g=!1,b(x),x=-1),m=!0;var o=p;try{for(E(n),f=r(u);null!==f&&(!(f.expirationTime>n)||e&&!R());){var i=f.callback;if("function"==typeof i){f.callback=null,p=f.priorityLevel;var l=i(f.expirationTime<=n);n=t.unstable_now(),"function"==typeof l?f.callback=l:f===r(u)&&a(u),E(n)}else a(u);f=r(u)}if(null!==f)var s=!0;else{var d=r(c);null!==d&&P(S,d.startTime-n),s=!1}return s}finally{f=null,p=o,m=!1}}"undefined"!=typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var w,k=!1,T=null,x=-1,A=5,C=-1;function R(){return!(t.unstable_now()-C<A)}function O(){if(null!==T){var e=t.unstable_now();C=e;var n=!0;try{n=T(!0,e)}finally{n?w():(k=!1,T=null)}}else k=!1}if("function"==typeof v)w=function(){v(O)};else if("undefined"!=typeof MessageChannel){var N=new MessageChannel,I=N.port2;N.port1.onmessage=O,w=function(){I.postMessage(null)}}else w=function(){y(O,0)};function L(e){T=e,k||(k=!0,w())}function P(e,n){x=y((function(){e(t.unstable_now())}),n)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){h||m||(h=!0,L(_))},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):A=0<e?Math.floor(1e3/e):5},t.unstable_getCurrentPriorityLevel=function(){return p},t.unstable_getFirstCallbackNode=function(){return r(u)},t.unstable_next=function(e){switch(p){case 1:case 2:case 3:var t=3;break;default:t=p}var n=p;p=t;try{return e()}finally{p=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=function(){},t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=p;p=e;try{return t()}finally{p=n}},t.unstable_scheduleCallback=function(e,a,o){var i=t.unstable_now();switch("object"==typeof o&&null!==o?o="number"==typeof(o=o.delay)&&0<o?i+o:i:o=i,e){case 1:var l=-1;break;case 2:l=250;break;case 5:l=1073741823;break;case 4:l=1e4;break;default:l=5e3}return e={id:d++,callback:a,priorityLevel:e,startTime:o,expirationTime:l=o+l,sortIndex:-1},o>i?(e.sortIndex=o,n(c,e),null===r(u)&&e===r(c)&&(g?(b(x),x=-1):g=!0,P(S,o-i))):(e.sortIndex=l,n(u,e),h||m||(h=!0,L(_))),e},t.unstable_shouldYield=R,t.unstable_wrapCallback=function(e){var t=p;return function(){var n=p;p=t;try{return e.apply(this,arguments)}finally{p=n}}}},9982:(e,t,n)=>{"use strict";e.exports=n(7463)},2833:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var o=Object.keys(e),i=Object.keys(t);if(o.length!==i.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),s=0;s<o.length;s++){var u=o[s];if(!l(u))return!1;var c=e[u],d=t[u];if(!1===(a=n?n.call(r,c,d,u):void 0)||void 0===a&&c!==d)return!1}return!0}},1910:(e,t,n)=>{var r={"./prism-qmake":6094,"./prism-qmake.js":6094};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=1910},4784:(e,t,n)=>{"use strict";n.d(t,{A:()=>r});const r={title:"TinyORM",tagline:"C++ ORM library for Qt framework",favicon:"img/favicon.ico",url:"https://www.tinyorm.org",baseUrl:"/",organizationName:"silverqx",projectName:"TinyORM",onBrokenLinks:"throw",onBrokenMarkdownLinks:"throw",deploymentBranch:"gh-pages",trailingSlash:!1,titleDelimiter:"-",noIndex:!1,i18n:{defaultLocale:"en",locales:["en"],path:"i18n",localeConfigs:{}},presets:[["classic",{docs:{sidebarPath:"./sidebars.js",routeBasePath:"/",exclude:["**/assets/**","building/README.md","database/README.md","tinydrivers/README.md","tinyorm/README.md"]},blog:!1,theme:{customCss:"./src/css/custom.css"},sitemap:{changefreq:"weekly"},gtag:{trackingID:"G-2QRS622BWQ",anonymizeIP:!1}}]],themeConfig:{colorMode:{defaultMode:"dark",disableSwitch:!1,respectPrefersColorScheme:!1},navbar:{hideOnScroll:!0,title:"TinyORM",logo:{alt:"TinyORM Logo",src:"img/logo.svg"},items:[{href:"https://github.com/silverqx/TinyORM",position:"right",className:"header-github-link","aria-label":"TinyORM GitHub repository",title:"TinyORM GitHub repository"}]},docs:{sidebar:{hideable:!0,autoCollapseCategories:!0},versionPersistence:"localStorage"},footer:{links:[],copyright:'<span>Copyright \xa9 2024 </span><a href="https://github.com/silverqx" target="_blank">Silver Zachara</a>',style:"light"},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},defaultLanguage:"cpp",additionalLanguages:["cmake","powershell","bash"],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},algolia:{appId:"ML6TJ6GTSR",apiKey:"2d548632681c7f359587e5671f67e636",indexName:"TinyORM-github.io",contextualSearch:!1,searchParameters:{},searchPagePath:"search"},metadata:[{name:"keywords",content:"c++ orm, tinyorm"}],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},plugins:[["@docusaurus/plugin-client-redirects",{redirects:[{to:"/building/tinyorm",from:"/building"},{to:"/database/getting-started",from:"/database"},{to:"/database/query-builder",from:"/query-builder"},{to:"/tinyorm/getting-started",from:"/tinyorm"},{to:"/tinyorm/relationships",from:"/tinyorm-relationships"}]}],null,null,null],baseUrlIssueBanner:!0,onBrokenAnchors:"warn",onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],markdown:{format:"mdx",mermaid:!1,mdx1Compat:{comments:!0,admonitions:!0,headingIds:!0},anchors:{maintainCase:!1}}}},8168:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{A:()=>r})},2892:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{A:()=>a})},8587:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){if(t.indexOf(r)>=0)continue;n[r]=e[r]}return n}n.d(t,{A:()=>r})},4164:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n)}else for(n in e)e[n]&&(a&&(a+=" "),a+=n);return a}n.d(t,{A:()=>a});const a=function(){for(var e,t,n=0,a="",o=arguments.length;n<o;n++)(e=arguments[n])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},1765:(e,t,n)=>{"use strict";n.d(t,{My:()=>A,f4:()=>ee});var r,a,o,i,l,s,u,c=n(6540),d=n(4164),f=Object.create,p=Object.defineProperty,m=Object.defineProperties,h=Object.getOwnPropertyDescriptor,g=Object.getOwnPropertyDescriptors,y=Object.getOwnPropertyNames,b=Object.getOwnPropertySymbols,v=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable,_=(e,t,n)=>t in e?p(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,w=(e,t)=>{for(var n in t||(t={}))E.call(t,n)&&_(e,n,t[n]);if(b)for(var n of b(t))S.call(t,n)&&_(e,n,t[n]);return e},k=(e,t)=>m(e,g(t)),T=(e,t)=>{var n={};for(var r in e)E.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&b)for(var r of b(e))t.indexOf(r)<0&&S.call(e,r)&&(n[r]=e[r]);return n},x=(r={"../../node_modules/.pnpm/prismjs@1.29.0_patch_hash=vrxx3pzkik6jpmgpayxfjunetu/node_modules/prismjs/prism.js"(e,t){var n=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,o;switch(n=n||{},r.util.type(t)){case"Object":if(o=r.util.objId(t),n[o])return n[o];for(var i in a={},n[o]=a,t)t.hasOwnProperty(i)&&(a[i]=e(t[i],n));return a;case"Array":return o=r.util.objId(t),n[o]?n[o]:(a=[],n[o]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var o=(a=a||r.languages)[e],i={};for(var l in o)if(o.hasOwnProperty(l)){if(l==t)for(var s in n)n.hasOwnProperty(s)&&(i[s]=n[s]);n.hasOwnProperty(l)||(i[l]=o[l])}var u=a[e];return a[e]=i,r.languages.DFS(r.languages,(function(t,n){n===u&&t!=e&&(this[t]=i)})),i},DFS:function e(t,n,a,o){o=o||{};var i=r.util.objId;for(var l in t)if(t.hasOwnProperty(l)){n.call(t,l,t[l],a||l);var s=t[l],u=r.util.type(s);"Object"!==u||o[i(s)]?"Array"!==u||o[i(s)]||(o[i(s)]=!0,e(s,n,l,o)):(o[i(s)]=!0,e(s,n,null,o))}}},plugins:{},highlight:function(e,t,n){var o={code:e,grammar:t,language:n};if(r.hooks.run("before-tokenize",o),!o.grammar)throw new Error('The language "'+o.language+'" has no grammar.');return o.tokens=r.tokenize(o.code,o.grammar),r.hooks.run("after-tokenize",o),a.stringify(r.util.encode(o.tokens),o.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new l;return s(a,a.head,e),i(e,a,t,a.head,0),function(e){for(var t=[],n=e.head.next;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,o=0;a=n[o++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function o(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var o=a[1].length;a.index+=o,a[0]=a[0].slice(o)}return a}function i(e,t,n,l,c,d){for(var f in n)if(n.hasOwnProperty(f)&&n[f]){var p=n[f];p=Array.isArray(p)?p:[p];for(var m=0;m<p.length;++m){if(d&&d.cause==f+","+m)return;var h=p[m],g=h.inside,y=!!h.lookbehind,b=!!h.greedy,v=h.alias;if(b&&!h.pattern.global){var E=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,E+"g")}for(var S=h.pattern||h,_=l.next,w=c;_!==t.tail&&!(d&&w>=d.reach);w+=_.value.length,_=_.next){var k=_.value;if(t.length>e.length)return;if(!(k instanceof a)){var T,x=1;if(b){if(!(T=o(S,w,e,y))||T.index>=e.length)break;var A=T.index,C=T.index+T[0].length,R=w;for(R+=_.value.length;A>=R;)R+=(_=_.next).value.length;if(w=R-=_.value.length,_.value instanceof a)continue;for(var O=_;O!==t.tail&&(R<C||"string"==typeof O.value);O=O.next)x++,R+=O.value.length;x--,k=e.slice(w,R),T.index-=w}else if(!(T=o(S,0,k,y)))continue;A=T.index;var N=T[0],I=k.slice(0,A),L=k.slice(A+N.length),P=w+k.length;d&&P>d.reach&&(d.reach=P);var D=_.prev;if(I&&(D=s(t,D,I),w+=I.length),u(t,D,x),_=s(t,D,new a(f,g?r.tokenize(N,g):N,v,N)),L&&s(t,_,L),x>1){var M={cause:f+","+m,reach:P};i(e,t,n,_.prev,w,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function u(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var o={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},i=t.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(o.classes,i):o.classes.push(i)),r.hooks.run("wrap",o);var l="";for(var s in o.attributes)l+=" "+s+'="'+(o.attributes[s]||"").replace(/"/g,""")+'"';return"<"+o.tag+' class="'+o.classes.join(" ")+'"'+l+">"+o.content+"</"+o.tag+">"},r}();t.exports=n,n.default=n}},function(){return a||(0,r[y(r)[0]])((a={exports:{}}).exports,a),a.exports}),A=((e,t,n)=>(n=null!=e?f(v(e)):{},((e,t,n,r)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let a of y(t))E.call(e,a)||a===n||p(e,a,{get:()=>t[a],enumerable:!(r=h(t,a))||r.enumerable});return e})(!t&&e&&e.__esModule?n:p(n,"default",{value:e,enumerable:!0}),e)))(x());A.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},A.languages.markup.tag.inside["attr-value"].inside.entity=A.languages.markup.entity,A.languages.markup.doctype.inside["internal-subset"].inside=A.languages.markup,A.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(A.languages.markup.tag,"addInlined",{value:function(e,t){var n;(t=((n=((n={})["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:A.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i,{"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}}))["language-"+t]={pattern:/[\s\S]+/,inside:A.languages[t]},{}))[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:n},A.languages.insertBefore("markup","cdata",t)}}),Object.defineProperty(A.languages.markup.tag,"addAttribute",{value:function(e,t){A.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:A.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),A.languages.html=A.languages.markup,A.languages.mathml=A.languages.markup,A.languages.svg=A.languages.markup,A.languages.xml=A.languages.extend("markup",{}),A.languages.ssml=A.languages.xml,A.languages.atom=A.languages.xml,A.languages.rss=A.languages.xml,o=A,i={pattern:/\\[\\(){}[\]^$+*?|.]/,alias:"escape"},s="(?:[^\\\\-]|"+(l=/\\(?:x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]+\}|0[0-7]{0,2}|[123][0-7]{2}|c[a-zA-Z]|.)/).source+")",s=RegExp(s+"-"+s),u={pattern:/(<|')[^<>']+(?=[>']$)/,lookbehind:!0,alias:"variable"},o.languages.regex={"char-class":{pattern:/((?:^|[^\\])(?:\\\\)*)\[(?:[^\\\]]|\\[\s\S])*\]/,lookbehind:!0,inside:{"char-class-negation":{pattern:/(^\[)\^/,lookbehind:!0,alias:"operator"},"char-class-punctuation":{pattern:/^\[|\]$/,alias:"punctuation"},range:{pattern:s,inside:{escape:l,"range-punctuation":{pattern:/-/,alias:"operator"}}},"special-escape":i,"char-set":{pattern:/\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},escape:l}},"special-escape":i,"char-set":{pattern:/\.|\\[wsd]|\\p\{[^{}]+\}/i,alias:"class-name"},backreference:[{pattern:/\\(?![123][0-7]{2})[1-9]/,alias:"keyword"},{pattern:/\\k<[^<>']+>/,alias:"keyword",inside:{"group-name":u}}],anchor:{pattern:/[$^]|\\[ABbGZz]/,alias:"function"},escape:l,group:[{pattern:/\((?:\?(?:<[^<>']+>|'[^<>']+'|[>:]|<?[=!]|[idmnsuxU]+(?:-[idmnsuxU]+)?:?))?/,alias:"punctuation",inside:{"group-name":u}},{pattern:/\)/,alias:"punctuation"}],quantifier:{pattern:/(?:[+*?]|\{\d+(?:,\d*)?\})[?+]?/,alias:"number"},alternation:{pattern:/\|/,alias:"keyword"}},A.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},A.languages.javascript=A.languages.extend("clike",{"class-name":[A.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),A.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,A.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:A.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:A.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:A.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:A.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:A.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),A.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:A.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),A.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),A.languages.markup&&(A.languages.markup.tag.addInlined("script","javascript"),A.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),A.languages.js=A.languages.javascript,A.languages.actionscript=A.languages.extend("javascript",{keyword:/\b(?:as|break|case|catch|class|const|default|delete|do|dynamic|each|else|extends|final|finally|for|function|get|if|implements|import|in|include|instanceof|interface|internal|is|namespace|native|new|null|override|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|use|var|void|while|with)\b/,operator:/\+\+|--|(?:[+\-*\/%^]|&&?|\|\|?|<<?|>>?>?|[!=]=?)=?|[~?@]/}),A.languages.actionscript["class-name"].alias="function",delete A.languages.actionscript.parameter,delete A.languages.actionscript["literal-property"],A.languages.markup&&A.languages.insertBefore("actionscript","string",{xml:{pattern:/(^|[^.])<\/?\w+(?:\s+[^\s>\/=]+=("|')(?:\\[\s\S]|(?!\2)[^\\])*\2)*\s*\/?>/,lookbehind:!0,inside:A.languages.markup}}),function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(A),function(e){var t=e.languages.javadoclike={parameter:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*@(?:arg|arguments|param)\s+)\w+/m,lookbehind:!0},keyword:{pattern:/(^[\t ]*(?:\/{3}|\*|\/\*\*)\s*|\{)@[a-z][a-zA-Z-]+\b/m,lookbehind:!0},punctuation:/[{}]/};Object.defineProperty(t,"addSupport",{value:function(t,n){(t="string"==typeof t?[t]:t).forEach((function(t){var r=function(e){e.inside||(e.inside={}),e.inside.rest=n},a="doc-comment";if(o=e.languages[t]){var o,i=o[a];if((i=i||(o=e.languages.insertBefore(t,"comment",{"doc-comment":{pattern:/(^|[^\\])\/\*\*[^/][\s\S]*?(?:\*\/|$)/,lookbehind:!0,alias:"comment"}}))[a])instanceof RegExp&&(i=o[a]={pattern:i}),Array.isArray(i))for(var l=0,s=i.length;l<s;l++)i[l]instanceof RegExp&&(i[l]={pattern:i[l]}),r(i[l]);else r(i)}}))}}),t.addSupport(["java","javascript","php"],t)}(A),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;(t=(e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+t.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css,e.languages.markup))&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))}(A),function(e){var t=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,n=(t=(e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+t.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[t,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}}),{pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0}),{pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0});e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|RebeccaPurple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,number:n})}(A),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),o=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+a+"|"+o+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(o),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(A),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),o=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source,i=(e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+o+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+o+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a,o=t[n];"code"!==o.type?e(o.content):(a=o.content[1],o=o.content[3],a&&o&&"code-language"===a.type&&"code-block"===o.type&&"string"==typeof a.content&&(a=a.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),a="language-"+(a=(/[a-z][\w-]*/i.exec(a)||[""])[0].toLowerCase()),o.alias?"string"==typeof o.alias?o.alias=[o.alias,a]:o.alias.push(a):o.alias=[a]))}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var o=t.classes[r];if(o=/language-(.+)/.exec(o)){n=o[1];break}}var u,c=e.languages[n];c?t.content=e.highlight(t.content.replace(i,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;return"#"===(t=t.toLowerCase())[0]?(n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),s(n)):l[t]||e})),c,n):n&&"none"!==n&&e.plugins.autoloader&&(u="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random()),t.attributes.id=u,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(u);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))})))}})),RegExp(e.languages.markup.tag.pattern.source,"gi")),l={amp:"&",lt:"<",gt:">",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(A),A.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:A.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},A.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===c(1).content){n+=2;var o=f(/^\($/,/^\)$/);if(-1===o)continue;for(;n<o;n++){var i=c(0);"variable"===i.type&&(p(i,"variable-input"),a.push(i.content))}n=o+1}if(d(["punctuation","property-query"])&&"{"===c(0).content&&(n++,p(c(0),"property-mutation"),0<a.length)){var l=f(/^\{$/,/^\}$/);if(-1!==l)for(var s=n;s<l;s++){var u=t[s];"variable"===u.type&&0<=a.indexOf(u.content)&&p(u,"variable-input")}}}}function c(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=c(n+t);if(!r||r.type!==e[n])return}return 1}function f(e,r){for(var a=1,o=n;o<t.length;o++){var i=t[o],l=i.content;if("punctuation"===i.type&&"string"==typeof l)if(e.test(l))a++;else if(r.test(l)&&0==--a)return o}return-1}function p(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),A.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],o=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(t,n,r){return t={code:t,grammar:n,language:r},e.hooks.run("before-tokenize",t),t.tokens=e.tokenize(t.code,t.grammar),e.hooks.run("after-tokenize",t),t.tokens}function s(t,n,i){var s=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),u=0,c={},d=(s=l(s.map((function(e){if("string"==typeof e)return e;var n,r;for(e=e.content;-1!==t.indexOf((r=u++,n="___"+i.toUpperCase()+"_"+r+"___")););return c[n]=e,n})).join(""),n,i),Object.keys(c));return u=0,function t(n){for(var o=0;o<n.length;o++){if(u>=d.length)return;var i,s,f,p,m,h,g,y=n[o];"string"==typeof y||"string"==typeof y.content?(i=d[u],-1!==(g=(h="string"==typeof y?y:y.content).indexOf(i))&&(++u,s=h.substring(0,g),m=c[i],f=void 0,(p={})["interpolation-punctuation"]=a,3===(p=e.tokenize(m,p)).length&&((f=[1,1]).push.apply(f,l(p[1],e.languages.javascript,"javascript")),p.splice.apply(p,f)),f=new e.Token("interpolation",p,r.alias,m),p=h.substring(g+i.length),m=[],s&&m.push(s),m.push(f),p&&(t(h=[p]),m.push.apply(m,h)),"string"==typeof y?(n.splice.apply(n,[o,1].concat(m)),o+=m.length-1):y.content=m)):(g=y.content,Array.isArray(g)?t(g):t([g]))}}(s),new e.Token(i,s,"language-"+i,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var u={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function c(e){return"string"==typeof e?e:Array.isArray(e)?e.map(c).join(""):c(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in u&&function t(n){for(var r=0,a=n.length;r<a;r++){var o,i,l,u=n[r];"string"!=typeof u&&(o=u.content,Array.isArray(o)?"template-string"===u.type?(u=o[1],3===o.length&&"string"!=typeof u&&"embedded-code"===u.type&&(i=c(u),u=u.alias,u=Array.isArray(u)?u[0]:u,l=e.languages[u])&&(o[1]=s(i,l,u))):t(o):"string"!=typeof o&&t([o]))}}(t.tokens)}))}(A),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(A),function(e){var t=e.languages.javascript,n=/\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})+\}/.source,r="(@(?:arg|argument|param|property)\\s+(?:"+n+"\\s+)?)";e.languages.jsdoc=e.languages.extend("javadoclike",{parameter:{pattern:RegExp(r+/(?:(?!\s)[$\w\xA0-\uFFFF.])+(?=\s|$)/.source),lookbehind:!0,inside:{punctuation:/\./}}}),e.languages.insertBefore("jsdoc","keyword",{"optional-parameter":{pattern:RegExp(r+/\[(?:(?!\s)[$\w\xA0-\uFFFF.])+(?:=[^[\]]+)?\](?=\s|$)/.source),lookbehind:!0,inside:{parameter:{pattern:/(^\[)[$\w\xA0-\uFFFF\.]+/,lookbehind:!0,inside:{punctuation:/\./}},code:{pattern:/(=)[\s\S]*(?=\]$)/,lookbehind:!0,inside:t,alias:"language-javascript"},punctuation:/[=[\]]/}},"class-name":[{pattern:RegExp(/(@(?:augments|class|extends|interface|memberof!?|template|this|typedef)\s+(?:<TYPE>\s+)?)[A-Z]\w*(?:\.[A-Z]\w*)*/.source.replace(/<TYPE>/g,(function(){return n}))),lookbehind:!0,inside:{punctuation:/\./}},{pattern:RegExp("(@[a-z]+\\s+)"+n),lookbehind:!0,inside:{string:t.string,number:t.number,boolean:t.boolean,keyword:e.languages.typescript.keyword,operator:/=>|\.\.\.|[&|?:*]/,punctuation:/[.,;=<>{}()[\]]/}}],example:{pattern:/(@example\s+(?!\s))(?:[^@\s]|\s+(?!\s))+?(?=\s*(?:\*\s*)?(?:@\w|\*\/))/,lookbehind:!0,inside:{code:{pattern:/^([\t ]*(?:\*\s*)?)\S.*$/m,lookbehind:!0,inside:t,alias:"language-javascript"}}}}),e.languages.javadoclike.addSupport("javascript",e.languages.jsdoc)}(A),function(e){e.languages.flow=e.languages.extend("javascript",{}),e.languages.insertBefore("flow","keyword",{type:[{pattern:/\b(?:[Bb]oolean|Function|[Nn]umber|[Ss]tring|[Ss]ymbol|any|mixed|null|void)\b/,alias:"class-name"}]}),e.languages.flow["function-variable"].pattern=/(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=\s*(?:function\b|(?:\([^()]*\)(?:\s*:\s*\w+)?|(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/i,delete e.languages.flow.parameter,e.languages.insertBefore("flow","operator",{"flow-punctuation":{pattern:/\{\||\|\}/,alias:"punctuation"}}),Array.isArray(e.languages.flow.keyword)||(e.languages.flow.keyword=[e.languages.flow.keyword]),e.languages.flow.keyword.unshift({pattern:/(^|[^$]\b)(?:Class|declare|opaque|type)\b(?!\$)/,lookbehind:!0},{pattern:/(^|[^$]\B)\$(?:Diff|Enum|Exact|Keys|ObjMap|PropertyType|Record|Shape|Subtype|Supertype|await)\b(?!\$)/,lookbehind:!0})}(A),A.languages.n4js=A.languages.extend("javascript",{keyword:/\b(?:Array|any|boolean|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|module|new|null|number|package|private|protected|public|return|set|static|string|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/}),A.languages.insertBefore("n4js","constant",{annotation:{pattern:/@+\w+/,alias:"operator"}}),A.languages.n4jsd=A.languages.n4js,function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],o=e.languages.javascript[a];a=(o="RegExp"===e.util.type(o)?e.languages.javascript[a]={pattern:o}:o).inside||{};(o.inside=a)["maybe-class-name"]=/^[A-Z][\s\S]*/}}(A),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function o(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return a})),RegExp(e,t)}function i(t){for(var n=[],r=0;r<t.length;r++){var a=t[r],o=!1;"string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?0<n.length&&n[n.length-1].tagName===l(a.content[0].content[1])&&n.pop():"/>"!==a.content[a.content.length-1].content&&n.push({tagName:l(a.content[0].content[1]),openedBraces:0}):0<n.length&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:0<n.length&&0<n[n.length-1].openedBraces&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof a)&&0<n.length&&0===n[n.length-1].openedBraces&&(o=l(a),r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(o+=l(t[r+1]),t.splice(r+1,1)),0<r&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(o=l(t[r-1])+o,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",o,null,o)),a.content&&"string"!=typeof a.content&&i(a.content)}}a=o(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var l=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(l).join(""):""};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||i(e.tokens)}))}(A),function(e){var t=e.util.clone(e.languages.typescript);(t=(e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"],e.languages.tsx.tag)).pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+t.pattern.source+")",t.pattern.flags),t.lookbehind=!0}(A),A.languages.swift={comment:{pattern:/(^|[^\\:])(?:\/\/.*|\/\*(?:[^/*]|\/(?!\*)|\*(?!\/)|\/\*(?:[^*]|\*(?!\/))*\*\/)*\*\/)/,lookbehind:!0,greedy:!0},"string-literal":[{pattern:RegExp(/(^|[^"#])/.source+"(?:"+/"(?:\\(?:\((?:[^()]|\([^()]*\))*\)|\r\n|[^(])|[^\\\r\n"])*"/.source+"|"+/"""(?:\\(?:\((?:[^()]|\([^()]*\))*\)|[^(])|[^\\"]|"(?!""))*"""/.source+")"+/(?!["#])/.source),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\\($/,alias:"punctuation"},punctuation:/\\(?=[\r\n])/,string:/[\s\S]+/}},{pattern:RegExp(/(^|[^"#])(#+)/.source+"(?:"+/"(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|\r\n|[^#])|[^\\\r\n])*?"/.source+"|"+/"""(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|[^#])|[^\\])*?"""/.source+")\\2"),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\#+\()(?:[^()]|\([^()]*\))*(?=\))/,lookbehind:!0,inside:null},"interpolation-punctuation":{pattern:/^\)|\\#+\($/,alias:"punctuation"},string:/[\s\S]+/}}],directive:{pattern:RegExp(/#/.source+"(?:"+/(?:elseif|if)\b/.source+"(?:[ \t]*"+/(?:![ \t]*)?(?:\b\w+\b(?:[ \t]*\((?:[^()]|\([^()]*\))*\))?|\((?:[^()]|\([^()]*\))*\))(?:[ \t]*(?:&&|\|\|))?/.source+")+|"+/(?:else|endif)\b/.source+")"),alias:"property",inside:{"directive-name":/^#\w+/,boolean:/\b(?:false|true)\b/,number:/\b\d+(?:\.\d+)*\b/,operator:/!|&&|\|\||[<>]=?/,punctuation:/[(),]/}},literal:{pattern:/#(?:colorLiteral|column|dsohandle|file(?:ID|Literal|Path)?|function|imageLiteral|line)\b/,alias:"constant"},"other-directive":{pattern:/#\w+\b/,alias:"property"},attribute:{pattern:/@\w+/,alias:"atrule"},"function-definition":{pattern:/(\bfunc\s+)\w+/,lookbehind:!0,alias:"function"},label:{pattern:/\b(break|continue)\s+\w+|\b[a-zA-Z_]\w*(?=\s*:\s*(?:for|repeat|while)\b)/,lookbehind:!0,alias:"important"},keyword:/\b(?:Any|Protocol|Self|Type|actor|as|assignment|associatedtype|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic|else|enum|extension|fallthrough|fileprivate|final|for|func|get|guard|higherThan|if|import|in|indirect|infix|init|inout|internal|is|isolated|lazy|left|let|lowerThan|mutating|none|nonisolated|nonmutating|open|operator|optional|override|postfix|precedencegroup|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|set|some|static|struct|subscript|super|switch|throw|throws|try|typealias|unowned|unsafe|var|weak|where|while|willSet)\b/,boolean:/\b(?:false|true)\b/,nil:{pattern:/\bnil\b/,alias:"constant"},"short-argument":/\$\d+\b/,omit:{pattern:/\b_\b/,alias:"keyword"},number:/\b(?:[\d_]+(?:\.[\de_]+)?|0x[a-f0-9_]+(?:\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i,"class-name":/\b[A-Z](?:[A-Z_\d]*[a-z]\w*)?\b/,function:/\b[a-z_]\w*(?=\s*\()/i,constant:/\b(?:[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/,operator:/[-+*/%=!<>&|^~?]+|\.[.\-+*/%=!<>&|^~?]+/,punctuation:/[{}[\]();,.:\\]/},A.languages.swift["string-literal"].forEach((function(e){e.inside.interpolation.inside=A.languages.swift})),function(e){e.languages.kotlin=e.languages.extend("clike",{keyword:{pattern:/(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/,lookbehind:!0},function:[{pattern:/(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/,greedy:!0},{pattern:/(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/,lookbehind:!0,greedy:!0}],number:/\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/,operator:/\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/}),delete e.languages.kotlin["class-name"];var t={"interpolation-punctuation":{pattern:/^\$\{?|\}$/,alias:"punctuation"},expression:{pattern:/[\s\S]+/,inside:e.languages.kotlin}};e.languages.insertBefore("kotlin","string",{"string-literal":[{pattern:/"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/,alias:"multiline",inside:{interpolation:{pattern:/\$(?:[a-z_]\w*|\{[^{}]*\})/i,inside:t},string:/[\s\S]+/}},{pattern:/"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/,alias:"singleline",inside:{interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i,lookbehind:!0,inside:t},string:/[\s\S]+/}}],char:{pattern:/'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete e.languages.kotlin.string,e.languages.insertBefore("kotlin","keyword",{annotation:{pattern:/\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/,alias:"builtin"}}),e.languages.insertBefore("kotlin","function",{label:{pattern:/\b\w+@|@\w+\b/,alias:"symbol"}}),e.languages.kt=e.languages.kotlin,e.languages.kts=e.languages.kotlin}(A),A.languages.c=A.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),A.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),A.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},A.languages.c.string],char:A.languages.c.char,comment:A.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:A.languages.c}}}}),A.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete A.languages.c.boolean,A.languages.objectivec=A.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete A.languages.objectivec["class-name"],A.languages.objc=A.languages.objectivec,A.languages.reason=A.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),A.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete A.languages.reason.function,function(e){for(var t=/\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source,n=0;n<2;n++)t=t.replace(/<self>/g,(function(){return t}));t=t.replace(/<self>/g,(function(){return/[^\s\S]/.source})),e.languages.rust={comment:[{pattern:RegExp(/(^|[^\\])/.source+t),lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/,greedy:!0},char:{pattern:/b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/,greedy:!0},attribute:{pattern:/#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/,greedy:!0,alias:"attr-name",inside:{string:null}},"closure-params":{pattern:/([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/,lookbehind:!0,greedy:!0,inside:{"closure-punctuation":{pattern:/^\||\|$/,alias:"punctuation"},rest:null}},"lifetime-annotation":{pattern:/'\w+/,alias:"symbol"},"fragment-specifier":{pattern:/(\$\w+:)[a-z]+/,lookbehind:!0,alias:"punctuation"},variable:/\$\w+/,"function-definition":{pattern:/(\bfn\s+)\w+/,lookbehind:!0,alias:"function"},"type-definition":{pattern:/(\b(?:enum|struct|trait|type|union)\s+)\w+/,lookbehind:!0,alias:"class-name"},"module-declaration":[{pattern:/(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/,lookbehind:!0,alias:"namespace"},{pattern:/(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/,lookbehind:!0,alias:"namespace",inside:{punctuation:/::/}}],keyword:[/\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/,/\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/],function:/\b[a-z_]\w*(?=\s*(?:::\s*<|\())/,macro:{pattern:/\b\w+!/,alias:"property"},constant:/\b[A-Z_][A-Z_\d]+\b/,"class-name":/\b[A-Z]\w*\b/,namespace:{pattern:/(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/,inside:{punctuation:/::/}},number:/\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/,boolean:/\b(?:false|true)\b/,punctuation:/->|\.\.=|\.{1,3}|::|[{}[\];(),:]/,operator:/[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/},e.languages.rust["closure-params"].inside.rest=e.languages.rust,e.languages.rust.attribute.inside.string=e.languages.rust.string}(A),A.languages.go=A.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),A.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete A.languages.go["class-name"],function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(A),A.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},A.languages.python["string-interpolation"].inside.interpolation.inside.rest=A.languages.python,A.languages.py=A.languages.python;((e,t)=>{for(var n in t)p(e,n,{get:t[n],enumerable:!0})})({},{dracula:()=>C,duotoneDark:()=>R,duotoneLight:()=>O,github:()=>N,jettwaveDark:()=>G,jettwaveLight:()=>V,nightOwl:()=>I,nightOwlLight:()=>L,oceanicNext:()=>M,okaidia:()=>j,oneDark:()=>W,oneLight:()=>Y,palenight:()=>U,shadesOfPurple:()=>F,synthwave84:()=>B,ultramin:()=>z,vsDark:()=>$,vsLight:()=>H});var C={plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},R={plain:{backgroundColor:"#2a2734",color:"#9a86fd"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#6c6783"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#e09142"}},{types:["property","function"],style:{color:"#9a86fd"}},{types:["tag-id","selector","atrule-id"],style:{color:"#eeebff"}},{types:["attr-name"],style:{color:"#c4b9fe"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule","placeholder","variable"],style:{color:"#ffcc99"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#c4b9fe"}}]},O={plain:{backgroundColor:"#faf8f5",color:"#728fcb"},styles:[{types:["comment","prolog","doctype","cdata","punctuation"],style:{color:"#b6ad9a"}},{types:["namespace"],style:{opacity:.7}},{types:["tag","operator","number"],style:{color:"#063289"}},{types:["property","function"],style:{color:"#b29762"}},{types:["tag-id","selector","atrule-id"],style:{color:"#2d2006"}},{types:["attr-name"],style:{color:"#896724"}},{types:["boolean","string","entity","url","attr-value","keyword","control","directive","unit","statement","regex","atrule"],style:{color:"#728fcb"}},{types:["placeholder","variable"],style:{color:"#93abdc"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"#896724"}}]},N={plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},I={plain:{color:"#d6deeb",backgroundColor:"#011627"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(99, 119, 119)",fontStyle:"italic"}},{types:["string","url"],style:{color:"rgb(173, 219, 103)"}},{types:["variable"],style:{color:"rgb(214, 222, 235)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation"],style:{color:"rgb(199, 146, 234)"}},{types:["selector","doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(255, 203, 139)"}},{types:["tag","operator","keyword"],style:{color:"rgb(127, 219, 202)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["property"],style:{color:"rgb(128, 203, 196)"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}}]},L={plain:{color:"#403f53",backgroundColor:"#FBFBFB"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)",fontStyle:"italic"}},{types:["inserted","attr-name"],style:{color:"rgb(72, 118, 214)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(152, 159, 177)",fontStyle:"italic"}},{types:["string","builtin","char","constant","url"],style:{color:"rgb(72, 118, 214)"}},{types:["variable"],style:{color:"rgb(201, 103, 101)"}},{types:["number"],style:{color:"rgb(170, 9, 130)"}},{types:["punctuation"],style:{color:"rgb(153, 76, 195)"}},{types:["function","selector","doctype"],style:{color:"rgb(153, 76, 195)",fontStyle:"italic"}},{types:["class-name"],style:{color:"rgb(17, 17, 17)"}},{types:["tag"],style:{color:"rgb(153, 76, 195)"}},{types:["operator","property","keyword","namespace"],style:{color:"rgb(12, 150, 155)"}},{types:["boolean"],style:{color:"rgb(188, 84, 84)"}}]},P="#c5a5c5",D="#8dc891",M={plain:{backgroundColor:"#282c34",color:"#ffffff"},styles:[{types:["attr-name"],style:{color:P}},{types:["attr-value"],style:{color:D}},{types:["comment","block-comment","prolog","doctype","cdata","shebang"],style:{color:"#999999"}},{types:["property","number","function-name","constant","symbol","deleted"],style:{color:"#5a9bcf"}},{types:["boolean"],style:{color:"#ff8b50"}},{types:["tag"],style:{color:"#fc929e"}},{types:["string"],style:{color:D}},{types:["punctuation"],style:{color:D}},{types:["selector","char","builtin","inserted"],style:{color:"#D8DEE9"}},{types:["function"],style:{color:"#79b6f2"}},{types:["operator","entity","url","variable"],style:{color:"#d7deea"}},{types:["keyword"],style:{color:P}},{types:["atrule","class-name"],style:{color:"#FAC863"}},{types:["important"],style:{fontWeight:"400"}},{types:["bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}}]},j={plain:{color:"#f8f8f2",backgroundColor:"#272822"},styles:[{types:["changed"],style:{color:"rgb(162, 191, 252)",fontStyle:"italic"}},{types:["deleted"],style:{color:"#f92672",fontStyle:"italic"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)",fontStyle:"italic"}},{types:["comment"],style:{color:"#8292a2",fontStyle:"italic"}},{types:["string","url"],style:{color:"#a6e22e"}},{types:["variable"],style:{color:"#f8f8f2"}},{types:["number"],style:{color:"#ae81ff"}},{types:["builtin","char","constant","function","class-name"],style:{color:"#e6db74"}},{types:["punctuation"],style:{color:"#f8f8f2"}},{types:["selector","doctype"],style:{color:"#a6e22e",fontStyle:"italic"}},{types:["tag","operator","keyword"],style:{color:"#66d9ef"}},{types:["boolean"],style:{color:"#ae81ff"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)",opacity:.7}},{types:["tag","property"],style:{color:"#f92672"}},{types:["attr-name"],style:{color:"#a6e22e !important"}},{types:["doctype"],style:{color:"#8292a2"}},{types:["rule"],style:{color:"#e6db74"}}]},U={plain:{color:"#bfc7d5",backgroundColor:"#292d3e"},styles:[{types:["comment"],style:{color:"rgb(105, 112, 152)",fontStyle:"italic"}},{types:["string","inserted"],style:{color:"rgb(195, 232, 141)"}},{types:["number"],style:{color:"rgb(247, 140, 108)"}},{types:["builtin","char","constant","function"],style:{color:"rgb(130, 170, 255)"}},{types:["punctuation","selector"],style:{color:"rgb(199, 146, 234)"}},{types:["variable"],style:{color:"rgb(191, 199, 213)"}},{types:["class-name","attr-name"],style:{color:"rgb(255, 203, 107)"}},{types:["tag","deleted"],style:{color:"rgb(255, 85, 114)"}},{types:["operator"],style:{color:"rgb(137, 221, 255)"}},{types:["boolean"],style:{color:"rgb(255, 88, 116)"}},{types:["keyword"],style:{fontStyle:"italic"}},{types:["doctype"],style:{color:"rgb(199, 146, 234)",fontStyle:"italic"}},{types:["namespace"],style:{color:"rgb(178, 204, 214)"}},{types:["url"],style:{color:"rgb(221, 221, 221)"}}]},F={plain:{color:"#9EFEFF",backgroundColor:"#2D2A55"},styles:[{types:["changed"],style:{color:"rgb(255, 238, 128)"}},{types:["deleted"],style:{color:"rgba(239, 83, 80, 0.56)"}},{types:["inserted"],style:{color:"rgb(173, 219, 103)"}},{types:["comment"],style:{color:"rgb(179, 98, 255)",fontStyle:"italic"}},{types:["punctuation"],style:{color:"rgb(255, 255, 255)"}},{types:["constant"],style:{color:"rgb(255, 98, 140)"}},{types:["string","url"],style:{color:"rgb(165, 255, 144)"}},{types:["variable"],style:{color:"rgb(255, 238, 128)"}},{types:["number","boolean"],style:{color:"rgb(255, 98, 140)"}},{types:["attr-name"],style:{color:"rgb(255, 180, 84)"}},{types:["keyword","operator","property","namespace","tag","selector","doctype"],style:{color:"rgb(255, 157, 0)"}},{types:["builtin","char","constant","function","class-name"],style:{color:"rgb(250, 208, 0)"}}]},B={plain:{backgroundColor:"linear-gradient(to bottom, #2a2139 75%, #34294f)",backgroundImage:"#34294f",color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"},styles:[{types:["comment","block-comment","prolog","doctype","cdata"],style:{color:"#495495",fontStyle:"italic"}},{types:["punctuation"],style:{color:"#ccc"}},{types:["tag","attr-name","namespace","number","unit","hexcode","deleted"],style:{color:"#e2777a"}},{types:["property","selector"],style:{color:"#72f1b8",textShadow:"0 0 2px #100c0f, 0 0 10px #257c5575, 0 0 35px #21272475"}},{types:["function-name"],style:{color:"#6196cc"}},{types:["boolean","selector-id","function"],style:{color:"#fdfdfd",textShadow:"0 0 2px #001716, 0 0 3px #03edf975, 0 0 5px #03edf975, 0 0 8px #03edf975"}},{types:["class-name","maybe-class-name","builtin"],style:{color:"#fff5f6",textShadow:"0 0 2px #000, 0 0 10px #fc1f2c75, 0 0 5px #fc1f2c75, 0 0 25px #fc1f2c75"}},{types:["constant","symbol"],style:{color:"#f92aad",textShadow:"0 0 2px #100c0f, 0 0 5px #dc078e33, 0 0 10px #fff3"}},{types:["important","atrule","keyword","selector-class"],style:{color:"#f4eee4",textShadow:"0 0 2px #393a33, 0 0 8px #f39f0575, 0 0 2px #f39f0575"}},{types:["string","char","attr-value","regex","variable"],style:{color:"#f87c32"}},{types:["parameter"],style:{fontStyle:"italic"}},{types:["entity","url"],style:{color:"#67cdcc"}},{types:["operator"],style:{color:"ffffffee"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["entity"],style:{cursor:"help"}},{types:["inserted"],style:{color:"green"}}]},z={plain:{color:"#282a2e",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(197, 200, 198)"}},{types:["string","number","builtin","variable"],style:{color:"rgb(150, 152, 150)"}},{types:["class-name","function","tag","attr-name"],style:{color:"rgb(40, 42, 46)"}}]},$={plain:{color:"#9CDCFE",backgroundColor:"#1E1E1E"},styles:[{types:["prolog"],style:{color:"rgb(0, 0, 128)"}},{types:["comment"],style:{color:"rgb(106, 153, 85)"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"rgb(86, 156, 214)"}},{types:["number","inserted"],style:{color:"rgb(181, 206, 168)"}},{types:["constant"],style:{color:"rgb(100, 102, 149)"}},{types:["attr-name","variable"],style:{color:"rgb(156, 220, 254)"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"rgb(206, 145, 120)"}},{types:["selector"],style:{color:"rgb(215, 186, 125)"}},{types:["tag"],style:{color:"rgb(78, 201, 176)"}},{types:["tag"],languages:["markup"],style:{color:"rgb(86, 156, 214)"}},{types:["punctuation","operator"],style:{color:"rgb(212, 212, 212)"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"rgb(220, 220, 170)"}},{types:["class-name"],style:{color:"rgb(78, 201, 176)"}},{types:["char"],style:{color:"rgb(209, 105, 105)"}}]},H={plain:{color:"#000000",backgroundColor:"#ffffff"},styles:[{types:["comment"],style:{color:"rgb(0, 128, 0)"}},{types:["builtin"],style:{color:"rgb(0, 112, 193)"}},{types:["number","variable","inserted"],style:{color:"rgb(9, 134, 88)"}},{types:["operator"],style:{color:"rgb(0, 0, 0)"}},{types:["constant","char"],style:{color:"rgb(129, 31, 63)"}},{types:["tag"],style:{color:"rgb(128, 0, 0)"}},{types:["attr-name"],style:{color:"rgb(255, 0, 0)"}},{types:["deleted","string"],style:{color:"rgb(163, 21, 21)"}},{types:["changed","punctuation"],style:{color:"rgb(4, 81, 165)"}},{types:["function","keyword"],style:{color:"rgb(0, 0, 255)"}},{types:["class-name"],style:{color:"rgb(38, 127, 153)"}}]},G={plain:{color:"#f8fafc",backgroundColor:"#011627"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#569CD6"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#f8fafc"}},{types:["attr-name","variable"],style:{color:"#9CDCFE"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#cbd5e1"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#D4D4D4"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#7dd3fc"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},V={plain:{color:"#0f172a",backgroundColor:"#f1f5f9"},styles:[{types:["prolog"],style:{color:"#000080"}},{types:["comment"],style:{color:"#6A9955"}},{types:["builtin","changed","keyword","interpolation-punctuation"],style:{color:"#0c4a6e"}},{types:["number","inserted"],style:{color:"#B5CEA8"}},{types:["constant"],style:{color:"#0f172a"}},{types:["attr-name","variable"],style:{color:"#0c4a6e"}},{types:["deleted","string","attr-value","template-punctuation"],style:{color:"#64748b"}},{types:["selector"],style:{color:"#D7BA7D"}},{types:["tag"],style:{color:"#0ea5e9"}},{types:["tag"],languages:["markup"],style:{color:"#0ea5e9"}},{types:["punctuation","operator"],style:{color:"#475569"}},{types:["punctuation"],languages:["markup"],style:{color:"#808080"}},{types:["function"],style:{color:"#0e7490"}},{types:["class-name"],style:{color:"#0ea5e9"}},{types:["char"],style:{color:"#D16969"}}]},W={plain:{backgroundColor:"hsl(220, 13%, 18%)",color:"hsl(220, 14%, 71%)",textShadow:"0 1px rgba(0, 0, 0, 0.3)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(220, 10%, 40%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(220, 14%, 71%)"}},{types:["attr-name","class-name","maybe-class-name","boolean","constant","number","atrule"],style:{color:"hsl(29, 54%, 61%)"}},{types:["keyword"],style:{color:"hsl(286, 60%, 67%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(355, 65%, 65%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value"],style:{color:"hsl(95, 38%, 62%)"}},{types:["variable","operator","function"],style:{color:"hsl(207, 82%, 66%)"}},{types:["url"],style:{color:"hsl(187, 47%, 55%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(220, 14%, 71%)"}}]},Y={plain:{backgroundColor:"hsl(230, 1%, 98%)",color:"hsl(230, 8%, 24%)"},styles:[{types:["comment","prolog","cdata"],style:{color:"hsl(230, 4%, 64%)"}},{types:["doctype","punctuation","entity"],style:{color:"hsl(230, 8%, 24%)"}},{types:["attr-name","class-name","boolean","constant","number","atrule"],style:{color:"hsl(35, 99%, 36%)"}},{types:["keyword"],style:{color:"hsl(301, 63%, 40%)"}},{types:["property","tag","symbol","deleted","important"],style:{color:"hsl(5, 74%, 59%)"}},{types:["selector","string","char","builtin","inserted","regex","attr-value","punctuation"],style:{color:"hsl(119, 34%, 47%)"}},{types:["variable","operator","function"],style:{color:"hsl(221, 87%, 60%)"}},{types:["url"],style:{color:"hsl(198, 99%, 37%)"}},{types:["deleted"],style:{textDecorationLine:"line-through"}},{types:["inserted"],style:{textDecorationLine:"underline"}},{types:["italic"],style:{fontStyle:"italic"}},{types:["important","bold"],style:{fontWeight:"bold"}},{types:["important"],style:{color:"hsl(230, 8%, 24%)"}}]},K=(e,t)=>{const{plain:n}=e,r=e.styles.reduce(((e,n)=>{const{languages:r,style:a}=n;return r&&!r.includes(t)||n.types.forEach((t=>{const n=w(w({},e[t]),a);e[t]=n})),e}),{});return r.root=n,r.plain=k(w({},n),{backgroundColor:void 0}),r},q=/\r\n|\r|\n/,X=e=>{0===e.length?e.push({types:["plain"],content:"\n",empty:!0}):1===e.length&&""===e[0].content&&(e[0].content="\n",e[0].empty=!0)},Q=(e,t)=>{const n=e.length;return n>0&&e[n-1]===t?e:e.concat(t)},Z=e=>{const t=[[]],n=[e],r=[0],a=[e.length];let o=0,i=0,l=[];const s=[l];for(;i>-1;){for(;(o=r[i]++)<a[i];){let e,u=t[i];const c=n[i][o];if("string"==typeof c?(u=i>0?u:["plain"],e=c):(u=Q(u,c.type),c.alias&&(u=Q(u,c.alias)),e=c.content),"string"!=typeof e){i++,t.push(u),n.push(e),r.push(0),a.push(e.length);continue}const d=e.split(q),f=d.length;l.push({types:u,content:d[0]});for(let t=1;t<f;t++)X(l),s.push(l=[]),l.push({types:u,content:d[t]})}i--,t.pop(),n.pop(),r.pop(),a.pop()}return X(l),s},J=({children:e,language:t,code:n,theme:r,prism:a})=>{const o=t.toLowerCase(),i=((e,t)=>{const[n,r]=(0,c.useState)(K(t,e)),a=(0,c.useRef)(),o=(0,c.useRef)();return(0,c.useEffect)((()=>{t===a.current&&e===o.current||(a.current=t,o.current=e,r(K(t,e)))}),[e,t]),n})(o,r),l=(e=>(0,c.useCallback)((t=>{var n=t,{className:r,style:a,line:o}=n,i=T(n,["className","style","line"]);const l=k(w({},i),{className:(0,d.A)("token-line",r)});return"object"==typeof e&&"plain"in e&&(l.style=e.plain),"object"==typeof a&&(l.style=w(w({},l.style||{}),a)),l}),[e]))(i),s=(e=>{const t=(0,c.useCallback)((({types:t,empty:n})=>{if(null!=e)return 1===t.length&&"plain"===t[0]?null!=n?{display:"inline-block"}:void 0:1===t.length&&null!=n?e[t[0]]:Object.assign(null!=n?{display:"inline-block"}:{},...t.map((t=>e[t])))}),[e]);return(0,c.useCallback)((e=>{var n=e,{token:r,className:a,style:o}=n,i=T(n,["token","className","style"]);const l=k(w({},i),{className:(0,d.A)("token",...r.types,a),children:r.content,style:t(r)});return null!=o&&(l.style=w(w({},l.style||{}),o)),l}),[t])})(i),u=(({prism:e,code:t,grammar:n,language:r})=>{const a=(0,c.useRef)(e);return(0,c.useMemo)((()=>{if(null==n)return Z([t]);const e={code:t,grammar:n,language:r,tokens:[]};return a.current.hooks.run("before-tokenize",e),e.tokens=a.current.tokenize(t,n),a.current.hooks.run("after-tokenize",e),Z(e.tokens)}),[t,n,r])})({prism:a,language:o,code:n,grammar:a.languages[o]});return e({tokens:u,className:`prism-code language-${o}`,style:null!=i?i.root:{},getLineProps:l,getTokenProps:s})},ee=e=>(0,c.createElement)(J,k(w({},e),{prism:e.prism||A,theme:e.theme||$,code:e.code,language:e.language}))},1561:(e,t,n)=>{"use strict";n.d(t,{A:()=>o});var r=!0,a="Invariant failed";function o(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,o=n?"".concat(a,": ").concat(n):a;throw new Error(o)}}},2654:e=>{"use strict";e.exports={}},4054:e=>{"use strict";e.exports=JSON.parse('{"/search-5de":{"__comp":"1a4e3797","__context":{"plugin":"c141421f"}},"/-dbe":{"__comp":"5e95c892","__context":{"plugin":"aba21aa0"}},"/-8df":{"__comp":"a7bd4aaa","__props":"6629c45f"},"/-017":{"__comp":"a94703ab"},"/building/hello-world-9c2":{"__comp":"17896441","content":"feaee7f3"},"/building/migrations-531":{"__comp":"17896441","content":"8a8faf8d"},"/building/tinyorm-b57":{"__comp":"17896441","content":"0ab078a9"},"/database/getting-started-0b1":{"__comp":"17896441","content":"ba3d4959"},"/database/migrations-6de":{"__comp":"17896441","content":"21dc2778"},"/database/query-builder-2bb":{"__comp":"17896441","content":"cbe663fe"},"/database/seeding-9c2":{"__comp":"17896441","content":"a4d3e054"},"/dependencies-a43":{"__comp":"17896441","content":"e3ac21cb"},"/features-summary-235":{"__comp":"17896441","content":"fb313d4e"},"/sponsors-3aa":{"__comp":"17896441","content":"e19c288b"},"/supported-compilers-699":{"__comp":"17896441","content":"d459b1c4"},"/tinydrivers/getting-started-071":{"__comp":"17896441","content":"cb1e72f9"},"/tinyorm/casts-09c":{"__comp":"17896441","content":"62a1276f"},"/tinyorm/collections-5b8":{"__comp":"17896441","content":"3dd307b5"},"/tinyorm/getting-started-699":{"__comp":"17896441","content":"5b254f70"},"/tinyorm/relationships-80b":{"__comp":"17896441","content":"7333c691"},"/tinyorm/serialization-b90":{"__comp":"17896441","content":"1222ea4e"},"/-f1e":{"__comp":"17896441","content":"59b1a96c"}}')}},e=>{e.O(0,[869],(()=>{return t=6756,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/assets/js/main.f840787c.js.LICENSE.txt b/assets/js/main.120f60f5.js.LICENSE.txt similarity index 76% rename from assets/js/main.f840787c.js.LICENSE.txt rename to assets/js/main.120f60f5.js.LICENSE.txt index eb75d6910..91dc89499 100644 --- a/assets/js/main.f840787c.js.LICENSE.txt +++ b/assets/js/main.120f60f5.js.LICENSE.txt @@ -1,15 +1,22 @@ -/* -object-assign -(c) Sindre Sorhus -@license MIT -*/ - /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress * @license MIT */ +/*! Bundled license information: + +prismjs/prism.js: + (** + * Prism: Lightweight, robust, elegant syntax highlighting + * + * @license MIT <https://opensource.org/licenses/MIT> + * @author Lea Verou <https://lea.verou.me> + * @namespace + * @public + *) +*/ + /** * @license React - * use-sync-external-store-shim.production.min.js + * react-dom.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * @@ -18,16 +25,8 @@ object-assign */ /** - * Prism: Lightweight, robust, elegant syntax highlighting - * - * @license MIT <https://opensource.org/licenses/MIT> - * @author Lea Verou <https://lea.verou.me> - * @namespace - * @public - */ - -/** @license React v0.20.2 - * scheduler.production.min.js + * @license React + * react-jsx-runtime.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * @@ -35,8 +34,9 @@ object-assign * LICENSE file in the root directory of this source tree. */ -/** @license React v16.13.1 - * react-is.production.min.js +/** + * @license React + * react.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * @@ -44,8 +44,9 @@ object-assign * LICENSE file in the root directory of this source tree. */ -/** @license React v17.0.2 - * react-dom.production.min.js +/** + * @license React + * scheduler.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * @@ -53,8 +54,8 @@ object-assign * LICENSE file in the root directory of this source tree. */ -/** @license React v17.0.2 - * react.production.min.js +/** @license React v16.13.1 + * react-is.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * diff --git a/assets/js/main.f840787c.js b/assets/js/main.f840787c.js deleted file mode 100644 index 7e75e8a27..000000000 --- a/assets/js/main.f840787c.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.f840787c.js.LICENSE.txt */ -(self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[]).push([[179],{830:(e,t,n)=>{"use strict";n.d(t,{W:()=>a});var r=n(7294);function a(){return r.createElement("svg",{width:"20",height:"20",className:"DocSearch-Search-Icon",viewBox:"0 0 20 20"},r.createElement("path",{d:"M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z",stroke:"currentColor",fill:"none",fillRule:"evenodd",strokeLinecap:"round",strokeLinejoin:"round"}))}},723:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7294),a=n(7462),o=n(8356),i=n.n(o),l=n(6887);const s={"0ab078a9":[()=>Promise.all([n.e(532),n.e(176),n.e(969)]).then(n.bind(n,4040)),"@site/docs/building/tinyorm.mdx",4040],"1222ea4e":[()=>n.e(535).then(n.bind(n,1412)),"@site/docs/tinyorm/serialization.mdx",1412],17896441:[()=>Promise.all([n.e(532),n.e(176),n.e(918)]).then(n.bind(n,5836)),"@theme/DocItem",5836],"1a4e3797":[()=>Promise.all([n.e(532),n.e(920)]).then(n.bind(n,6675)),"@theme/SearchPage",6675],"1be78505":[()=>Promise.all([n.e(532),n.e(514)]).then(n.bind(n,9963)),"@theme/DocPage",9963],"21dc2778":[()=>Promise.all([n.e(532),n.e(176),n.e(291)]).then(n.bind(n,6122)),"@site/docs/database/migrations.mdx",6122],"3dd307b5":[()=>n.e(108).then(n.bind(n,8503)),"@site/docs/tinyorm/collections.mdx",8503],"59b1a96c":[()=>n.e(67).then(n.bind(n,2075)),"@site/docs/README.mdx",2075],"5b254f70":[()=>n.e(116).then(n.bind(n,7923)),"@site/docs/tinyorm/getting-started.mdx",7923],"62a1276f":[()=>n.e(57).then(n.bind(n,9823)),"@site/docs/tinyorm/casts.mdx",9823],"7333c691":[()=>n.e(799).then(n.bind(n,7273)),"@site/docs/tinyorm/relationships.mdx",7273],"8156e19a":[()=>n.e(683).then(n.t.bind(n,3769,19)),"E:\\code\\nodejs\\TinyORM-github.io\\.docusaurus\\docusaurus-plugin-content-docs\\default\\plugin-route-context-module-100.json",3769],"8a8faf8d":[()=>Promise.all([n.e(532),n.e(176),n.e(225)]).then(n.bind(n,3974)),"@site/docs/building/migrations.mdx",3974],"935f2afb":[()=>n.e(53).then(n.t.bind(n,1109,19)),"~docs/default/version-current-metadata-prop-751.json",1109],a4d3e054:[()=>n.e(454).then(n.bind(n,8261)),"@site/docs/database/seeding.mdx",8261],ba3d4959:[()=>Promise.all([n.e(532),n.e(784)]).then(n.bind(n,288)),"@site/docs/database/getting-started.mdx",288],cb1e72f9:[()=>n.e(684).then(n.bind(n,5955)),"@site/docs/tinydrivers/getting-started.mdx",5955],cbe663fe:[()=>n.e(594).then(n.bind(n,9542)),"@site/docs/database/query-builder.mdx",9542],cdf0eeb2:[()=>n.e(113).then(n.t.bind(n,7085,19)),"E:\\code\\nodejs\\TinyORM-github.io\\.docusaurus\\docusaurus-theme-search-algolia\\default\\plugin-route-context-module-100.json",7085],d459b1c4:[()=>n.e(966).then(n.bind(n,4742)),"@site/docs/supported-compilers.mdx",4742],e19c288b:[()=>Promise.all([n.e(532),n.e(865)]).then(n.bind(n,6903)),"@site/docs/sponsors.mdx",6903],e3ac21cb:[()=>n.e(8).then(n.bind(n,5136)),"@site/docs/dependencies.mdx",5136],fb313d4e:[()=>n.e(832).then(n.bind(n,4716)),"@site/docs/features-summary.mdx",4716],feaee7f3:[()=>Promise.all([n.e(532),n.e(176),n.e(168)]).then(n.bind(n,4588)),"@site/docs/building/hello-world.mdx",4588]};function u(e){let{error:t,retry:n,pastDelay:a}=e;return t?r.createElement("div",{style:{textAlign:"center",color:"#fff",backgroundColor:"#fa383e",borderColor:"#fa383e",borderStyle:"solid",borderRadius:"0.25rem",borderWidth:"1px",boxSizing:"border-box",display:"block",padding:"1rem",flex:"0 0 50%",marginLeft:"25%",marginRight:"25%",marginTop:"5rem",maxWidth:"50%",width:"100%"}},r.createElement("p",null,String(t)),r.createElement("div",null,r.createElement("button",{type:"button",onClick:n},"Retry"))):a?r.createElement("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",height:"100vh"}},r.createElement("svg",{id:"loader",style:{width:128,height:110,position:"absolute",top:"calc(100vh - 64%)"},viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",stroke:"#61dafb"},r.createElement("g",{fill:"none",fillRule:"evenodd",transform:"translate(1 1)",strokeWidth:"2"},r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"1.5s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"1.5s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"1.5s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"6",strokeOpacity:"0"},r.createElement("animate",{attributeName:"r",begin:"3s",dur:"3s",values:"6;22",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-opacity",begin:"3s",dur:"3s",values:"1;0",calcMode:"linear",repeatCount:"indefinite"}),r.createElement("animate",{attributeName:"stroke-width",begin:"3s",dur:"3s",values:"2;0",calcMode:"linear",repeatCount:"indefinite"})),r.createElement("circle",{cx:"22",cy:"22",r:"8"},r.createElement("animate",{attributeName:"r",begin:"0s",dur:"1.5s",values:"6;1;2;3;4;5;6",calcMode:"linear",repeatCount:"indefinite"}))))):null}var c=n(9670),d=n(226);function f(e,t){if("*"===e)return i()({loading:u,loader:()=>n.e(972).then(n.bind(n,4972)),modules:["@theme/NotFound"],webpack:()=>[4972],render(e,t){const n=e.default;return r.createElement(d.z,{value:{plugin:{name:"native",id:"default"}}},r.createElement(n,t))}});const o=l[`${e}-${t}`],f={},p=[],m=[],h=(0,c.Z)(o);return Object.entries(h).forEach((e=>{let[t,n]=e;const r=s[n];r&&(f[t]=r[0],p.push(r[1]),m.push(r[2]))})),i().Map({loading:u,loader:f,modules:p,webpack:()=>m,render(t,n){const i=JSON.parse(JSON.stringify(o));Object.entries(t).forEach((t=>{let[n,r]=t;const a=r.default;if(!a)throw new Error(`The page component at ${e} doesn't have a default export. This makes it impossible to render anything. Consider default-exporting a React component.`);"object"!=typeof a&&"function"!=typeof a||Object.keys(r).filter((e=>"default"!==e)).forEach((e=>{a[e]=r[e]}));let o=i;const l=n.split(".");l.slice(0,-1).forEach((e=>{o=o[e]})),o[l[l.length-1]]=a}));const l=i.__comp;delete i.__comp;const s=i.__context;return delete i.__context,r.createElement(d.z,{value:s},r.createElement(l,(0,a.Z)({},i,n)))}})}const p=[{path:"/search",component:f("/search","c88"),exact:!0},{path:"/",component:f("/","848"),routes:[{path:"/",component:f("/","b76"),exact:!0,sidebar:"tinyormSidebar"},{path:"/building/hello-world",component:f("/building/hello-world","acb"),exact:!0,sidebar:"tinyormSidebar"},{path:"/building/migrations",component:f("/building/migrations","06d"),exact:!0,sidebar:"tinyormSidebar"},{path:"/building/tinyorm",component:f("/building/tinyorm","b42"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/getting-started",component:f("/database/getting-started","cc8"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/migrations",component:f("/database/migrations","15a"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/query-builder",component:f("/database/query-builder","258"),exact:!0,sidebar:"tinyormSidebar"},{path:"/database/seeding",component:f("/database/seeding","358"),exact:!0,sidebar:"tinyormSidebar"},{path:"/dependencies",component:f("/dependencies","a89"),exact:!0,sidebar:"tinyormSidebar"},{path:"/features-summary",component:f("/features-summary","652"),exact:!0,sidebar:"tinyormSidebar"},{path:"/sponsors",component:f("/sponsors","c1d"),exact:!0,sidebar:"tinyormSidebar"},{path:"/supported-compilers",component:f("/supported-compilers","24e"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinydrivers/getting-started",component:f("/tinydrivers/getting-started","d48"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/casts",component:f("/tinyorm/casts","331"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/collections",component:f("/tinyorm/collections","35b"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/getting-started",component:f("/tinyorm/getting-started","715"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/relationships",component:f("/tinyorm/relationships","04a"),exact:!0,sidebar:"tinyormSidebar"},{path:"/tinyorm/serialization",component:f("/tinyorm/serialization","9c7"),exact:!0,sidebar:"tinyormSidebar"}]},{path:"*",component:f("*")}]},8934:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,t:()=>o});var r=n(7294);const a=r.createContext(!1);function o(e){let{children:t}=e;const[n,o]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{o(!0)}),[]),r.createElement(a.Provider,{value:n},t)}},85:(e,t,n)=>{"use strict";var r=n(7294),a=n(3935),o=n(3727),i=n(405),l=n(412);const s=[n(6657),n(2497),n(7021),n(8320),n(8213)];var u=n(723),c=n(6550),d=n(8790),f=n(9482),p=n(12);const m="tinyorm.rootFolder.",h=()=>{const[e,t]=(0,r.useState)({}),n=(0,r.useCallback)(((e,t)=>{(0,p.WA)(`${m}${e}`).set(t)}),[]);return(0,r.useEffect)((()=>{try{const e={};(0,p._f)().forEach((t=>{if(t.startsWith(m)){const n=t.substring(19);e[n]=(0,p.WA)(t).get()}})),t(e)}catch(e){console.error(e)}}),[]),{rootFolder:e,setRootFolder:(e,r)=>{t((t=>({...t,[e]:r}))),n(e,r)}}};function g(e){const{rootFolder:t,setRootFolder:n}=h(),a=(0,r.useMemo)((()=>({rootFolder:t,setRootFolder:n})),[t,n]);return r.createElement(f.Z.Provider,{value:a},e.children)}let b,v,y,E=0;function S(){const e=document.querySelector('.theme-doc-sidebar-container div[title="Expand sidebar"]');e&&(e.title+=" (q)",clearTimeout(v))}function _(){y=document.querySelector(".theme-doc-sidebar-container > div > div > button"),E>=50?clearInterval(b):y?(y.title+=" (q)",clearInterval(b),y.addEventListener("click",(()=>{v=setTimeout(S,300)}))):++E}function w(e){e.target.isContentEditable||"INPUT"===e.target.nodeName||"TEXTAREA"===e.target.nodeName||"SELECT"===e.target.nodeName||"KeyQ"===e.code&&(y.click(),v=setTimeout(S,300))}function T(){var e;e=()=>{b=setInterval(_,30),document.addEventListener("keyup",w)},"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)}function k(e){let{children:t}=e;return r.createElement(g,null,t)}l.Z.canUseDOM&&T();var C=n(7462),A=n(5742),I=n(2263),O=n(4996),R=n(6668),N=n(833),L=n(4711),P=n(9727),x=n(3320),D=n(8780),M=n(197);function U(){const{i18n:{defaultLocale:e,localeConfigs:t}}=(0,I.Z)(),n=(0,L.l)();return r.createElement(A.Z,null,Object.entries(t).map((e=>{let[t,{htmlLang:a}]=e;return r.createElement("link",{key:t,rel:"alternate",href:n.createUrl({locale:t,fullyQualified:!0}),hrefLang:a})})),r.createElement("link",{rel:"alternate",href:n.createUrl({locale:e,fullyQualified:!0}),hrefLang:"x-default"}))}function F(e){let{permalink:t}=e;const{siteConfig:{url:n}}=(0,I.Z)(),a=function(){const{siteConfig:{url:e,baseUrl:t,trailingSlash:n}}=(0,I.Z)(),{pathname:r}=(0,c.TH)();return e+(0,D.applyTrailingSlash)((0,O.Z)(r),{trailingSlash:n,baseUrl:t})}(),o=t?`${n}${t}`:a;return r.createElement(A.Z,null,r.createElement("meta",{property:"og:url",content:o}),r.createElement("link",{rel:"canonical",href:o}))}function B(){const{i18n:{currentLocale:e}}=(0,I.Z)(),{metadata:t,image:n}=(0,R.L)();return r.createElement(r.Fragment,null,r.createElement(A.Z,null,r.createElement("meta",{name:"twitter:card",content:"summary_large_image"}),r.createElement("body",{className:P.h})),n&&r.createElement(N.d,{image:n}),r.createElement(F,null),r.createElement(U,null),r.createElement(M.Z,{tag:x.HX,locale:e}),r.createElement(A.Z,null,t.map(((e,t)=>r.createElement("meta",(0,C.Z)({key:t},e))))))}const $=new Map;function z(e){if($.has(e.pathname))return{...e,pathname:$.get(e.pathname)};if((0,d.f)(u.Z,e.pathname).some((e=>{let{route:t}=e;return!0===t.exact})))return $.set(e.pathname,e.pathname),e;const t=e.pathname.trim().replace(/(?:\/index)?\.html$/,"")||"/";return $.set(e.pathname,t),{...e,pathname:t}}var H=n(8934),j=n(8940);function G(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];const a=s.map((t=>{const r=t.default?.[e]??t[e];return r?.(...n)}));return()=>a.forEach((e=>e?.()))}const Z=function(e){let{children:t,location:n,previousLocation:a}=e;return(0,r.useLayoutEffect)((()=>{a!==n&&(!function(e){let{location:t,previousLocation:n}=e;if(!n)return;const r=t.pathname===n.pathname,a=t.hash===n.hash,o=t.search===n.search;if(r&&a&&!o)return;const{hash:i}=t;if(i){const e=decodeURIComponent(i.substring(1)),t=document.getElementById(e);t?.scrollIntoView()}else window.scrollTo(0,0)}({location:n,previousLocation:a}),G("onRouteDidUpdate",{previousLocation:a,location:n}))}),[a,n]),t};function V(e){const t=Array.from(new Set([e,decodeURI(e)])).map((e=>(0,d.f)(u.Z,e))).flat();return Promise.all(t.map((e=>e.route.component.preload?.())))}class W extends r.Component{previousLocation;routeUpdateCleanupCb;constructor(e){super(e),this.previousLocation=null,this.routeUpdateCleanupCb=l.Z.canUseDOM?G("onRouteUpdate",{previousLocation:null,location:this.props.location}):()=>{},this.state={nextRouteHasLoaded:!0}}shouldComponentUpdate(e,t){if(e.location===this.props.location)return t.nextRouteHasLoaded;const n=e.location;return this.previousLocation=this.props.location,this.setState({nextRouteHasLoaded:!1}),this.routeUpdateCleanupCb=G("onRouteUpdate",{previousLocation:this.previousLocation,location:n}),V(n.pathname).then((()=>{this.routeUpdateCleanupCb(),this.setState({nextRouteHasLoaded:!0})})).catch((e=>{console.warn(e),window.location.reload()})),!1}render(){const{children:e,location:t}=this.props;return r.createElement(Z,{previousLocation:this.previousLocation,location:t},r.createElement(c.AW,{location:t,render:()=>e}))}}const Y=W,K="__docusaurus-base-url-issue-banner-container",X="__docusaurus-base-url-issue-banner",q="__docusaurus-base-url-issue-banner-suggestion-container",Q="__DOCUSAURUS_INSERT_BASEURL_BANNER";function J(e){return`\nwindow['${Q}'] = true;\n\ndocument.addEventListener('DOMContentLoaded', maybeInsertBanner);\n\nfunction maybeInsertBanner() {\n var shouldInsert = window['${Q}'];\n shouldInsert && insertBanner();\n}\n\nfunction insertBanner() {\n var bannerContainer = document.getElementById('${K}');\n if (!bannerContainer) {\n return;\n }\n var bannerHtml = ${JSON.stringify(function(e){return`\n<div id="${X}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">\n <p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>\n <p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>\n <p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${e}</span> ${"/"===e?" (default value)":""}</p>\n <p>We suggest trying baseUrl = <span id="${q}" style="font-weight: bold; color: green;"></span></p>\n</div>\n`}(e)).replace(/</g,"\\<")};\n bannerContainer.innerHTML = bannerHtml;\n var suggestionContainer = document.getElementById('${q}');\n var actualHomePagePath = window.location.pathname;\n var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'\n ? actualHomePagePath\n : actualHomePagePath + '/';\n suggestionContainer.innerHTML = suggestedBaseUrl;\n}\n`}function ee(){const{siteConfig:{baseUrl:e}}=(0,I.Z)();return(0,r.useLayoutEffect)((()=>{window[Q]=!1}),[]),r.createElement(r.Fragment,null,!l.Z.canUseDOM&&r.createElement(A.Z,null,r.createElement("script",null,J(e))),r.createElement("div",{id:K}))}function te(){const{siteConfig:{baseUrl:e,baseUrlIssueBanner:t}}=(0,I.Z)(),{pathname:n}=(0,c.TH)();return t&&n===e?r.createElement(ee,null):null}function ne(){const{siteConfig:{favicon:e,title:t,noIndex:n},i18n:{currentLocale:a,localeConfigs:o}}=(0,I.Z)(),i=(0,O.Z)(e),{htmlLang:l,direction:s}=o[a];return r.createElement(A.Z,null,r.createElement("html",{lang:l,dir:s}),r.createElement("title",null,t),r.createElement("meta",{property:"og:title",content:t}),r.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1.0"}),n&&r.createElement("meta",{name:"robots",content:"noindex, nofollow"}),e&&r.createElement("link",{rel:"icon",href:i}))}var re=n(4763),ae=n(2389);function oe(){const e=(0,ae.Z)();return r.createElement(A.Z,null,r.createElement("html",{"data-has-hydrated":e}))}function ie(){const e=(0,d.H)(u.Z),t=(0,c.TH)();return r.createElement(re.Z,null,r.createElement(j.M,null,r.createElement(H.t,null,r.createElement(k,null,r.createElement(ne,null),r.createElement(B,null),r.createElement(te,null),r.createElement(Y,{location:z(t)},e)),r.createElement(oe,null))))}var le=n(6887);const se=function(e){try{return document.createElement("link").relList.supports(e)}catch{return!1}}("prefetch")?function(e){return new Promise(((t,n)=>{if("undefined"==typeof document)return void n();const r=document.createElement("link");r.setAttribute("rel","prefetch"),r.setAttribute("href",e),r.onload=()=>t(),r.onerror=()=>n();const a=document.getElementsByTagName("head")[0]??document.getElementsByName("script")[0]?.parentNode;a?.appendChild(r)}))}:function(e){return new Promise(((t,n)=>{const r=new XMLHttpRequest;r.open("GET",e,!0),r.withCredentials=!0,r.onload=()=>{200===r.status?t():n()},r.send(null)}))};var ue=n(9670);const ce=new Set,de=new Set,fe=()=>navigator.connection?.effectiveType.includes("2g")||navigator.connection?.saveData,pe={prefetch(e){if(!(e=>!fe()&&!de.has(e)&&!ce.has(e))(e))return!1;ce.add(e);const t=(0,d.f)(u.Z,e).flatMap((e=>{return t=e.route.path,Object.entries(le).filter((e=>{let[n]=e;return n.replace(/-[^-]+$/,"")===t})).flatMap((e=>{let[,t]=e;return Object.values((0,ue.Z)(t))}));var t}));return Promise.all(t.map((e=>{const t=n.gca(e);return t&&!t.includes("undefined")?se(t).catch((()=>{})):Promise.resolve()})))},preload:e=>!!(e=>!fe()&&!de.has(e))(e)&&(de.add(e),V(e))},me=Object.freeze(pe);if(l.Z.canUseDOM){window.docusaurus=me;const e=a.hydrate;V(window.location.pathname).then((()=>{e(r.createElement(i.B6,null,r.createElement(o.VK,null,r.createElement(ie,null))),document.getElementById("__docusaurus"))}))}},8940:(e,t,n)=>{"use strict";n.d(t,{_:()=>c,M:()=>d});var r=n(7294),a=n(6809);const o=JSON.parse('{"docusaurus-plugin-google-gtag":{"default":{"trackingID":["G-2QRS622BWQ"],"anonymizeIP":false,"id":"default"}},"docusaurus-plugin-content-docs":{"default":{"path":"/","versions":[{"name":"current","label":"Next","isLast":true,"path":"/","mainDocId":"README","docs":[{"id":"building/hello-world","path":"/building/hello-world","sidebar":"tinyormSidebar"},{"id":"building/migrations","path":"/building/migrations","sidebar":"tinyormSidebar"},{"id":"building/tinyorm","path":"/building/tinyorm","sidebar":"tinyormSidebar"},{"id":"database/getting-started","path":"/database/getting-started","sidebar":"tinyormSidebar"},{"id":"database/migrations","path":"/database/migrations","sidebar":"tinyormSidebar"},{"id":"database/query-builder","path":"/database/query-builder","sidebar":"tinyormSidebar"},{"id":"database/seeding","path":"/database/seeding","sidebar":"tinyormSidebar"},{"id":"dependencies","path":"/dependencies","sidebar":"tinyormSidebar"},{"id":"features-summary","path":"/features-summary","sidebar":"tinyormSidebar"},{"id":"README","path":"/","sidebar":"tinyormSidebar"},{"id":"sponsors","path":"/sponsors","sidebar":"tinyormSidebar"},{"id":"supported-compilers","path":"/supported-compilers","sidebar":"tinyormSidebar"},{"id":"tinydrivers/getting-started","path":"/tinydrivers/getting-started","sidebar":"tinyormSidebar"},{"id":"tinyorm/casts","path":"/tinyorm/casts","sidebar":"tinyormSidebar"},{"id":"tinyorm/collections","path":"/tinyorm/collections","sidebar":"tinyormSidebar"},{"id":"tinyorm/getting-started","path":"/tinyorm/getting-started","sidebar":"tinyormSidebar"},{"id":"tinyorm/relationships","path":"/tinyorm/relationships","sidebar":"tinyormSidebar"},{"id":"tinyorm/serialization","path":"/tinyorm/serialization","sidebar":"tinyormSidebar"}],"draftIds":[],"sidebars":{"tinyormSidebar":{"link":{"path":"/","label":"\ud83d\udd25 Prologue"}}}}],"breadcrumbs":true}}}'),i=JSON.parse('{"defaultLocale":"en","locales":["en"],"path":"i18n","currentLocale":"en","localeConfigs":{"en":{"label":"English","direction":"ltr","htmlLang":"en","calendar":"gregory","path":"en"}}}');var l=n(7529);const s=JSON.parse('{"docusaurusVersion":"2.4.3","siteVersion":"0.3.3","pluginVersions":{"docusaurus-plugin-content-docs":{"type":"package","name":"@docusaurus/plugin-content-docs","version":"2.4.3"},"docusaurus-plugin-content-pages":{"type":"package","name":"@docusaurus/plugin-content-pages","version":"2.4.3"},"docusaurus-plugin-google-gtag":{"type":"package","name":"@docusaurus/plugin-google-gtag","version":"2.4.3"},"docusaurus-plugin-sitemap":{"type":"package","name":"@docusaurus/plugin-sitemap","version":"2.4.3"},"docusaurus-theme-classic":{"type":"package","name":"@docusaurus/theme-classic","version":"2.4.3"},"docusaurus-theme-search-algolia":{"type":"package","name":"@docusaurus/theme-search-algolia","version":"2.4.3"},"docusaurus-plugin-client-redirects":{"type":"package","name":"@docusaurus/plugin-client-redirects","version":"2.4.3"},"webpack-configuration-plugin":{"type":"local"},"postcss-configuration-plugin":{"type":"local"},"tiny-common":{"type":"local"}}}'),u={siteConfig:a.default,siteMetadata:s,globalData:o,i18n:i,codeTranslations:l},c=r.createContext(u);function d(e){let{children:t}=e;return r.createElement(c.Provider,{value:u},t)}},4763:(e,t,n)=>{"use strict";n.d(t,{Z:()=>f});var r=n(7294),a=n(412),o=n(5742),i=n(8780),l=n(7452);function s(e){let{error:t,tryAgain:n}=e;return r.createElement("div",{style:{display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"flex-start",minHeight:"100vh",width:"100%",maxWidth:"80ch",fontSize:"20px",margin:"0 auto",padding:"1rem"}},r.createElement("h1",{style:{fontSize:"3rem"}},"This page crashed"),r.createElement("button",{type:"button",onClick:n,style:{margin:"1rem 0",fontSize:"2rem",cursor:"pointer",borderRadius:20,padding:"1rem"}},"Try again"),r.createElement(u,{error:t}))}function u(e){let{error:t}=e;const n=(0,i.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{style:{whiteSpace:"pre-wrap"}},n)}function c(e){let{error:t,tryAgain:n}=e;return r.createElement(f,{fallback:()=>r.createElement(s,{error:t,tryAgain:n})},r.createElement(o.Z,null,r.createElement("title",null,"Page Error")),r.createElement(l.Z,null,r.createElement(s,{error:t,tryAgain:n})))}const d=e=>r.createElement(c,e);class f extends r.Component{constructor(e){super(e),this.state={error:null}}componentDidCatch(e){a.Z.canUseDOM&&this.setState({error:e})}render(){const{children:e}=this.props,{error:t}=this.state;if(t){const e={error:t,tryAgain:()=>this.setState({error:null})};return(this.props.fallback??d)(e)}return e??null}}},412:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r="undefined"!=typeof window&&"document"in window&&"createElement"in window.document,a={canUseDOM:r,canUseEventListeners:r&&("addEventListener"in window||"attachEvent"in window),canUseIntersectionObserver:r&&"IntersectionObserver"in window,canUseViewport:r&&"screen"in window}},5742:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(405);function o(e){return r.createElement(a.ql,e)}},9960:(e,t,n)=>{"use strict";n.d(t,{Z:()=>p});var r=n(7462),a=n(7294),o=n(3727),i=n(8780),l=n(2263),s=n(3919),u=n(412);const c=a.createContext({collectLink:()=>{}});var d=n(4996);function f(e,t){let{isNavLink:n,to:f,href:p,activeClassName:m,isActive:h,"data-noBrokenLinkCheck":g,autoAddBaseUrl:b=!0,...v}=e;const{siteConfig:{trailingSlash:y,baseUrl:E}}=(0,l.Z)(),{withBaseUrl:S}=(0,d.C)(),_=(0,a.useContext)(c),w=(0,a.useRef)(null);(0,a.useImperativeHandle)(t,(()=>w.current));const T=f||p;const k=(0,s.Z)(T),C=T?.replace("pathname://","");let A=void 0!==C?(I=C,b&&(e=>e.startsWith("/"))(I)?S(I):I):void 0;var I;A&&k&&(A=(0,i.applyTrailingSlash)(A,{trailingSlash:y,baseUrl:E}));const O=(0,a.useRef)(!1),R=n?o.OL:o.rU,N=u.Z.canUseIntersectionObserver,L=(0,a.useRef)(),P=()=>{O.current||null==A||(window.docusaurus.preload(A),O.current=!0)};(0,a.useEffect)((()=>(!N&&k&&null!=A&&window.docusaurus.prefetch(A),()=>{N&&L.current&&L.current.disconnect()})),[L,A,N,k]);const x=A?.startsWith("#")??!1,D=!A||!k||x;return D||g||_.collectLink(A),D?a.createElement("a",(0,r.Z)({ref:w,href:A},T&&!k&&{target:"_blank",rel:"noopener noreferrer"},v)):a.createElement(R,(0,r.Z)({},v,{onMouseEnter:P,onTouchStart:P,innerRef:e=>{w.current=e,N&&e&&k&&(L.current=new window.IntersectionObserver((t=>{t.forEach((t=>{e===t.target&&(t.isIntersecting||t.intersectionRatio>0)&&(L.current.unobserve(e),L.current.disconnect(),null!=A&&window.docusaurus.prefetch(A))}))})),L.current.observe(e))},to:A},n&&{isActive:h,activeClassName:m}))}const p=a.forwardRef(f)},5999:(e,t,n)=>{"use strict";n.d(t,{Z:()=>s,I:()=>l});var r=n(7294);function a(e,t){const n=e.split(/(\{\w+\})/).map(((e,n)=>{if(n%2==1){const n=t?.[e.slice(1,-1)];if(void 0!==n)return n}return e}));return n.some((e=>(0,r.isValidElement)(e)))?n.map(((e,t)=>(0,r.isValidElement)(e)?r.cloneElement(e,{key:t}):e)).filter((e=>""!==e)):n.join("")}var o=n(7529);function i(e){let{id:t,message:n}=e;if(void 0===t&&void 0===n)throw new Error("Docusaurus translation declarations must have at least a translation id or a default translation message");return o[t??n]??n??t}function l(e,t){let{message:n,id:r}=e;return a(i({message:n,id:r}),t)}function s(e){let{children:t,id:n,values:o}=e;if(t&&"string"!=typeof t)throw console.warn("Illegal <Translate> children",t),new Error("The Docusaurus <Translate> component only accept simple string values");const l=i({message:t,id:n});return r.createElement(r.Fragment,null,a(l,o))}},9935:(e,t,n)=>{"use strict";n.d(t,{m:()=>r});const r="default"},3919:(e,t,n)=>{"use strict";function r(e){return/^(?:\w*:|\/\/)/.test(e)}function a(e){return void 0!==e&&!r(e)}n.d(t,{Z:()=>a,b:()=>r})},4996:(e,t,n)=>{"use strict";n.d(t,{C:()=>i,Z:()=>l});var r=n(7294),a=n(2263),o=n(3919);function i(){const{siteConfig:{baseUrl:e,url:t}}=(0,a.Z)(),n=(0,r.useCallback)(((n,r)=>function(e,t,n,r){let{forcePrependBaseUrl:a=!1,absolute:i=!1}=void 0===r?{}:r;if(!n||n.startsWith("#")||(0,o.b)(n))return n;if(a)return t+n.replace(/^\//,"");if(n===t.replace(/\/$/,""))return t;const l=n.startsWith(t)?n:t+n.replace(/^\//,"");return i?e+l:l}(t,e,n,r)),[t,e]);return{withBaseUrl:n}}function l(e,t){void 0===t&&(t={});const{withBaseUrl:n}=i();return n(e,t)}},2263:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8940);function o(){return(0,r.useContext)(a._)}},2389:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(8934);function o(){return(0,r.useContext)(a._)}},9670:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=e=>"object"==typeof e&&!!e&&Object.keys(e).length>0;function a(e){const t={};return function e(n,a){Object.entries(n).forEach((n=>{let[o,i]=n;const l=a?`${a}.${o}`:o;r(i)?e(i,l):t[l]=i}))}(e),t}},226:(e,t,n)=>{"use strict";n.d(t,{_:()=>a,z:()=>o});var r=n(7294);const a=r.createContext(null);function o(e){let{children:t,value:n}=e;const o=r.useContext(a),i=(0,r.useMemo)((()=>function(e){let{parent:t,value:n}=e;if(!t){if(!n)throw new Error("Unexpected: no Docusaurus route context found");if(!("plugin"in n))throw new Error("Unexpected: Docusaurus topmost route context has no `plugin` attribute");return n}const r={...t.data,...n?.data};return{plugin:t.plugin,data:r}}({parent:o,value:n})),[o,n]);return r.createElement(a.Provider,{value:i},t)}},143:(e,t,n)=>{"use strict";n.d(t,{Iw:()=>b,gA:()=>p,WS:()=>m,_r:()=>d,Jo:()=>v,zh:()=>f,yW:()=>g,gB:()=>h});var r=n(6550),a=n(2263),o=n(9935);function i(e,t){void 0===t&&(t={});const n=function(){const{globalData:e}=(0,a.Z)();return e}()[e];if(!n&&t.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin.`);return n}const l=e=>e.versions.find((e=>e.isLast));function s(e,t){const n=l(e);return[...e.versions.filter((e=>e!==n)),n].find((e=>!!(0,r.LX)(t,{path:e.path,exact:!1,strict:!1})))}function u(e,t){const n=s(e,t),a=n?.docs.find((e=>!!(0,r.LX)(t,{path:e.path,exact:!0,strict:!1})));return{activeVersion:n,activeDoc:a,alternateDocVersions:a?function(t){const n={};return e.versions.forEach((e=>{e.docs.forEach((r=>{r.id===t&&(n[e.name]=r)}))})),n}(a.id):{}}}const c={},d=()=>i("docusaurus-plugin-content-docs")??c,f=e=>function(e,t,n){void 0===t&&(t=o.m),void 0===n&&(n={});const r=i(e),a=r?.[t];if(!a&&n.failfast)throw new Error(`Docusaurus plugin global data not found for "${e}" plugin with id "${t}".`);return a}("docusaurus-plugin-content-docs",e,{failfast:!0});function p(e){void 0===e&&(e={});const t=d(),{pathname:n}=(0,r.TH)();return function(e,t,n){void 0===n&&(n={});const a=Object.entries(e).sort(((e,t)=>t[1].path.localeCompare(e[1].path))).find((e=>{let[,n]=e;return!!(0,r.LX)(t,{path:n.path,exact:!1,strict:!1})})),o=a?{pluginId:a[0],pluginData:a[1]}:void 0;if(!o&&n.failfast)throw new Error(`Can't find active docs plugin for "${t}" pathname, while it was expected to be found. Maybe you tried to use a docs feature that can only be used on a docs-related page? Existing docs plugin paths are: ${Object.values(e).map((e=>e.path)).join(", ")}`);return o}(t,n,e)}function m(e){void 0===e&&(e={});const t=p(e),{pathname:n}=(0,r.TH)();if(!t)return;return{activePlugin:t,activeVersion:s(t.pluginData,n)}}function h(e){return f(e).versions}function g(e){const t=f(e);return l(t)}function b(e){const t=f(e),{pathname:n}=(0,r.TH)();return u(t,n)}function v(e){const t=f(e),{pathname:n}=(0,r.TH)();return function(e,t){const n=l(e);return{latestDocSuggestion:u(e,t).alternateDocVersions[n.name],latestVersionSuggestion:n}}(t,n)}},6657:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>r});const r={onRouteDidUpdate(e){let{location:t,previousLocation:n}=e;!n||t.pathname===n.pathname&&t.search===n.search&&t.hash===n.hash||setTimeout((()=>{window.gtag("event","page_view",{page_title:document.title,page_location:window.location.href,page_path:t.pathname+t.search+t.hash})}))}}},8320:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>o});var r=n(4865),a=n.n(r);a().configure({showSpinner:!1});const o={onRouteUpdate(e){let{location:t,previousLocation:n}=e;if(n&&t.pathname!==n.pathname){const e=window.setTimeout((()=>{a().start()}),200);return()=>window.clearTimeout(e)}},onRouteDidUpdate(){a().done()}}},7021:(e,t,n)=>{"use strict";n.r(t);var r=n(7410),a=n(412),o=n(6809);const i=e=>{if(!a.Z.canUseDOM)return;const{themeConfig:{prism:t={}}}=o.default,{additionalLanguages:r=[]}=t;window.Prism=e,r.forEach((e=>{n(2295)(`./prism-${e}`)}));["qmake","bash"].forEach((e=>{n(7044)(`./prism-${e}`)})),delete window.Prism};i(r.Z)},9471:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294);const a={iconExternalLink:"iconExternalLink_nPIU"};function o(e){let{width:t=13.5,height:n=13.5}=e;return r.createElement("svg",{width:t,height:n,"aria-hidden":"true",viewBox:"0 0 24 24",className:a.iconExternalLink},r.createElement("path",{fill:"currentColor",d:"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"}))}},7452:(e,t,n)=>{"use strict";n.d(t,{Z:()=>Rt});var r=n(7294),a=n(6010),o=n(4763),i=n(833),l=n(7462),s=n(6550),u=n(5999),c=n(5936);const d="__docusaurus_skipToContent_fallback";function f(e){e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")}function p(){const e=(0,r.useRef)(null),{action:t}=(0,s.k6)(),n=(0,r.useCallback)((e=>{e.preventDefault();const t=document.querySelector("main:first-of-type")??document.getElementById(d);t&&f(t)}),[]);return(0,c.S)((n=>{let{location:r}=n;e.current&&!r.hash&&"PUSH"===t&&f(e.current)})),{containerRef:e,onClick:n}}const m=(0,u.I)({id:"theme.common.skipToMainContent",description:"The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation",message:"Skip to main content"});function h(e){const t=e.children??m,{containerRef:n,onClick:a}=p();return r.createElement("div",{ref:n,role:"region","aria-label":m},r.createElement("a",(0,l.Z)({},e,{href:`#${d}`,onClick:a}),t))}var g=n(5281),b=n(9727);const v={skipToContent:"skipToContent_fXgn"};function y(){return r.createElement(h,{className:v.skipToContent})}var E=n(6668),S=n(9689);function _(e){let{width:t=21,height:n=21,color:a="currentColor",strokeWidth:o=1.2,className:i,...s}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 15 15",width:t,height:n},s),r.createElement("g",{stroke:a,strokeWidth:o},r.createElement("path",{d:"M.75.75l13.5 13.5M14.25.75L.75 14.25"})))}const w={closeButton:"closeButton_CVFx"};function T(e){return r.createElement("button",(0,l.Z)({type:"button","aria-label":(0,u.I)({id:"theme.AnnouncementBar.closeButtonAriaLabel",message:"Close",description:"The ARIA label for close button of announcement bar"})},e,{className:(0,a.Z)("clean-btn close",w.closeButton,e.className)}),r.createElement(_,{width:14,height:14,strokeWidth:3.1}))}const k={content:"content_knG7"};function C(e){const{announcementBar:t}=(0,E.L)(),{content:n}=t;return r.createElement("div",(0,l.Z)({},e,{className:(0,a.Z)(k.content,e.className),dangerouslySetInnerHTML:{__html:n}}))}const A={announcementBar:"announcementBar_mb4j",announcementBarPlaceholder:"announcementBarPlaceholder_vyr4",announcementBarClose:"announcementBarClose_gvF7",announcementBarContent:"announcementBarContent_xLdY"};function I(){const{announcementBar:e}=(0,E.L)(),{isActive:t,close:n}=(0,S.nT)();if(!t)return null;const{backgroundColor:a,textColor:o,isCloseable:i}=e;return r.createElement("div",{className:A.announcementBar,style:{backgroundColor:a,color:o},role:"banner"},i&&r.createElement("div",{className:A.announcementBarPlaceholder}),r.createElement(C,{className:A.announcementBarContent}),i&&r.createElement(T,{onClick:n,className:A.announcementBarClose}))}var O=n(3163),R=n(2466);var N=n(902),L=n(3102);const P=r.createContext(null);function x(e){let{children:t}=e;const n=function(){const e=(0,O.e)(),t=(0,L.HY)(),[n,a]=(0,r.useState)(!1),o=null!==t.component,i=(0,N.D9)(o);return(0,r.useEffect)((()=>{o&&!i&&a(!0)}),[o,i]),(0,r.useEffect)((()=>{o?e.shown||a(!0):a(!1)}),[e.shown,o]),(0,r.useMemo)((()=>[n,a]),[n])}();return r.createElement(P.Provider,{value:n},t)}function D(e){if(e.component){const t=e.component;return r.createElement(t,e.props)}}function M(){const e=(0,r.useContext)(P);if(!e)throw new N.i6("NavbarSecondaryMenuDisplayProvider");const[t,n]=e,a=(0,r.useCallback)((()=>n(!1)),[n]),o=(0,L.HY)();return(0,r.useMemo)((()=>({shown:t,hide:a,content:D(o)})),[a,o,t])}function U(e){let{header:t,primaryMenu:n,secondaryMenu:o}=e;const{shown:i}=M();return r.createElement("div",{className:"navbar-sidebar"},t,r.createElement("div",{className:(0,a.Z)("navbar-sidebar__items",{"navbar-sidebar__items--show-secondary":i})},r.createElement("div",{className:"navbar-sidebar__item menu"},n),r.createElement("div",{className:"navbar-sidebar__item menu"},o)))}var F=n(2949),B=n(2389);function $(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"}))}function z(e){return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:24,height:24},e),r.createElement("path",{fill:"currentColor",d:"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"}))}const H={toggle:"toggle_vylO",toggleButton:"toggleButton_gllP",darkToggleIcon:"darkToggleIcon_wfgR",lightToggleIcon:"lightToggleIcon_pyhR",toggleButtonDisabled:"toggleButtonDisabled_aARS"};function j(e){let{className:t,buttonClassName:n,value:o,onChange:i}=e;const l=(0,B.Z)(),s=(0,u.I)({message:"Switch between dark and light mode (currently {mode})",id:"theme.colorToggle.ariaLabel",description:"The ARIA label for the navbar color mode toggle"},{mode:"dark"===o?(0,u.I)({message:"dark mode",id:"theme.colorToggle.ariaLabel.mode.dark",description:"The name for the dark color mode"}):(0,u.I)({message:"light mode",id:"theme.colorToggle.ariaLabel.mode.light",description:"The name for the light color mode"})});return r.createElement("div",{className:(0,a.Z)(H.toggle,t)},r.createElement("button",{className:(0,a.Z)("clean-btn",H.toggleButton,!l&&H.toggleButtonDisabled,n),type:"button",onClick:()=>i("dark"===o?"light":"dark"),disabled:!l,title:s,"aria-label":s,"aria-live":"polite"},r.createElement($,{className:(0,a.Z)(H.toggleIcon,H.lightToggleIcon)}),r.createElement(z,{className:(0,a.Z)(H.toggleIcon,H.darkToggleIcon)})))}const G=r.memo(j),Z={darkNavbarColorModeToggle:"darkNavbarColorModeToggle_X3D1"};function V(e){let{className:t}=e;const n=(0,E.L)().navbar.style,a=(0,E.L)().colorMode.disableSwitch,{colorMode:o,setColorMode:i}=(0,F.I)();return a?null:r.createElement(G,{className:t,buttonClassName:"dark"===n?Z.darkNavbarColorModeToggle:void 0,value:o,onChange:i})}var W=n(1327);function Y(){return r.createElement(W.Z,{className:"navbar__brand",imageClassName:"navbar__logo",titleClassName:"navbar__title text--truncate"})}function K(){const e=(0,O.e)();return r.createElement("button",{type:"button","aria-label":(0,u.I)({id:"theme.docs.sidebar.closeSidebarButtonAriaLabel",message:"Close navigation bar",description:"The ARIA label for close button of mobile sidebar"}),className:"clean-btn navbar-sidebar__close",onClick:()=>e.toggle()},r.createElement(_,{color:"var(--ifm-color-emphasis-600)"}))}function X(){return r.createElement("div",{className:"navbar-sidebar__brand"},r.createElement(Y,null),r.createElement(V,{className:"margin-right--md"}),r.createElement(K,null))}var q=n(9960),Q=n(4996),J=n(3919),ee=n(8022),te=n(9471);function ne(e){let{activeBasePath:t,activeBaseRegex:n,to:a,href:o,label:i,html:s,isDropdownLink:u,prependBaseUrlToHref:c,...d}=e;const f=(0,Q.Z)(a),p=(0,Q.Z)(t),m=(0,Q.Z)(o,{forcePrependBaseUrl:!0}),h=i&&o&&!(0,J.Z)(o),g=s?{dangerouslySetInnerHTML:{__html:s}}:{children:r.createElement(r.Fragment,null,i,h&&r.createElement(te.Z,u&&{width:12,height:12}))};return o?r.createElement(q.Z,(0,l.Z)({href:c?m:o},d,g)):r.createElement(q.Z,(0,l.Z)({to:f,isNavLink:!0},(t||n)&&{isActive:(e,t)=>n?(0,ee.F)(n,t.pathname):t.pathname.startsWith(p)},d,g))}function re(e){let{className:t,isDropdownItem:n=!1,...o}=e;const i=r.createElement(ne,(0,l.Z)({className:(0,a.Z)(n?"dropdown__link":"navbar__item navbar__link",t),isDropdownLink:n},o));return n?r.createElement("li",null,i):i}function ae(e){let{className:t,isDropdownItem:n,...o}=e;return r.createElement("li",{className:"menu__list-item"},r.createElement(ne,(0,l.Z)({className:(0,a.Z)("menu__link",t)},o)))}function oe(e){let{mobile:t=!1,position:n,...a}=e;const o=t?ae:re;return r.createElement(o,(0,l.Z)({},a,{activeClassName:a.activeClassName??(t?"menu__link--active":"navbar__link--active")}))}var ie=n(6043),le=n(8596),se=n(2263);function ue(e,t){return e.some((e=>function(e,t){return!!(0,le.Mg)(e.to,t)||!!(0,ee.F)(e.activeBaseRegex,t)||!(!e.activeBasePath||!t.startsWith(e.activeBasePath))}(e,t)))}function ce(e){let{items:t,position:n,className:o,onClick:i,...s}=e;const u=(0,r.useRef)(null),[c,d]=(0,r.useState)(!1);return(0,r.useEffect)((()=>{const e=e=>{u.current&&!u.current.contains(e.target)&&d(!1)};return document.addEventListener("mousedown",e),document.addEventListener("touchstart",e),document.addEventListener("focusin",e),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("touchstart",e),document.removeEventListener("focusin",e)}}),[u]),r.createElement("div",{ref:u,className:(0,a.Z)("navbar__item","dropdown","dropdown--hoverable",{"dropdown--right":"right"===n,"dropdown--show":c})},r.createElement(ne,(0,l.Z)({"aria-haspopup":"true","aria-expanded":c,role:"button",href:s.to?void 0:"#",className:(0,a.Z)("navbar__link",o)},s,{onClick:s.to?void 0:e=>e.preventDefault(),onKeyDown:e=>{"Enter"===e.key&&(e.preventDefault(),d(!c))}}),s.children??s.label),r.createElement("ul",{className:"dropdown__menu"},t.map(((e,t)=>r.createElement(je,(0,l.Z)({isDropdownItem:!0,activeClassName:"dropdown__link--active"},e,{key:t}))))))}function de(e){let{items:t,className:n,position:o,onClick:i,...u}=e;const c=function(){const{siteConfig:{baseUrl:e}}=(0,se.Z)(),{pathname:t}=(0,s.TH)();return t.replace(e,"/")}(),d=ue(t,c),{collapsed:f,toggleCollapsed:p,setCollapsed:m}=(0,ie.u)({initialState:()=>!d});return(0,r.useEffect)((()=>{d&&m(!d)}),[c,d,m]),r.createElement("li",{className:(0,a.Z)("menu__list-item",{"menu__list-item--collapsed":f})},r.createElement(ne,(0,l.Z)({role:"button",className:(0,a.Z)("menu__link menu__link--sublist menu__link--sublist-caret",n)},u,{onClick:e=>{e.preventDefault(),p()}}),u.children??u.label),r.createElement(ie.z,{lazy:!0,as:"ul",className:"menu__list",collapsed:f},t.map(((e,t)=>r.createElement(je,(0,l.Z)({mobile:!0,isDropdownItem:!0,onClick:i,activeClassName:"menu__link--active"},e,{key:t}))))))}function fe(e){let{mobile:t=!1,...n}=e;const a=t?de:ce;return r.createElement(a,n)}var pe=n(4711);function me(e){let{width:t=20,height:n=20,...a}=e;return r.createElement("svg",(0,l.Z)({viewBox:"0 0 24 24",width:t,height:n,"aria-hidden":!0},a),r.createElement("path",{fill:"currentColor",d:"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"}))}const he="iconLanguage_nlXk";function ge(){return r.createElement("svg",{width:"15",height:"15",className:"DocSearch-Control-Key-Icon"},r.createElement("path",{d:"M4.505 4.496h2M5.505 5.496v5M8.216 4.496l.055 5.993M10 7.5c.333.333.5.667.5 1v2M12.326 4.5v5.996M8.384 4.496c1.674 0 2.116 0 2.116 1.5s-.442 1.5-2.116 1.5M3.205 9.303c-.09.448-.277 1.21-1.241 1.203C1 10.5.5 9.513.5 8V7c0-1.57.5-2.5 1.464-2.494.964.006 1.134.598 1.24 1.342M12.553 10.5h1.953",strokeWidth:"1.2",stroke:"currentColor",fill:"none",strokeLinecap:"square"}))}var be=n(830),ve=["translations"];function ye(){return ye=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},ye.apply(this,arguments)}function Ee(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,a,o=[],i=!0,l=!1;try{for(n=n.call(e);!(i=(r=n.next()).done)&&(o.push(r.value),!t||o.length!==t);i=!0);}catch(s){l=!0,a=s}finally{try{i||null==n.return||n.return()}finally{if(l)throw a}}return o}(e,t)||function(e,t){if(!e)return;if("string"==typeof e)return Se(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Se(e,t)}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Se(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function _e(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var we="Ctrl";var Te=r.forwardRef((function(e,t){var n=e.translations,a=void 0===n?{}:n,o=_e(e,ve),i=a.buttonText,l=void 0===i?"Search":i,s=a.buttonAriaLabel,u=void 0===s?"Search":s,c=Ee((0,r.useState)(null),2),d=c[0],f=c[1];return(0,r.useEffect)((function(){"undefined"!=typeof navigator&&(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?f("\u2318"):f(we))}),[]),r.createElement("button",ye({type:"button",className:"DocSearch DocSearch-Button","aria-label":u},o,{ref:t}),r.createElement("span",{className:"DocSearch-Button-Container"},r.createElement(be.W,null),r.createElement("span",{className:"DocSearch-Button-Placeholder"},l)),r.createElement("span",{className:"DocSearch-Button-Keys"},null!==d&&r.createElement(r.Fragment,null,r.createElement("kbd",{className:"DocSearch-Button-Key"},d===we?r.createElement(ge,null):d),r.createElement("kbd",{className:"DocSearch-Button-Key"},"K"))))})),ke=n(5742),Ce=n(6177),Ae=n(239),Ie=n(3320);var Oe=n(3935);const Re={button:{buttonText:(0,u.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"}),buttonAriaLabel:(0,u.I)({id:"theme.SearchBar.label",message:"Search",description:"The ARIA label and placeholder for search button"})},modal:{searchBox:{resetButtonTitle:(0,u.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),resetButtonAriaLabel:(0,u.I)({id:"theme.SearchModal.searchBox.resetButtonTitle",message:"Clear the query",description:"The label and ARIA label for search box reset button"}),cancelButtonText:(0,u.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"}),cancelButtonAriaLabel:(0,u.I)({id:"theme.SearchModal.searchBox.cancelButtonText",message:"Cancel",description:"The label and ARIA label for search box cancel button"})},startScreen:{recentSearchesTitle:(0,u.I)({id:"theme.SearchModal.startScreen.recentSearchesTitle",message:"Recent",description:"The title for recent searches"}),noRecentSearchesText:(0,u.I)({id:"theme.SearchModal.startScreen.noRecentSearchesText",message:"No recent searches",description:"The text when no recent searches"}),saveRecentSearchButtonTitle:(0,u.I)({id:"theme.SearchModal.startScreen.saveRecentSearchButtonTitle",message:"Save this search",description:"The label for save recent search button"}),removeRecentSearchButtonTitle:(0,u.I)({id:"theme.SearchModal.startScreen.removeRecentSearchButtonTitle",message:"Remove this search from history",description:"The label for remove recent search button"}),favoriteSearchesTitle:(0,u.I)({id:"theme.SearchModal.startScreen.favoriteSearchesTitle",message:"Favorite",description:"The title for favorite searches"}),removeFavoriteSearchButtonTitle:(0,u.I)({id:"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle",message:"Remove this search from favorites",description:"The label for remove favorite search button"})},errorScreen:{titleText:(0,u.I)({id:"theme.SearchModal.errorScreen.titleText",message:"Unable to fetch results",description:"The title for error screen of search modal"}),helpText:(0,u.I)({id:"theme.SearchModal.errorScreen.helpText",message:"You might want to check your network connection.",description:"The help text for error screen of search modal"})},footer:{selectText:(0,u.I)({id:"theme.SearchModal.footer.selectText",message:"to select",description:"The explanatory text of the action for the enter key"}),selectKeyAriaLabel:(0,u.I)({id:"theme.SearchModal.footer.selectKeyAriaLabel",message:"Enter key",description:"The ARIA label for the Enter key button that makes the selection"}),navigateText:(0,u.I)({id:"theme.SearchModal.footer.navigateText",message:"to navigate",description:"The explanatory text of the action for the Arrow up and Arrow down key"}),navigateUpKeyAriaLabel:(0,u.I)({id:"theme.SearchModal.footer.navigateUpKeyAriaLabel",message:"Arrow up",description:"The ARIA label for the Arrow up key button that makes the navigation"}),navigateDownKeyAriaLabel:(0,u.I)({id:"theme.SearchModal.footer.navigateDownKeyAriaLabel",message:"Arrow down",description:"The ARIA label for the Arrow down key button that makes the navigation"}),closeText:(0,u.I)({id:"theme.SearchModal.footer.closeText",message:"to close",description:"The explanatory text of the action for Escape key"}),closeKeyAriaLabel:(0,u.I)({id:"theme.SearchModal.footer.closeKeyAriaLabel",message:"Escape key",description:"The ARIA label for the Escape key button that close the modal"}),searchByText:(0,u.I)({id:"theme.SearchModal.footer.searchByText",message:"Search by",description:"The text explain that the search is making by Algolia"})},noResultsScreen:{noResultsText:(0,u.I)({id:"theme.SearchModal.noResultsScreen.noResultsText",message:"No results for",description:"The text explains that there are no results for the following search"}),suggestedQueryText:(0,u.I)({id:"theme.SearchModal.noResultsScreen.suggestedQueryText",message:"Try searching for",description:"The text for the suggested query when no results are found for the following search"}),reportMissingResultsText:(0,u.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsText",message:"Believe this query should return results?",description:"The text for the question where the user thinks there are missing results"}),reportMissingResultsLinkText:(0,u.I)({id:"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText",message:"Let us know.",description:"The text for the link to report missing results"})}},placeholder:(0,u.I)({id:"theme.SearchModal.placeholder",message:"Search docs",description:"The placeholder of the input of the DocSearch pop-up modal"})};let Ne=null;function Le(e){let{hit:t,children:n}=e;return r.createElement(q.Z,{to:t.url},n)}function Pe(e){let{state:t,onClose:n}=e;const a=(0,Ce.M)();return r.createElement(q.Z,{to:a(t.query),onClick:n},r.createElement(u.Z,{id:"theme.SearchBar.seeAll",values:{count:t.context.nbHits}},"See all {count} results"))}function xe(e){let{contextualSearch:t,externalUrlRegex:a,...o}=e;const{siteMetadata:i}=(0,se.Z)(),u=(0,Ae.l)(),c=function(){const{locale:e,tags:t}=(0,Ie._q)();return[`language:${e}`,t.map((e=>`docusaurus_tag:${e}`))]}(),d=o.searchParameters?.facetFilters??[],f=t?function(e,t){const n=e=>"string"==typeof e?[e]:e;return[...n(e),...n(t)]}(c,d):d,p={...o.searchParameters,facetFilters:f},m=(0,s.k6)(),h=(0,r.useRef)(null),g=(0,r.useRef)(null),[b,v]=(0,r.useState)(!1),[y,E]=(0,r.useState)(void 0),S=(0,r.useCallback)((()=>Ne?Promise.resolve():Promise.all([n.e(426).then(n.bind(n,1426)),Promise.all([n.e(532),n.e(945)]).then(n.bind(n,6945)),Promise.all([n.e(532),n.e(894)]).then(n.bind(n,8894))]).then((e=>{let[{DocSearchModal:t}]=e;Ne=t}))),[]),_=(0,r.useCallback)((()=>{S().then((()=>{h.current=document.createElement("div"),document.body.insertBefore(h.current,document.body.firstChild),v(!0)}))}),[S,v]),w=(0,r.useCallback)((()=>{v(!1),h.current?.remove()}),[v]),T=(0,r.useCallback)((e=>{S().then((()=>{v(!0),E(e.key)}))}),[S,v,E]),k=(0,r.useRef)({navigate(e){let{itemUrl:t}=e;(0,ee.F)(a,t)?window.location.href=t:m.push(t)}}).current,C=(0,r.useRef)((e=>o.transformItems?o.transformItems(e):e.map((e=>({...e,url:u(e.url)}))))).current,A=(0,r.useMemo)((()=>e=>r.createElement(Pe,(0,l.Z)({},e,{onClose:w}))),[w]),I=(0,r.useCallback)((e=>(e.addAlgoliaAgent("docusaurus",i.docusaurusVersion),e)),[i.docusaurusVersion]);return function(e){var t=e.isOpen,n=e.onOpen,a=e.onClose,o=e.onInput,i=e.searchButtonRef;r.useEffect((function(){function e(e){var r;(27===e.keyCode&&t||"k"===(null===(r=e.key)||void 0===r?void 0:r.toLowerCase())&&(e.metaKey||e.ctrlKey)||!function(e){var t=e.target,n=t.tagName;return t.isContentEditable||"INPUT"===n||"SELECT"===n||"TEXTAREA"===n}(e)&&"/"===e.key&&!t)&&(e.preventDefault(),t?a():document.body.classList.contains("DocSearch--active")||document.body.classList.contains("DocSearch--active")||n()),i&&i.current===document.activeElement&&o&&/[a-zA-Z0-9]/.test(String.fromCharCode(e.keyCode))&&o(e)}return window.addEventListener("keydown",e),function(){window.removeEventListener("keydown",e)}}),[t,n,a,o,i])}({isOpen:b,onOpen:_,onClose:w,onInput:T,searchButtonRef:g}),r.createElement(r.Fragment,null,r.createElement(ke.Z,null,r.createElement("link",{rel:"preconnect",href:`https://${o.appId}-dsn.algolia.net`,crossOrigin:"anonymous"})),r.createElement(Te,{onTouchStart:S,onFocus:S,onMouseOver:S,onClick:_,ref:g,translations:Re.button}),b&&Ne&&h.current&&(0,Oe.createPortal)(r.createElement(Ne,(0,l.Z)({onClose:w,initialScrollY:window.scrollY,initialQuery:y,navigator:k,transformItems:C,hitComponent:Le,transformSearchClient:I},o.searchPagePath&&{resultsFooterComponent:A},o,{searchParameters:p,placeholder:Re.placeholder,translations:Re.modal})),h.current))}function De(){const{siteConfig:e}=(0,se.Z)();return r.createElement(xe,e.themeConfig.algolia)}const Me={searchBox:"searchBox_ZlJk"};function Ue(e){let{children:t,className:n}=e;return r.createElement("div",{className:(0,a.Z)(n,Me.searchBox)},t)}var Fe=n(143),Be=n(3438);var $e=n(373);const ze=e=>e.docs.find((t=>t.id===e.mainDocId));const He={default:oe,localeDropdown:function(e){let{mobile:t,dropdownItemsBefore:n,dropdownItemsAfter:a,...o}=e;const{i18n:{currentLocale:i,locales:c,localeConfigs:d}}=(0,se.Z)(),f=(0,pe.l)(),{search:p,hash:m}=(0,s.TH)(),h=[...n,...c.map((e=>{const n=`${`pathname://${f.createUrl({locale:e,fullyQualified:!1})}`}${p}${m}`;return{label:d[e].label,lang:d[e].htmlLang,to:n,target:"_self",autoAddBaseUrl:!1,className:e===i?t?"menu__link--active":"dropdown__link--active":""}})),...a],g=t?(0,u.I)({message:"Languages",id:"theme.navbar.mobileLanguageDropdown.label",description:"The label for the mobile language switcher dropdown"}):d[i].label;return r.createElement(fe,(0,l.Z)({},o,{mobile:t,label:r.createElement(r.Fragment,null,r.createElement(me,{className:he}),g),items:h}))},search:function(e){let{mobile:t,className:n}=e;return t?null:r.createElement(Ue,{className:n},r.createElement(De,null))},dropdown:fe,html:function(e){let{value:t,className:n,mobile:o=!1,isDropdownItem:i=!1}=e;const l=i?"li":"div";return r.createElement(l,{className:(0,a.Z)({navbar__item:!o&&!i,"menu__list-item":o},n),dangerouslySetInnerHTML:{__html:t}})},doc:function(e){let{docId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,Fe.Iw)(a),s=(0,Be.vY)(t,a);return null===s?null:r.createElement(oe,(0,l.Z)({exact:!0},o,{isActive:()=>i?.path===s.path||!!i?.sidebar&&i.sidebar===s.sidebar,label:n??s.id,to:s.path}))},docSidebar:function(e){let{sidebarId:t,label:n,docsPluginId:a,...o}=e;const{activeDoc:i}=(0,Fe.Iw)(a),s=(0,Be.oz)(t,a).link;if(!s)throw new Error(`DocSidebarNavbarItem: Sidebar with ID "${t}" doesn't have anything to be linked to.`);return r.createElement(oe,(0,l.Z)({exact:!0},o,{isActive:()=>i?.sidebar===t,label:n??s.label,to:s.path}))},docsVersion:function(e){let{label:t,to:n,docsPluginId:a,...o}=e;const i=(0,Be.lO)(a)[0],s=t??i.label,u=n??(e=>e.docs.find((t=>t.id===e.mainDocId)))(i).path;return r.createElement(oe,(0,l.Z)({},o,{label:s,to:u}))},docsVersionDropdown:function(e){let{mobile:t,docsPluginId:n,dropdownActiveClassDisabled:a,dropdownItemsBefore:o,dropdownItemsAfter:i,...c}=e;const{search:d,hash:f}=(0,s.TH)(),p=(0,Fe.Iw)(n),m=(0,Fe.gB)(n),{savePreferredVersionName:h}=(0,$e.J)(n),g=[...o,...m.map((e=>{const t=p.alternateDocVersions[e.name]??ze(e);return{label:e.label,to:`${t.path}${d}${f}`,isActive:()=>e===p.activeVersion,onClick:()=>h(e.name)}})),...i],b=(0,Be.lO)(n)[0],v=t&&g.length>1?(0,u.I)({id:"theme.navbar.mobileVersionsDropdown.label",message:"Versions",description:"The label for the navbar versions dropdown on mobile view"}):b.label,y=t&&g.length>1?void 0:ze(b).path;return g.length<=1?r.createElement(oe,(0,l.Z)({},c,{mobile:t,label:v,to:y,isActive:a?()=>!1:void 0})):r.createElement(fe,(0,l.Z)({},c,{mobile:t,label:v,to:y,items:g,isActive:a?()=>!1:void 0}))}};function je(e){let{type:t,...n}=e;const a=function(e,t){return e&&"default"!==e?e:"items"in t?"dropdown":"default"}(t,n),o=He[a];if(!o)throw new Error(`No NavbarItem component found for type "${t}".`);return r.createElement(o,n)}function Ge(){const e=(0,O.e)(),t=(0,E.L)().navbar.items;return r.createElement("ul",{className:"menu__list"},t.map(((t,n)=>r.createElement(je,(0,l.Z)({mobile:!0},t,{onClick:()=>e.toggle(),key:n})))))}function Ze(e){return r.createElement("button",(0,l.Z)({},e,{type:"button",className:"clean-btn navbar-sidebar__back"}),r.createElement(u.Z,{id:"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel",description:"The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"},"\u2190 Back to main menu"))}function Ve(){const e=0===(0,E.L)().navbar.items.length,t=M();return r.createElement(r.Fragment,null,!e&&r.createElement(Ze,{onClick:()=>t.hide()}),t.content)}function We(){const e=(0,O.e)();var t;return void 0===(t=e.shown)&&(t=!0),(0,r.useEffect)((()=>(document.body.style.overflow=t?"hidden":"visible",()=>{document.body.style.overflow="visible"})),[t]),e.shouldRender?r.createElement(U,{header:r.createElement(X,null),primaryMenu:r.createElement(Ge,null),secondaryMenu:r.createElement(Ve,null)}):null}const Ye={navbarHideable:"navbarHideable_m1mJ",navbarHidden:"navbarHidden_jGov"};function Ke(e){return r.createElement("div",(0,l.Z)({role:"presentation"},e,{className:(0,a.Z)("navbar-sidebar__backdrop",e.className)}))}function Xe(e){let{children:t}=e;const{navbar:{hideOnScroll:n,style:o}}=(0,E.L)(),i=(0,O.e)(),{navbarRef:l,isNavbarVisible:s}=function(e){const[t,n]=(0,r.useState)(e),a=(0,r.useRef)(!1),o=(0,r.useRef)(0),i=(0,r.useCallback)((e=>{null!==e&&(o.current=e.getBoundingClientRect().height)}),[]);return(0,R.RF)(((t,r)=>{let{scrollY:i}=t;if(!e)return;if(i<o.current)return void n(!0);if(a.current)return void(a.current=!1);const l=r?.scrollY,s=document.documentElement.scrollHeight-o.current,u=window.innerHeight;l&&i>=l?n(!1):i+u<s&&n(!0)})),(0,c.S)((t=>{if(!e)return;const r=t.location.hash;if(r?document.getElementById(r.substring(1)):void 0)return a.current=!0,void n(!1);n(!0)})),{navbarRef:i,isNavbarVisible:t}}(n);return r.createElement("nav",{ref:l,"aria-label":(0,u.I)({id:"theme.NavBar.navAriaLabel",message:"Main",description:"The ARIA label for the main navigation"}),className:(0,a.Z)("navbar","navbar--fixed-top",n&&[Ye.navbarHideable,!s&&Ye.navbarHidden],{"navbar--dark":"dark"===o,"navbar--primary":"primary"===o,"navbar-sidebar--show":i.shown})},t,r.createElement(Ke,{onClick:i.toggle}),r.createElement(We,null))}var qe=n(8780);const Qe={errorBoundaryError:"errorBoundaryError_a6uf"};function Je(e){return r.createElement("button",(0,l.Z)({type:"button"},e),r.createElement(u.Z,{id:"theme.ErrorPageContent.tryAgain",description:"The label of the button to try again rendering when the React error boundary captures an error"},"Try again"))}function et(e){let{error:t}=e;const n=(0,qe.getErrorCausalChain)(t).map((e=>e.message)).join("\n\nCause:\n");return r.createElement("p",{className:Qe.errorBoundaryError},n)}class tt extends r.Component{componentDidCatch(e,t){throw this.props.onError(e,t)}render(){return this.props.children}}const nt="right";function rt(e){let{width:t=30,height:n=30,className:a,...o}=e;return r.createElement("svg",(0,l.Z)({className:a,width:t,height:n,viewBox:"0 0 30 30","aria-hidden":"true"},o),r.createElement("path",{stroke:"currentColor",strokeLinecap:"round",strokeMiterlimit:"10",strokeWidth:"2",d:"M4 7h22M4 15h22M4 23h22"}))}function at(){const{toggle:e,shown:t}=(0,O.e)();return r.createElement("button",{onClick:e,"aria-label":(0,u.I)({id:"theme.docs.sidebar.toggleSidebarButtonAriaLabel",message:"Toggle navigation bar",description:"The ARIA label for hamburger menu button of mobile navigation"}),"aria-expanded":t,className:"navbar__toggle clean-btn",type:"button"},r.createElement(rt,null))}const ot={colorModeToggle:"colorModeToggle_DEke"};function it(e){let{items:t}=e;return r.createElement(r.Fragment,null,t.map(((e,t)=>r.createElement(tt,{key:t,onError:t=>new Error(`A theme navbar item failed to render.\nPlease double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:\n${JSON.stringify(e,null,2)}`,{cause:t})},r.createElement(je,e)))))}function lt(e){let{left:t,right:n}=e;return r.createElement("div",{className:"navbar__inner"},r.createElement("div",{className:"navbar__items"},t),r.createElement("div",{className:"navbar__items navbar__items--right"},n))}function st(){const e=(0,O.e)(),t=(0,E.L)().navbar.items,[n,a]=function(e){function t(e){return"left"===(e.position??nt)}return[e.filter(t),e.filter((e=>!t(e)))]}(t),o=t.find((e=>"search"===e.type));return r.createElement(lt,{left:r.createElement(r.Fragment,null,!e.disabled&&r.createElement(at,null),r.createElement(Y,null),r.createElement(it,{items:n})),right:r.createElement(r.Fragment,null,r.createElement(it,{items:a}),r.createElement(V,{className:ot.colorModeToggle}),!o&&r.createElement(Ue,null,r.createElement(De,null)))})}function ut(){return r.createElement(Xe,null,r.createElement(st,null))}function ct(e){let{item:t}=e;const{to:n,href:a,label:o,prependBaseUrlToHref:i,...s}=t,u=(0,Q.Z)(n),c=(0,Q.Z)(a,{forcePrependBaseUrl:!0});return r.createElement(q.Z,(0,l.Z)({className:"footer__link-item"},a?{href:i?c:a}:{to:u},s),o,a&&!(0,J.Z)(a)&&r.createElement(te.Z,null))}function dt(e){let{item:t}=e;return t.html?r.createElement("li",{className:"footer__item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement("li",{key:t.href??t.to,className:"footer__item"},r.createElement(ct,{item:t}))}function ft(e){let{column:t}=e;return r.createElement("div",{className:"col footer__col"},r.createElement("div",{className:"footer__title"},t.title),r.createElement("ul",{className:"footer__items clean-list"},t.items.map(((e,t)=>r.createElement(dt,{key:t,item:e})))))}function pt(e){let{columns:t}=e;return r.createElement("div",{className:"row footer__links"},t.map(((e,t)=>r.createElement(ft,{key:t,column:e}))))}function mt(){return r.createElement("span",{className:"footer__link-separator"},"\xb7")}function ht(e){let{item:t}=e;return t.html?r.createElement("span",{className:"footer__link-item",dangerouslySetInnerHTML:{__html:t.html}}):r.createElement(ct,{item:t})}function gt(e){let{links:t}=e;return r.createElement("div",{className:"footer__links text--center"},r.createElement("div",{className:"footer__links"},t.map(((e,n)=>r.createElement(r.Fragment,{key:n},r.createElement(ht,{item:e}),t.length!==n+1&&r.createElement(mt,null))))))}function bt(e){let{links:t}=e;return function(e){return"title"in e[0]}(t)?r.createElement(pt,{columns:t}):r.createElement(gt,{links:t})}var vt=n(941);const yt={footerLogoLink:"footerLogoLink_BH7S"};function Et(e){let{logo:t}=e;const{withBaseUrl:n}=(0,Q.C)(),o={light:n(t.src),dark:n(t.srcDark??t.src)};return r.createElement(vt.Z,{className:(0,a.Z)("footer__logo",t.className),alt:t.alt,sources:o,width:t.width,height:t.height,style:t.style})}function St(e){let{logo:t}=e;return t.href?r.createElement(q.Z,{href:t.href,className:yt.footerLogoLink,target:t.target},r.createElement(Et,{logo:t})):r.createElement(Et,{logo:t})}function _t(e){let{copyright:t}=e;return r.createElement("div",{className:"footer__copyright",dangerouslySetInnerHTML:{__html:t}})}function wt(e){let{style:t,links:n,logo:o,copyright:i}=e;return r.createElement("footer",{className:(0,a.Z)("footer",{"footer--dark":"dark"===t})},r.createElement("div",{className:"container container-fluid"},n,(o||i)&&r.createElement("div",{className:"footer__bottom text--center"},o&&r.createElement("div",{className:"margin-bottom--sm"},o),i)))}function Tt(){const{footer:e}=(0,E.L)();if(!e)return null;const{copyright:t,links:n,logo:a,style:o}=e;return r.createElement(wt,{style:o,links:n&&n.length>0&&r.createElement(bt,{links:n}),logo:a&&r.createElement(St,{logo:a}),copyright:t&&r.createElement(_t,{copyright:t})})}const kt=r.memo(Tt),Ct=(0,N.Qc)([F.S,S.pl,R.OC,$e.L5,i.VC,function(e){let{children:t}=e;return r.createElement(L.n2,null,r.createElement(O.M,null,r.createElement(x,null,t)))}]);function At(e){let{children:t}=e;return r.createElement(Ct,null,t)}function It(e){let{error:t,tryAgain:n}=e;return r.createElement("main",{className:"container margin-vert--xl"},r.createElement("div",{className:"row"},r.createElement("div",{className:"col col--6 col--offset-3"},r.createElement("h1",{className:"hero__title"},r.createElement(u.Z,{id:"theme.ErrorPageContent.title",description:"The title of the fallback page when the page crashed"},"This page crashed.")),r.createElement("div",{className:"margin-vert--lg"},r.createElement(Je,{onClick:n,className:"button button--primary shadow--lw"})),r.createElement("hr",null),r.createElement("div",{className:"margin-vert--md"},r.createElement(et,{error:t})))))}const Ot={mainWrapper:"mainWrapper_z2l0"};function Rt(e){const{children:t,noFooter:n,wrapperClassName:l,title:s,description:u}=e;return(0,b.t)(),r.createElement(At,null,r.createElement(i.d,{title:s,description:u}),r.createElement(y,null),r.createElement(I,null),r.createElement(ut,null),r.createElement("div",{id:d,className:(0,a.Z)(g.k.wrapper.main,Ot.mainWrapper,l)},r.createElement(o.Z,{fallback:e=>r.createElement(It,e)},t)),!n&&r.createElement(kt,null))}},1327:(e,t,n)=>{"use strict";n.d(t,{Z:()=>d});var r=n(7462),a=n(7294),o=n(9960),i=n(4996),l=n(2263),s=n(6668),u=n(941);function c(e){let{logo:t,alt:n,imageClassName:r}=e;const o={light:(0,i.Z)(t.src),dark:(0,i.Z)(t.srcDark||t.src)},l=a.createElement(u.Z,{className:t.className,sources:o,height:t.height,width:t.width,alt:n,style:t.style});return r?a.createElement("div",{className:r},l):l}function d(e){const{siteConfig:{title:t}}=(0,l.Z)(),{navbar:{title:n,logo:u}}=(0,s.L)(),{imageClassName:d,titleClassName:f,...p}=e,m=(0,i.Z)(u?.href||"/"),h=n?"":t,g=u?.alt??h;return a.createElement(o.Z,(0,r.Z)({to:m},p,u?.target&&{target:u.target}),u&&a.createElement(c,{logo:u,alt:g,imageClassName:d}),null!=n&&a.createElement("b",{className:f},n))}},197:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=n(7294),a=n(5742);function o(e){let{locale:t,version:n,tag:o}=e;const i=t;return r.createElement(a.Z,null,t&&r.createElement("meta",{name:"docusaurus_locale",content:t}),n&&r.createElement("meta",{name:"docusaurus_version",content:n}),o&&r.createElement("meta",{name:"docusaurus_tag",content:o}),i&&r.createElement("meta",{name:"docsearch:language",content:i}),n&&r.createElement("meta",{name:"docsearch:version",content:n}),o&&r.createElement("meta",{name:"docsearch:docusaurus_tag",content:o}))}},941:(e,t,n)=>{"use strict";n.d(t,{Z:()=>u});var r=n(7462),a=n(7294),o=n(6010),i=n(2389),l=n(2949);const s={themedImage:"themedImage_ToTc","themedImage--light":"themedImage--light_HNdA","themedImage--dark":"themedImage--dark_i4oU"};function u(e){const t=(0,i.Z)(),{colorMode:n}=(0,l.I)(),{sources:u,className:c,alt:d,...f}=e,p=t?"dark"===n?["dark"]:["light"]:["light","dark"];return a.createElement(a.Fragment,null,p.map((e=>a.createElement("img",(0,r.Z)({key:e,src:u[e],alt:d,className:(0,o.Z)(s.themedImage,s[`themedImage--${e}`],c)},f)))))}},6043:(e,t,n)=>{"use strict";n.d(t,{u:()=>s,z:()=>g});var r=n(7462),a=n(7294),o=n(412),i=n(1442);const l="ease-in-out";function s(e){let{initialState:t}=e;const[n,r]=(0,a.useState)(t??!1),o=(0,a.useCallback)((()=>{r((e=>!e))}),[]);return{collapsed:n,setCollapsed:r,toggleCollapsed:o}}const u={display:"none",overflow:"hidden",height:"0px"},c={display:"block",overflow:"visible",height:"auto"};function d(e,t){const n=t?u:c;e.style.display=n.display,e.style.overflow=n.overflow,e.style.height=n.height}function f(e){let{collapsibleRef:t,collapsed:n,animation:r}=e;const o=(0,a.useRef)(!1);(0,a.useEffect)((()=>{const e=t.current;function a(){const t=e.scrollHeight,n=r?.duration??function(e){if((0,i.n)())return 1;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}(t);return{transition:`height ${n}ms ${r?.easing??l}`,height:`${t}px`}}function s(){const t=a();e.style.transition=t.transition,e.style.height=t.height}if(!o.current)return d(e,n),void(o.current=!0);return e.style.willChange="height",function(){const t=requestAnimationFrame((()=>{n?(s(),requestAnimationFrame((()=>{e.style.height=u.height,e.style.overflow=u.overflow}))):(e.style.display="block",requestAnimationFrame((()=>{s()})))}));return()=>cancelAnimationFrame(t)}()}),[t,n,r])}function p(e){if(!o.Z.canUseDOM)return e?u:c}function m(e){let{as:t="div",collapsed:n,children:r,animation:o,onCollapseTransitionEnd:i,className:l,disableSSRStyle:s}=e;const u=(0,a.useRef)(null);return f({collapsibleRef:u,collapsed:n,animation:o}),a.createElement(t,{ref:u,style:s?void 0:p(n),onTransitionEnd:e=>{"height"===e.propertyName&&(d(u.current,n),i?.(n))},className:l},r)}function h(e){let{collapsed:t,...n}=e;const[o,i]=(0,a.useState)(!t),[l,s]=(0,a.useState)(t);return(0,a.useLayoutEffect)((()=>{t||i(!0)}),[t]),(0,a.useLayoutEffect)((()=>{o&&s(t)}),[o,t]),o?a.createElement(m,(0,r.Z)({},n,{collapsed:l})):null}function g(e){let{lazy:t,...n}=e;const r=t?h:m;return a.createElement(r,n)}},9689:(e,t,n)=>{"use strict";n.d(t,{nT:()=>m,pl:()=>p});var r=n(7294),a=n(2389),o=n(12),i=n(902),l=n(6668);const s=(0,o.WA)("docusaurus.announcement.dismiss"),u=(0,o.WA)("docusaurus.announcement.id"),c=()=>"true"===s.get(),d=e=>s.set(String(e)),f=r.createContext(null);function p(e){let{children:t}=e;const n=function(){const{announcementBar:e}=(0,l.L)(),t=(0,a.Z)(),[n,o]=(0,r.useState)((()=>!!t&&c()));(0,r.useEffect)((()=>{o(c())}),[]);const i=(0,r.useCallback)((()=>{d(!0),o(!0)}),[]);return(0,r.useEffect)((()=>{if(!e)return;const{id:t}=e;let n=u.get();"annoucement-bar"===n&&(n="announcement-bar");const r=t!==n;u.set(t),r&&d(!1),!r&&c()||o(!1)}),[e]),(0,r.useMemo)((()=>({isActive:!!e&&!n,close:i})),[e,n,i])}();return r.createElement(f.Provider,{value:n},t)}function m(){const e=(0,r.useContext)(f);if(!e)throw new i.i6("AnnouncementBarProvider");return e}},2949:(e,t,n)=>{"use strict";n.d(t,{I:()=>g,S:()=>h});var r=n(7294),a=n(412),o=n(902),i=n(12),l=n(6668);const s=r.createContext(void 0),u="theme",c=(0,i.WA)(u),d={light:"light",dark:"dark"},f=e=>e===d.dark?d.dark:d.light,p=e=>a.Z.canUseDOM?f(document.documentElement.getAttribute("data-theme")):f(e),m=e=>{c.set(f(e))};function h(e){let{children:t}=e;const n=function(){const{colorMode:{defaultMode:e,disableSwitch:t,respectPrefersColorScheme:n}}=(0,l.L)(),[a,o]=(0,r.useState)(p(e));(0,r.useEffect)((()=>{t&&c.del()}),[t]);const i=(0,r.useCallback)((function(t,r){void 0===r&&(r={});const{persist:a=!0}=r;t?(o(t),a&&m(t)):(o(n?window.matchMedia("(prefers-color-scheme: dark)").matches?d.dark:d.light:e),c.del())}),[n,e]);(0,r.useEffect)((()=>{document.documentElement.setAttribute("data-theme",f(a))}),[a]),(0,r.useEffect)((()=>{if(t)return;const e=e=>{if(e.key!==u)return;const t=c.get();null!==t&&i(f(t))};return window.addEventListener("storage",e),()=>window.removeEventListener("storage",e)}),[t,i]);const s=(0,r.useRef)(!1);return(0,r.useEffect)((()=>{if(t&&!n)return;const e=window.matchMedia("(prefers-color-scheme: dark)"),r=()=>{window.matchMedia("print").matches||s.current?s.current=window.matchMedia("print").matches:i(null)};return e.addListener(r),()=>e.removeListener(r)}),[i,t,n]),(0,r.useMemo)((()=>({colorMode:a,setColorMode:i,get isDarkTheme(){return a===d.dark},setLightTheme(){i(d.light)},setDarkTheme(){i(d.dark)}})),[a,i])}();return r.createElement(s.Provider,{value:n},t)}function g(){const e=(0,r.useContext)(s);if(null==e)throw new o.i6("ColorModeProvider","Please see https://docusaurus.io/docs/api/themes/configuration#use-color-mode.");return e}},373:(e,t,n)=>{"use strict";n.d(t,{J:()=>v,L5:()=>g,Oh:()=>y});var r=n(7294),a=n(143),o=n(9935),i=n(6668),l=n(3438),s=n(902),u=n(12);const c=e=>`docs-preferred-version-${e}`,d={save:(e,t,n)=>{(0,u.WA)(c(e),{persistence:t}).set(n)},read:(e,t)=>(0,u.WA)(c(e),{persistence:t}).get(),clear:(e,t)=>{(0,u.WA)(c(e),{persistence:t}).del()}},f=e=>Object.fromEntries(e.map((e=>[e,{preferredVersionName:null}])));const p=r.createContext(null);function m(){const e=(0,a._r)(),t=(0,i.L)().docs.versionPersistence,n=(0,r.useMemo)((()=>Object.keys(e)),[e]),[o,l]=(0,r.useState)((()=>f(n)));(0,r.useEffect)((()=>{l(function(e){let{pluginIds:t,versionPersistence:n,allDocsData:r}=e;function a(e){const t=d.read(e,n);return r[e].versions.some((e=>e.name===t))?{preferredVersionName:t}:(d.clear(e,n),{preferredVersionName:null})}return Object.fromEntries(t.map((e=>[e,a(e)])))}({allDocsData:e,versionPersistence:t,pluginIds:n}))}),[e,t,n]);return[o,(0,r.useMemo)((()=>({savePreferredVersion:function(e,n){d.save(e,t,n),l((t=>({...t,[e]:{preferredVersionName:n}})))}})),[t])]}function h(e){let{children:t}=e;const n=m();return r.createElement(p.Provider,{value:n},t)}function g(e){let{children:t}=e;return l.cE?r.createElement(h,null,t):r.createElement(r.Fragment,null,t)}function b(){const e=(0,r.useContext)(p);if(!e)throw new s.i6("DocsPreferredVersionContextProvider");return e}function v(e){void 0===e&&(e=o.m);const t=(0,a.zh)(e),[n,i]=b(),{preferredVersionName:l}=n[e];return{preferredVersion:t.versions.find((e=>e.name===l))??null,savePreferredVersionName:(0,r.useCallback)((t=>{i.savePreferredVersion(e,t)}),[i,e])}}function y(){const e=(0,a._r)(),[t]=b();function n(n){const r=e[n],{preferredVersionName:a}=t[n];return r.versions.find((e=>e.name===a))??null}const r=Object.keys(e);return Object.fromEntries(r.map((e=>[e,n(e)])))}},1116:(e,t,n)=>{"use strict";n.d(t,{V:()=>s,b:()=>l});var r=n(7294),a=n(902);const o=Symbol("EmptyContext"),i=r.createContext(o);function l(e){let{children:t,name:n,items:a}=e;const o=(0,r.useMemo)((()=>n&&a?{name:n,items:a}:null),[n,a]);return r.createElement(i.Provider,{value:o},t)}function s(){const e=(0,r.useContext)(i);if(e===o)throw new a.i6("DocsSidebarProvider");return e}},3163:(e,t,n)=>{"use strict";n.d(t,{M:()=>d,e:()=>f});var r=n(7294),a=n(3102),o=n(7524),i=n(1980),l=n(6668),s=n(902);const u=r.createContext(void 0);function c(){const e=function(){const e=(0,a.HY)(),{items:t}=(0,l.L)().navbar;return 0===t.length&&!e.component}(),t=(0,o.i)(),n=!e&&"mobile"===t,[s,u]=(0,r.useState)(!1);(0,i.Rb)((()=>{if(s)return u(!1),!1}));const c=(0,r.useCallback)((()=>{u((e=>!e))}),[]);return(0,r.useEffect)((()=>{"desktop"===t&&u(!1)}),[t]),(0,r.useMemo)((()=>({disabled:e,shouldRender:n,toggle:c,shown:s})),[e,n,c,s])}function d(e){let{children:t}=e;const n=c();return r.createElement(u.Provider,{value:n},t)}function f(){const e=r.useContext(u);if(void 0===e)throw new s.i6("NavbarMobileSidebarProvider");return e}},3102:(e,t,n)=>{"use strict";n.d(t,{HY:()=>l,Zo:()=>s,n2:()=>i});var r=n(7294),a=n(902);const o=r.createContext(null);function i(e){let{children:t}=e;const n=(0,r.useState)({component:null,props:null});return r.createElement(o.Provider,{value:n},t)}function l(){const e=(0,r.useContext)(o);if(!e)throw new a.i6("NavbarSecondaryMenuContentProvider");return e[0]}function s(e){let{component:t,props:n}=e;const i=(0,r.useContext)(o);if(!i)throw new a.i6("NavbarSecondaryMenuContentProvider");const[,l]=i,s=(0,a.Ql)(n);return(0,r.useEffect)((()=>{l({component:t,props:s})}),[l,t,s]),(0,r.useEffect)((()=>()=>l({component:null,props:null})),[l]),null}},9727:(e,t,n)=>{"use strict";n.d(t,{h:()=>a,t:()=>o});var r=n(7294);const a="navigation-with-keyboard";function o(){(0,r.useEffect)((()=>{function e(e){"keydown"===e.type&&"Tab"===e.key&&document.body.classList.add(a),"mousedown"===e.type&&document.body.classList.remove(a)}return document.addEventListener("keydown",e),document.addEventListener("mousedown",e),()=>{document.body.classList.remove(a),document.removeEventListener("keydown",e),document.removeEventListener("mousedown",e)}}),[])}},6177:(e,t,n)=>{"use strict";n.d(t,{K:()=>l,M:()=>s});var r=n(7294),a=n(2263),o=n(1980);const i="q";function l(){return(0,o.Nc)(i)}function s(){const{siteConfig:{baseUrl:e,themeConfig:t}}=(0,a.Z)(),{algolia:{searchPagePath:n}}=t;return(0,r.useCallback)((t=>`${e}${n}?${i}=${encodeURIComponent(t)}`),[e,n])}},7524:(e,t,n)=>{"use strict";n.d(t,{i:()=>u});var r=n(7294),a=n(412);const o={desktop:"desktop",mobile:"mobile",ssr:"ssr"},i=996;function l(){return a.Z.canUseDOM?window.innerWidth>i?o.desktop:o.mobile:o.ssr}const s=!1;function u(){const[e,t]=(0,r.useState)((()=>s?"ssr":l()));return(0,r.useEffect)((()=>{function e(){t(l())}const n=s?window.setTimeout(e,1e3):void 0;return window.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),clearTimeout(n)}}),[]),e}},5281:(e,t,n)=>{"use strict";n.d(t,{k:()=>r});const r={page:{blogListPage:"blog-list-page",blogPostPage:"blog-post-page",blogTagsListPage:"blog-tags-list-page",blogTagPostListPage:"blog-tags-post-list-page",docsDocPage:"docs-doc-page",docsTagsListPage:"docs-tags-list-page",docsTagDocListPage:"docs-tags-doc-list-page",mdxPage:"mdx-page"},wrapper:{main:"main-wrapper",blogPages:"blog-wrapper",docsPages:"docs-wrapper",mdxPages:"mdx-wrapper"},common:{editThisPage:"theme-edit-this-page",lastUpdated:"theme-last-updated",backToTopButton:"theme-back-to-top-button",codeBlock:"theme-code-block",admonition:"theme-admonition",admonitionType:e=>`theme-admonition-${e}`},layout:{},docs:{docVersionBanner:"theme-doc-version-banner",docVersionBadge:"theme-doc-version-badge",docBreadcrumbs:"theme-doc-breadcrumbs",docMarkdown:"theme-doc-markdown",docTocMobile:"theme-doc-toc-mobile",docTocDesktop:"theme-doc-toc-desktop",docFooter:"theme-doc-footer",docFooterTagsRow:"theme-doc-footer-tags-row",docFooterEditMetaRow:"theme-doc-footer-edit-meta-row",docSidebarContainer:"theme-doc-sidebar-container",docSidebarMenu:"theme-doc-sidebar-menu",docSidebarItemCategory:"theme-doc-sidebar-item-category",docSidebarItemLink:"theme-doc-sidebar-item-link",docSidebarItemCategoryLevel:e=>`theme-doc-sidebar-item-category-level-${e}`,docSidebarItemLinkLevel:e=>`theme-doc-sidebar-item-link-level-${e}`},blog:{}}},1442:(e,t,n)=>{"use strict";function r(){return window.matchMedia("(prefers-reduced-motion: reduce)").matches}n.d(t,{n:()=>r})},3438:(e,t,n)=>{"use strict";n.d(t,{Wl:()=>f,_F:()=>h,cE:()=>d,hI:()=>S,lO:()=>v,oz:()=>y,s1:()=>b,vY:()=>E});var r=n(7294),a=n(6550),o=n(8790),i=n(143),l=n(373),s=n(1116),u=n(7392),c=n(8596);const d=!!i._r;function f(e){if(e.href)return e.href;for(const t of e.items){if("link"===t.type)return t.href;if("category"===t.type){const e=f(t);if(e)return e}}}const p=(e,t)=>void 0!==e&&(0,c.Mg)(e,t),m=(e,t)=>e.some((e=>h(e,t)));function h(e,t){return"link"===e.type?p(e.href,t):"category"===e.type&&(p(e.href,t)||m(e.items,t))}function g(e){let{sidebarItems:t,pathname:n,onlyCategories:r=!1}=e;const a=[];return function e(t){for(const o of t)if("category"===o.type&&((0,c.Mg)(o.href,n)||e(o.items))||"link"===o.type&&(0,c.Mg)(o.href,n)){return r&&"category"!==o.type||a.unshift(o),!0}return!1}(t),a}function b(){const e=(0,s.V)(),{pathname:t}=(0,a.TH)(),n=(0,i.gA)()?.pluginData.breadcrumbs;return!1!==n&&e?g({sidebarItems:e.items,pathname:t}):null}function v(e){const{activeVersion:t}=(0,i.Iw)(e),{preferredVersion:n}=(0,l.J)(e),a=(0,i.yW)(e);return(0,r.useMemo)((()=>(0,u.j)([t,n,a].filter(Boolean))),[t,n,a])}function y(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.sidebars?Object.entries(e.sidebars):[])),r=t.find((t=>t[0]===e));if(!r)throw new Error(`Can't find any sidebar with id "${e}" in version${n.length>1?"s":""} ${n.map((e=>e.name)).join(", ")}".\nAvailable sidebar ids are:\n- ${t.map((e=>e[0])).join("\n- ")}`);return r[1]}),[e,n])}function E(e,t){const n=v(t);return(0,r.useMemo)((()=>{const t=n.flatMap((e=>e.docs)),r=t.find((t=>t.id===e));if(!r){if(n.flatMap((e=>e.draftIds)).includes(e))return null;throw new Error(`Couldn't find any doc with id "${e}" in version${n.length>1?"s":""} "${n.map((e=>e.name)).join(", ")}".\nAvailable doc ids are:\n- ${(0,u.j)(t.map((e=>e.id))).join("\n- ")}`)}return r}),[e,n])}function S(e){let{route:t,versionMetadata:n}=e;const r=(0,a.TH)(),i=t.routes,l=i.find((e=>(0,a.LX)(r.pathname,e)));if(!l)return null;const s=l.sidebar,u=s?n.docsSidebars[s]:void 0;return{docElement:(0,o.H)(i),sidebarName:s,sidebarItems:u}}},2128:(e,t,n)=>{"use strict";n.d(t,{p:()=>a});var r=n(2263);function a(e){const{siteConfig:t}=(0,r.Z)(),{title:n,titleDelimiter:a}=t;return e?.trim().length?`${e.trim()} ${a} ${n}`:n}},1980:(e,t,n)=>{"use strict";n.d(t,{Nc:()=>u,Rb:()=>l,_X:()=>s});var r=n(7294),a=n(6550),o=n(1688),i=n(902);function l(e){!function(e){const t=(0,a.k6)(),n=(0,i.zX)(e);(0,r.useEffect)((()=>t.block(((e,t)=>n(e,t)))),[t,n])}(((t,n)=>{if("POP"===n)return e(t,n)}))}function s(e){return function(e){const t=(0,a.k6)();return(0,o.useSyncExternalStore)(t.listen,(()=>e(t)),(()=>e(t)))}((t=>null===e?null:new URLSearchParams(t.location.search).get(e)))}function u(e){const t=s(e)??"",n=function(){const e=(0,a.k6)();return(0,r.useCallback)(((t,n,r)=>{const a=new URLSearchParams(e.location.search);n?a.set(t,n):a.delete(t),(r?.push?e.push:e.replace)({search:a.toString()})}),[e])}();return[t,(0,r.useCallback)(((t,r)=>{n(e,t,r)}),[n,e])]}},7392:(e,t,n)=>{"use strict";function r(e,t){return void 0===t&&(t=(e,t)=>e===t),e.filter(((n,r)=>e.findIndex((e=>t(e,n)))!==r))}function a(e){return Array.from(new Set(e))}n.d(t,{j:()=>a,l:()=>r})},833:(e,t,n)=>{"use strict";n.d(t,{FG:()=>f,d:()=>c,VC:()=>p});var r=n(7294),a=n(6010),o=n(5742),i=n(226);function l(){const e=r.useContext(i._);if(!e)throw new Error("Unexpected: no Docusaurus route context found");return e}var s=n(4996),u=n(2128);function c(e){let{title:t,description:n,keywords:a,image:i,children:l}=e;const c=(0,u.p)(t),{withBaseUrl:d}=(0,s.C)(),f=i?d(i,{absolute:!0}):void 0;return r.createElement(o.Z,null,t&&r.createElement("title",null,c),t&&r.createElement("meta",{property:"og:title",content:c}),n&&r.createElement("meta",{name:"description",content:n}),n&&r.createElement("meta",{property:"og:description",content:n}),a&&r.createElement("meta",{name:"keywords",content:Array.isArray(a)?a.join(","):a}),f&&r.createElement("meta",{property:"og:image",content:f}),f&&r.createElement("meta",{name:"twitter:image",content:f}),l)}const d=r.createContext(void 0);function f(e){let{className:t,children:n}=e;const i=r.useContext(d),l=(0,a.Z)(i,t);return r.createElement(d.Provider,{value:l},r.createElement(o.Z,null,r.createElement("html",{className:l})),n)}function p(e){let{children:t}=e;const n=l(),o=`plugin-${n.plugin.name.replace(/docusaurus-(?:plugin|theme)-(?:content-)?/gi,"")}`;const i=`plugin-id-${n.plugin.id}`;return r.createElement(f,{className:(0,a.Z)(o,i)},t)}},902:(e,t,n)=>{"use strict";n.d(t,{D9:()=>i,Qc:()=>u,Ql:()=>s,i6:()=>l,zX:()=>o});var r=n(7294);const a=n(412).Z.canUseDOM?r.useLayoutEffect:r.useEffect;function o(e){const t=(0,r.useRef)(e);return a((()=>{t.current=e}),[e]),(0,r.useCallback)((function(){return t.current(...arguments)}),[])}function i(e){const t=(0,r.useRef)();return a((()=>{t.current=e})),t.current}class l extends Error{constructor(e,t){super(),this.name="ReactContextError",this.message=`Hook ${this.stack?.split("\n")[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups.name??""} is called outside the <${e}>. ${t??""}`}}function s(e){const t=Object.entries(e);return t.sort(((e,t)=>e[0].localeCompare(t[0]))),(0,r.useMemo)((()=>e),t.flat())}function u(e){return t=>{let{children:n}=t;return r.createElement(r.Fragment,null,e.reduceRight(((e,t)=>r.createElement(t,null,e)),n))}}},8022:(e,t,n)=>{"use strict";function r(e,t){return void 0!==e&&void 0!==t&&new RegExp(e,"gi").test(t)}n.d(t,{F:()=>r})},8596:(e,t,n)=>{"use strict";n.d(t,{Mg:()=>i,Ns:()=>l});var r=n(7294),a=n(723),o=n(2263);function i(e,t){const n=e=>(!e||e.endsWith("/")?e:`${e}/`)?.toLowerCase();return n(e)===n(t)}function l(){const{baseUrl:e}=(0,o.Z)().siteConfig;return(0,r.useMemo)((()=>function(e){let{baseUrl:t,routes:n}=e;function r(e){return e.path===t&&!0===e.exact}function a(e){return e.path===t&&!e.exact}return function e(t){if(0===t.length)return;return t.find(r)||e(t.filter(a).flatMap((e=>e.routes??[])))}(n)}({routes:a.Z,baseUrl:e})),[e])}},2466:(e,t,n)=>{"use strict";n.d(t,{Ct:()=>p,OC:()=>s,RF:()=>d,o5:()=>f});var r=n(7294),a=n(412),o=n(2389),i=n(902);const l=r.createContext(void 0);function s(e){let{children:t}=e;const n=function(){const e=(0,r.useRef)(!0);return(0,r.useMemo)((()=>({scrollEventsEnabledRef:e,enableScrollEvents:()=>{e.current=!0},disableScrollEvents:()=>{e.current=!1}})),[])}();return r.createElement(l.Provider,{value:n},t)}function u(){const e=(0,r.useContext)(l);if(null==e)throw new i.i6("ScrollControllerProvider");return e}const c=()=>a.Z.canUseDOM?{scrollX:window.pageXOffset,scrollY:window.pageYOffset}:null;function d(e,t){void 0===t&&(t=[]);const{scrollEventsEnabledRef:n}=u(),a=(0,r.useRef)(c()),o=(0,i.zX)(e);(0,r.useEffect)((()=>{const e=()=>{if(!n.current)return;const e=c();o(e,a.current),a.current=e},t={passive:!0};return e(),window.addEventListener("scroll",e,t),()=>window.removeEventListener("scroll",e,t)}),[o,n,...t])}function f(){const e=u(),t=function(){const e=(0,r.useRef)({elem:null,top:0}),t=(0,r.useCallback)((t=>{e.current={elem:t,top:t.getBoundingClientRect().top}}),[]),n=(0,r.useCallback)((()=>{const{current:{elem:t,top:n}}=e;if(!t)return{restored:!1};const r=t.getBoundingClientRect().top-n;return r&&window.scrollBy({left:0,top:r}),e.current={elem:null,top:0},{restored:0!==r}}),[]);return(0,r.useMemo)((()=>({save:t,restore:n})),[n,t])}(),n=(0,r.useRef)(void 0),a=(0,r.useCallback)((r=>{t.save(r),e.disableScrollEvents(),n.current=()=>{const{restored:r}=t.restore();if(n.current=void 0,r){const t=()=>{e.enableScrollEvents(),window.removeEventListener("scroll",t)};window.addEventListener("scroll",t)}else e.enableScrollEvents()}}),[e,t]);return(0,r.useLayoutEffect)((()=>{queueMicrotask((()=>n.current?.()))})),{blockElementScrollPositionUntilNextRender:a}}function p(){const e=(0,r.useRef)(null),t=(0,o.Z)()&&"smooth"===getComputedStyle(document.documentElement).scrollBehavior;return{startScroll:n=>{e.current=t?function(e){return window.scrollTo({top:e,behavior:"smooth"}),()=>{}}(n):function(e){let t=null;const n=document.documentElement.scrollTop>e;return function r(){const a=document.documentElement.scrollTop;(n&&a>e||!n&&a<e)&&(t=requestAnimationFrame(r),window.scrollTo(0,Math.floor(.85*(a-e))+e))}(),()=>t&&cancelAnimationFrame(t)}(n)},cancelScroll:()=>e.current?.()}}},3320:(e,t,n)=>{"use strict";n.d(t,{HX:()=>i,_q:()=>s,os:()=>l});var r=n(143),a=n(2263),o=n(373);const i="default";function l(e,t){return`docs-${e}-${t}`}function s(){const{i18n:e}=(0,a.Z)(),t=(0,r._r)(),n=(0,r.WS)(),s=(0,o.Oh)();const u=[i,...Object.keys(t).map((function(e){const r=n?.activePlugin.pluginId===e?n.activeVersion:void 0,a=s[e],o=t[e].versions.find((e=>e.isLast));return l(e,(r??a??o).name)}))];return{locale:e.currentLocale,tags:u}}},12:(e,t,n)=>{"use strict";n.d(t,{Nk:()=>d,WA:()=>c,_f:()=>f});var r=n(7294),a=n(1688);const o="localStorage";function i(e){let{key:t,oldValue:n,newValue:r,storage:a}=e;if(n===r)return;const o=document.createEvent("StorageEvent");o.initStorageEvent("storage",!1,!1,t,n,r,window.location.href,a),window.dispatchEvent(o)}function l(e){if(void 0===e&&(e=o),"undefined"==typeof window)throw new Error("Browser storage is not available on Node.js/Docusaurus SSR process.");if("none"===e)return null;try{return window[e]}catch(n){return t=n,s||(console.warn("Docusaurus browser storage is not available.\nPossible reasons: running Docusaurus in an iframe, in an incognito browser session, or using too strict browser privacy settings.",t),s=!0),null}var t}let s=!1;const u={get:()=>null,set:()=>{},del:()=>{},listen:()=>()=>{}};function c(e,t){if("undefined"==typeof window)return function(e){function t(){throw new Error(`Illegal storage API usage for storage key "${e}".\nDocusaurus storage APIs are not supposed to be called on the server-rendering process.\nPlease only call storage APIs in effects and event handlers.`)}return{get:t,set:t,del:t,listen:t}}(e);const n=l(t?.persistence);return null===n?u:{get:()=>{try{return n.getItem(e)}catch(t){return console.error(`Docusaurus storage error, can't get key=${e}`,t),null}},set:t=>{try{const r=n.getItem(e);n.setItem(e,t),i({key:e,oldValue:r,newValue:t,storage:n})}catch(r){console.error(`Docusaurus storage error, can't set ${e}=${t}`,r)}},del:()=>{try{const t=n.getItem(e);n.removeItem(e),i({key:e,oldValue:t,newValue:null,storage:n})}catch(t){console.error(`Docusaurus storage error, can't delete key=${e}`,t)}},listen:t=>{try{const r=r=>{r.storageArea===n&&r.key===e&&t(r)};return window.addEventListener("storage",r),()=>window.removeEventListener("storage",r)}catch(r){return console.error(`Docusaurus storage error, can't listen for changes of key=${e}`,r),()=>{}}}}}function d(e,t){const n=(0,r.useRef)((()=>null===e?u:c(e,t))).current(),o=(0,r.useCallback)((e=>"undefined"==typeof window?()=>{}:n.listen(e)),[n]);return[(0,a.useSyncExternalStore)(o,(()=>"undefined"==typeof window?null:n.get()),(()=>null)),n]}function f(e){void 0===e&&(e=o);const t=l(e);if(!t)return[];const n=[];for(let r=0;r<t.length;r+=1){const e=t.key(r);null!==e&&n.push(e)}return n}},4711:(e,t,n)=>{"use strict";n.d(t,{l:()=>i});var r=n(2263),a=n(6550),o=n(8780);function i(){const{siteConfig:{baseUrl:e,url:t,trailingSlash:n},i18n:{defaultLocale:i,currentLocale:l}}=(0,r.Z)(),{pathname:s}=(0,a.TH)(),u=(0,o.applyTrailingSlash)(s,{trailingSlash:n,baseUrl:e}),c=l===i?e:e.replace(`/${l}/`,"/"),d=u.replace(e,"");return{createUrl:function(e){let{locale:n,fullyQualified:r}=e;return`${r?t:""}${function(e){return e===i?`${c}`:`${c}${e}/`}(n)}${d}`}}}},5936:(e,t,n)=>{"use strict";n.d(t,{S:()=>i});var r=n(7294),a=n(6550),o=n(902);function i(e){const t=(0,a.TH)(),n=(0,o.D9)(t),i=(0,o.zX)(e);(0,r.useEffect)((()=>{n&&t!==n&&i({location:t,previousLocation:n})}),[i,t,n])}},6668:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){return(0,r.Z)().siteConfig.themeConfig}},6278:(e,t,n)=>{"use strict";n.d(t,{L:()=>a});var r=n(2263);function a(){const{siteConfig:{themeConfig:e}}=(0,r.Z)();return e}},239:(e,t,n)=>{"use strict";n.d(t,{l:()=>l});var r=n(7294),a=n(8022),o=n(4996),i=n(6278);function l(){const{withBaseUrl:e}=(0,o.C)(),{algolia:{externalUrlRegex:t,replaceSearchResultPathname:n}}=(0,i.L)();return(0,r.useCallback)((r=>{const o=new URL(r);if((0,a.F)(t,o.href))return r;const i=`${o.pathname+o.hash}`;return e(function(e,t){return t?e.replaceAll(new RegExp(t.from,"g"),t.to):e}(i,n))}),[e,t,n])}},8802:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){const{trailingSlash:n,baseUrl:r}=t;if(e.startsWith("#"))return e;if(void 0===n)return e;const[a]=e.split(/[#?]/),o="/"===a||a===r?a:(i=a,n?function(e){return e.endsWith("/")?e:`${e}/`}(i):function(e){return e.endsWith("/")?e.slice(0,-1):e}(i));var i;return e.replace(a,o)}},4143:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=void 0,t.getErrorCausalChain=function e(t){return t.cause?[t,...e(t.cause)]:[t]}},8780:function(e,t,n){"use strict";var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.getErrorCausalChain=t.applyTrailingSlash=t.blogPostContainerID=void 0,t.blogPostContainerID="__blog-post-container";var a=n(8802);Object.defineProperty(t,"applyTrailingSlash",{enumerable:!0,get:function(){return r(a).default}});var o=n(4143);Object.defineProperty(t,"getErrorCausalChain",{enumerable:!0,get:function(){return o.getErrorCausalChain}})},8522:()=>{!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],variable:r.variable,function:{pattern:/(^|[\n;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i<a.length;i++)o[a[i]]=e.languages.bash[a[i]];e.languages.shell=e.languages.bash}(Prism)},5494:()=>{Prism.languages.qmake={comment:/#.*/,variable:/(?:(?:^|\n)[a-z_A-Z]\w+(?=\s*(?:=|\+=|-=|\*=|~=))\b|\${2}[a-z_A-Z]\w+\b(?!\()|\${2}{[a-z_A-Z]\w+}|\b(?:QT|TEMPLATE|CONFIG|DEFINES|SOURCES|HEADERS|INCLUDEPATH|LIBS|QMAKE_CXXFLAGS)\b)/,boolean:/\b(?:true|false)\b/,operator:/(=|\+=|-=|\*=|~=)/,number:/\b\d+(?:\.\d+)*\b/,function:/(?:\b[a-z_]\w*(?=\s*\()\b|\${2}[a-z_]\w+(?=\s*\()\b)/i}},9482:(e,t,n)=>{"use strict";n.d(t,{Z:()=>a});const r=(0,n(7294).createContext)(void 0);r.displayName="RootFolderContext";const a=r},6010:(e,t,n)=>{"use strict";function r(e){var t,n,a="";if("string"==typeof e||"number"==typeof e)a+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(n=r(e[t]))&&(a&&(a+=" "),a+=n);else for(t in e)e[t]&&(a&&(a+=" "),a+=t);return a}n.d(t,{Z:()=>a});const a=function(){for(var e,t,n=0,a="";n<arguments.length;)(e=arguments[n++])&&(t=r(e))&&(a&&(a+=" "),a+=t);return a}},9318:(e,t,n)=>{"use strict";n.d(t,{lX:()=>E,q_:()=>C,ob:()=>p,PP:()=>I,Ep:()=>f});var r=n(7462);function a(e){return"/"===e.charAt(0)}function o(e,t){for(var n=t,r=n+1,a=e.length;r<a;n+=1,r+=1)e[n]=e[r];e.pop()}const i=function(e,t){void 0===t&&(t="");var n,r=e&&e.split("/")||[],i=t&&t.split("/")||[],l=e&&a(e),s=t&&a(t),u=l||s;if(e&&a(e)?i=r:r.length&&(i.pop(),i=i.concat(r)),!i.length)return"/";if(i.length){var c=i[i.length-1];n="."===c||".."===c||""===c}else n=!1;for(var d=0,f=i.length;f>=0;f--){var p=i[f];"."===p?o(i,f):".."===p?(o(i,f),d++):d&&(o(i,f),d--)}if(!u)for(;d--;d)i.unshift("..");!u||""===i[0]||i[0]&&a(i[0])||i.unshift("");var m=i.join("/");return n&&"/"!==m.substr(-1)&&(m+="/"),m};var l=n(8776);function s(e){return"/"===e.charAt(0)?e:"/"+e}function u(e){return"/"===e.charAt(0)?e.substr(1):e}function c(e,t){return function(e,t){return 0===e.toLowerCase().indexOf(t.toLowerCase())&&-1!=="/?#".indexOf(e.charAt(t.length))}(e,t)?e.substr(t.length):e}function d(e){return"/"===e.charAt(e.length-1)?e.slice(0,-1):e}function f(e){var t=e.pathname,n=e.search,r=e.hash,a=t||"/";return n&&"?"!==n&&(a+="?"===n.charAt(0)?n:"?"+n),r&&"#"!==r&&(a+="#"===r.charAt(0)?r:"#"+r),a}function p(e,t,n,a){var o;"string"==typeof e?(o=function(e){var t=e||"/",n="",r="",a=t.indexOf("#");-1!==a&&(r=t.substr(a),t=t.substr(0,a));var o=t.indexOf("?");return-1!==o&&(n=t.substr(o),t=t.substr(0,o)),{pathname:t,search:"?"===n?"":n,hash:"#"===r?"":r}}(e),o.state=t):(void 0===(o=(0,r.Z)({},e)).pathname&&(o.pathname=""),o.search?"?"!==o.search.charAt(0)&&(o.search="?"+o.search):o.search="",o.hash?"#"!==o.hash.charAt(0)&&(o.hash="#"+o.hash):o.hash="",void 0!==t&&void 0===o.state&&(o.state=t));try{o.pathname=decodeURI(o.pathname)}catch(l){throw l instanceof URIError?new URIError('Pathname "'+o.pathname+'" could not be decoded. This is likely caused by an invalid percent-encoding.'):l}return n&&(o.key=n),a?o.pathname?"/"!==o.pathname.charAt(0)&&(o.pathname=i(o.pathname,a.pathname)):o.pathname=a.pathname:o.pathname||(o.pathname="/"),o}function m(){var e=null;var t=[];return{setPrompt:function(t){return e=t,function(){e===t&&(e=null)}},confirmTransitionTo:function(t,n,r,a){if(null!=e){var o="function"==typeof e?e(t,n):e;"string"==typeof o?"function"==typeof r?r(o,a):a(!0):a(!1!==o)}else a(!0)},appendListener:function(e){var n=!0;function r(){n&&e.apply(void 0,arguments)}return t.push(r),function(){n=!1,t=t.filter((function(e){return e!==r}))}},notifyListeners:function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];t.forEach((function(e){return e.apply(void 0,n)}))}}}var h=!("undefined"==typeof window||!window.document||!window.document.createElement);function g(e,t){t(window.confirm(e))}var b="popstate",v="hashchange";function y(){try{return window.history.state||{}}catch(e){return{}}}function E(e){void 0===e&&(e={}),h||(0,l.Z)(!1);var t,n=window.history,a=(-1===(t=window.navigator.userAgent).indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone"))&&window.history&&"pushState"in window.history,o=!(-1===window.navigator.userAgent.indexOf("Trident")),i=e,u=i.forceRefresh,E=void 0!==u&&u,S=i.getUserConfirmation,_=void 0===S?g:S,w=i.keyLength,T=void 0===w?6:w,k=e.basename?d(s(e.basename)):"";function C(e){var t=e||{},n=t.key,r=t.state,a=window.location,o=a.pathname+a.search+a.hash;return k&&(o=c(o,k)),p(o,r,n)}function A(){return Math.random().toString(36).substr(2,T)}var I=m();function O(e){(0,r.Z)(z,e),z.length=n.length,I.notifyListeners(z.location,z.action)}function R(e){(function(e){return void 0===e.state&&-1===navigator.userAgent.indexOf("CriOS")})(e)||P(C(e.state))}function N(){P(C(y()))}var L=!1;function P(e){if(L)L=!1,O();else{I.confirmTransitionTo(e,"POP",_,(function(t){t?O({action:"POP",location:e}):function(e){var t=z.location,n=D.indexOf(t.key);-1===n&&(n=0);var r=D.indexOf(e.key);-1===r&&(r=0);var a=n-r;a&&(L=!0,U(a))}(e)}))}}var x=C(y()),D=[x.key];function M(e){return k+f(e)}function U(e){n.go(e)}var F=0;function B(e){1===(F+=e)&&1===e?(window.addEventListener(b,R),o&&window.addEventListener(v,N)):0===F&&(window.removeEventListener(b,R),o&&window.removeEventListener(v,N))}var $=!1;var z={length:n.length,action:"POP",location:x,createHref:M,push:function(e,t){var r="PUSH",o=p(e,t,A(),z.location);I.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.pushState({key:i,state:l},null,t),E)window.location.href=t;else{var s=D.indexOf(z.location.key),u=D.slice(0,s+1);u.push(o.key),D=u,O({action:r,location:o})}else window.location.href=t}}))},replace:function(e,t){var r="REPLACE",o=p(e,t,A(),z.location);I.confirmTransitionTo(o,r,_,(function(e){if(e){var t=M(o),i=o.key,l=o.state;if(a)if(n.replaceState({key:i,state:l},null,t),E)window.location.replace(t);else{var s=D.indexOf(z.location.key);-1!==s&&(D[s]=o.key),O({action:r,location:o})}else window.location.replace(t)}}))},go:U,goBack:function(){U(-1)},goForward:function(){U(1)},block:function(e){void 0===e&&(e=!1);var t=I.setPrompt(e);return $||(B(1),$=!0),function(){return $&&($=!1,B(-1)),t()}},listen:function(e){var t=I.appendListener(e);return B(1),function(){B(-1),t()}}};return z}var S="hashchange",_={hashbang:{encodePath:function(e){return"!"===e.charAt(0)?e:"!/"+u(e)},decodePath:function(e){return"!"===e.charAt(0)?e.substr(1):e}},noslash:{encodePath:u,decodePath:s},slash:{encodePath:s,decodePath:s}};function w(e){var t=e.indexOf("#");return-1===t?e:e.slice(0,t)}function T(){var e=window.location.href,t=e.indexOf("#");return-1===t?"":e.substring(t+1)}function k(e){window.location.replace(w(window.location.href)+"#"+e)}function C(e){void 0===e&&(e={}),h||(0,l.Z)(!1);var t=window.history,n=(window.navigator.userAgent.indexOf("Firefox"),e),a=n.getUserConfirmation,o=void 0===a?g:a,i=n.hashType,u=void 0===i?"slash":i,b=e.basename?d(s(e.basename)):"",v=_[u],y=v.encodePath,E=v.decodePath;function C(){var e=E(T());return b&&(e=c(e,b)),p(e)}var A=m();function I(e){(0,r.Z)($,e),$.length=t.length,A.notifyListeners($.location,$.action)}var O=!1,R=null;function N(){var e,t,n=T(),r=y(n);if(n!==r)k(r);else{var a=C(),i=$.location;if(!O&&(t=a,(e=i).pathname===t.pathname&&e.search===t.search&&e.hash===t.hash))return;if(R===f(a))return;R=null,function(e){if(O)O=!1,I();else{var t="POP";A.confirmTransitionTo(e,t,o,(function(n){n?I({action:t,location:e}):function(e){var t=$.location,n=D.lastIndexOf(f(t));-1===n&&(n=0);var r=D.lastIndexOf(f(e));-1===r&&(r=0);var a=n-r;a&&(O=!0,M(a))}(e)}))}}(a)}}var L=T(),P=y(L);L!==P&&k(P);var x=C(),D=[f(x)];function M(e){t.go(e)}var U=0;function F(e){1===(U+=e)&&1===e?window.addEventListener(S,N):0===U&&window.removeEventListener(S,N)}var B=!1;var $={length:t.length,action:"POP",location:x,createHref:function(e){var t=document.querySelector("base"),n="";return t&&t.getAttribute("href")&&(n=w(window.location.href)),n+"#"+y(b+f(e))},push:function(e,t){var n="PUSH",r=p(e,void 0,void 0,$.location);A.confirmTransitionTo(r,n,o,(function(e){if(e){var t=f(r),a=y(b+t);if(T()!==a){R=t,function(e){window.location.hash=e}(a);var o=D.lastIndexOf(f($.location)),i=D.slice(0,o+1);i.push(t),D=i,I({action:n,location:r})}else I()}}))},replace:function(e,t){var n="REPLACE",r=p(e,void 0,void 0,$.location);A.confirmTransitionTo(r,n,o,(function(e){if(e){var t=f(r),a=y(b+t);T()!==a&&(R=t,k(a));var o=D.indexOf(f($.location));-1!==o&&(D[o]=t),I({action:n,location:r})}}))},go:M,goBack:function(){M(-1)},goForward:function(){M(1)},block:function(e){void 0===e&&(e=!1);var t=A.setPrompt(e);return B||(F(1),B=!0),function(){return B&&(B=!1,F(-1)),t()}},listen:function(e){var t=A.appendListener(e);return F(1),function(){F(-1),t()}}};return $}function A(e,t,n){return Math.min(Math.max(e,t),n)}function I(e){void 0===e&&(e={});var t=e,n=t.getUserConfirmation,a=t.initialEntries,o=void 0===a?["/"]:a,i=t.initialIndex,l=void 0===i?0:i,s=t.keyLength,u=void 0===s?6:s,c=m();function d(e){(0,r.Z)(E,e),E.length=E.entries.length,c.notifyListeners(E.location,E.action)}function h(){return Math.random().toString(36).substr(2,u)}var g=A(l,0,o.length-1),b=o.map((function(e){return p(e,void 0,"string"==typeof e?h():e.key||h())})),v=f;function y(e){var t=A(E.index+e,0,E.entries.length-1),r=E.entries[t];c.confirmTransitionTo(r,"POP",n,(function(e){e?d({action:"POP",location:r,index:t}):d()}))}var E={length:b.length,action:"POP",location:b[g],index:g,entries:b,createHref:v,push:function(e,t){var r="PUSH",a=p(e,t,h(),E.location);c.confirmTransitionTo(a,r,n,(function(e){if(e){var t=E.index+1,n=E.entries.slice(0);n.length>t?n.splice(t,n.length-t,a):n.push(a),d({action:r,location:a,index:t,entries:n})}}))},replace:function(e,t){var r="REPLACE",a=p(e,t,h(),E.location);c.confirmTransitionTo(a,r,n,(function(e){e&&(E.entries[E.index]=a,d({action:r,location:a}))}))},go:y,goBack:function(){y(-1)},goForward:function(){y(1)},canGo:function(e){var t=E.index+e;return t>=0&&t<E.entries.length},block:function(e){return void 0===e&&(e=!1),c.setPrompt(e)},listen:function(e){return c.appendListener(e)}};return E}},8679:(e,t,n)=>{"use strict";var r=n(9864),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||a}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var u=Object.defineProperty,c=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var a=p(n);a&&a!==m&&e(t,a,r)}var i=c(n);d&&(i=i.concat(d(n)));for(var l=s(t),h=s(n),g=0;g<i.length;++g){var b=i[g];if(!(o[b]||r&&r[b]||h&&h[b]||l&&l[b])){var v=f(n,b);try{u(t,b,v)}catch(y){}}}}return t}},1143:e=>{"use strict";e.exports=function(e,t,n,r,a,o,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var u=[n,r,a,o,i,l],c=0;(s=new Error(t.replace(/%s/g,(function(){return u[c++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},5826:e=>{e.exports=Array.isArray||function(e){return"[object Array]"==Object.prototype.toString.call(e)}},2497:(e,t,n)=>{"use strict";n.r(t)},8213:(e,t,n)=>{"use strict";n.r(t)},4865:function(e,t,n){var r,a;r=function(){var e,t,n={version:"0.2.0"},r=n.settings={minimum:.08,easing:"ease",positionUsing:"",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,showSpinner:!0,barSelector:'[role="bar"]',spinnerSelector:'[role="spinner"]',parent:"body",template:'<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'};function a(e,t,n){return e<t?t:e>n?n:e}function o(e){return 100*(-1+e)}function i(e,t,n){var a;return(a="translate3d"===r.positionUsing?{transform:"translate3d("+o(e)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+o(e)+"%,0)"}:{"margin-left":o(e)+"%"}).transition="all "+t+"ms "+n,a}n.configure=function(e){var t,n;for(t in e)void 0!==(n=e[t])&&e.hasOwnProperty(t)&&(r[t]=n);return this},n.status=null,n.set=function(e){var t=n.isStarted();e=a(e,r.minimum,1),n.status=1===e?null:e;var o=n.render(!t),u=o.querySelector(r.barSelector),c=r.speed,d=r.easing;return o.offsetWidth,l((function(t){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(u,i(e,c,d)),1===e?(s(o,{transition:"none",opacity:1}),o.offsetWidth,setTimeout((function(){s(o,{transition:"all "+c+"ms linear",opacity:0}),setTimeout((function(){n.remove(),t()}),c)}),c)):setTimeout(t,c)})),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var e=function(){setTimeout((function(){n.status&&(n.trickle(),e())}),r.trickleSpeed)};return r.trickle&&e(),this},n.done=function(e){return e||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(e){var t=n.status;return t?("number"!=typeof e&&(e=(1-t)*a(Math.random()*t,.1,.95)),t=a(t+e,0,.994),n.set(t)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},e=0,t=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===t&&n.start(),e++,t++,r.always((function(){0==--t?(e=0,n.done()):n.set((e-t)/e)})),this):this},n.render=function(e){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var t=document.createElement("div");t.id="nprogress",t.innerHTML=r.template;var a,i=t.querySelector(r.barSelector),l=e?"-100":o(n.status||0),u=document.querySelector(r.parent);return s(i,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),r.showSpinner||(a=t.querySelector(r.spinnerSelector))&&p(a),u!=document.body&&c(u,"nprogress-custom-parent"),u.appendChild(t),t},n.remove=function(){d(document.documentElement,"nprogress-busy"),d(document.querySelector(r.parent),"nprogress-custom-parent");var e=document.getElementById("nprogress");e&&p(e)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var e=document.body.style,t="WebkitTransform"in e?"Webkit":"MozTransform"in e?"Moz":"msTransform"in e?"ms":"OTransform"in e?"O":"";return t+"Perspective"in e?"translate3d":t+"Transform"in e?"translate":"margin"};var l=function(){var e=[];function t(){var n=e.shift();n&&n(t)}return function(n){e.push(n),1==e.length&&t()}}(),s=function(){var e=["Webkit","O","Moz","ms"],t={};function n(e){return e.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,(function(e,t){return t.toUpperCase()}))}function r(t){var n=document.body.style;if(t in n)return t;for(var r,a=e.length,o=t.charAt(0).toUpperCase()+t.slice(1);a--;)if((r=e[a]+o)in n)return r;return t}function a(e){return e=n(e),t[e]||(t[e]=r(e))}function o(e,t,n){t=a(t),e.style[t]=n}return function(e,t){var n,r,a=arguments;if(2==a.length)for(n in t)void 0!==(r=t[n])&&t.hasOwnProperty(n)&&o(e,n,r);else o(e,a[1],a[2])}}();function u(e,t){return("string"==typeof e?e:f(e)).indexOf(" "+t+" ")>=0}function c(e,t){var n=f(e),r=n+t;u(n,t)||(e.className=r.substring(1))}function d(e,t){var n,r=f(e);u(e,t)&&(n=r.replace(" "+t+" "," "),e.className=n.substring(1,n.length-1))}function f(e){return(" "+(e.className||"")+" ").replace(/\s+/gi," ")}function p(e){e&&e.parentNode&&e.parentNode.removeChild(e)}return n},void 0===(a="function"==typeof r?r.call(t,n,t,e):r)||(e.exports=a)},7418:e=>{"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(a){return!1}}()?Object.assign:function(e,a){for(var o,i,l=function(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}(e),s=1;s<arguments.length;s++){for(var u in o=Object(arguments[s]))n.call(o,u)&&(l[u]=o[u]);if(t){i=t(o);for(var c=0;c<i.length;c++)r.call(o,i[c])&&(l[i[c]]=o[i[c]])}}return l}},4779:(e,t,n)=>{var r=n(5826);e.exports=p,e.exports.parse=o,e.exports.compile=function(e,t){return l(o(e,t),t)},e.exports.tokensToFunction=l,e.exports.tokensToRegExp=f;var a=new RegExp(["(\\\\.)","([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))"].join("|"),"g");function o(e,t){for(var n,r=[],o=0,i=0,l="",c=t&&t.delimiter||"/";null!=(n=a.exec(e));){var d=n[0],f=n[1],p=n.index;if(l+=e.slice(i,p),i=p+d.length,f)l+=f[1];else{var m=e[i],h=n[2],g=n[3],b=n[4],v=n[5],y=n[6],E=n[7];l&&(r.push(l),l="");var S=null!=h&&null!=m&&m!==h,_="+"===y||"*"===y,w="?"===y||"*"===y,T=n[2]||c,k=b||v;r.push({name:g||o++,prefix:h||"",delimiter:T,optional:w,repeat:_,partial:S,asterisk:!!E,pattern:k?u(k):E?".*":"[^"+s(T)+"]+?"})}}return i<e.length&&(l+=e.substr(i)),l&&r.push(l),r}function i(e){return encodeURI(e).replace(/[\/?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))}function l(e,t){for(var n=new Array(e.length),a=0;a<e.length;a++)"object"==typeof e[a]&&(n[a]=new RegExp("^(?:"+e[a].pattern+")$",d(t)));return function(t,a){for(var o="",l=t||{},s=(a||{}).pretty?i:encodeURIComponent,u=0;u<e.length;u++){var c=e[u];if("string"!=typeof c){var d,f=l[c.name];if(null==f){if(c.optional){c.partial&&(o+=c.prefix);continue}throw new TypeError('Expected "'+c.name+'" to be defined')}if(r(f)){if(!c.repeat)throw new TypeError('Expected "'+c.name+'" to not repeat, but received `'+JSON.stringify(f)+"`");if(0===f.length){if(c.optional)continue;throw new TypeError('Expected "'+c.name+'" to not be empty')}for(var p=0;p<f.length;p++){if(d=s(f[p]),!n[u].test(d))throw new TypeError('Expected all "'+c.name+'" to match "'+c.pattern+'", but received `'+JSON.stringify(d)+"`");o+=(0===p?c.prefix:c.delimiter)+d}}else{if(d=c.asterisk?encodeURI(f).replace(/[?#]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()})):s(f),!n[u].test(d))throw new TypeError('Expected "'+c.name+'" to match "'+c.pattern+'", but received "'+d+'"');o+=c.prefix+d}}else o+=c}return o}}function s(e){return e.replace(/([.+*?=^!:${}()[\]|\/\\])/g,"\\$1")}function u(e){return e.replace(/([=!:$\/()])/g,"\\$1")}function c(e,t){return e.keys=t,e}function d(e){return e&&e.sensitive?"":"i"}function f(e,t,n){r(t)||(n=t||n,t=[]);for(var a=(n=n||{}).strict,o=!1!==n.end,i="",l=0;l<e.length;l++){var u=e[l];if("string"==typeof u)i+=s(u);else{var f=s(u.prefix),p="(?:"+u.pattern+")";t.push(u),u.repeat&&(p+="(?:"+f+p+")*"),i+=p=u.optional?u.partial?f+"("+p+")?":"(?:"+f+"("+p+"))?":f+"("+p+")"}}var m=s(n.delimiter||"/"),h=i.slice(-m.length)===m;return a||(i=(h?i.slice(0,-m.length):i)+"(?:"+m+"(?=$))?"),i+=o?"$":a&&h?"":"(?="+m+"|$)",c(new RegExp("^"+i,d(n)),t)}function p(e,t,n){return r(t)||(n=t||n,t=[]),n=n||{},e instanceof RegExp?function(e,t){var n=e.source.match(/\((?!\?)/g);if(n)for(var r=0;r<n.length;r++)t.push({name:r,prefix:null,delimiter:null,optional:!1,repeat:!1,partial:!1,asterisk:!1,pattern:null});return c(e,t)}(e,t):r(e)?function(e,t,n){for(var r=[],a=0;a<e.length;a++)r.push(p(e[a],t,n).source);return c(new RegExp("(?:"+r.join("|")+")",d(n)),t)}(e,t,n):function(e,t,n){return f(o(e,n),t,n)}(e,t,n)}},7410:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=function(){var e=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,n={},r={util:{encode:function e(t){return t instanceof a?new a(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&").replace(/</g,"<").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++t}),e.__id},clone:function e(t,n){var a,o;switch(n=n||{},r.util.type(t)){case"Object":if(o=r.util.objId(t),n[o])return n[o];for(var i in a={},n[o]=a,t)t.hasOwnProperty(i)&&(a[i]=e(t[i],n));return a;case"Array":return o=r.util.objId(t),n[o]?n[o]:(a=[],n[o]=a,t.forEach((function(t,r){a[r]=e(t,n)})),a);default:return t}},getLanguage:function(t){for(;t;){var n=e.exec(t.className);if(n)return n[1].toLowerCase();t=t.parentElement}return"none"},setLanguage:function(t,n){t.className=t.className.replace(RegExp(e,"gi"),""),t.classList.add("language-"+n)},isActive:function(e,t,n){for(var r="no-"+t;e;){var a=e.classList;if(a.contains(t))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!n}},languages:{plain:n,plaintext:n,text:n,txt:n,extend:function(e,t){var n=r.util.clone(r.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var o=(a=a||r.languages)[e],i={};for(var l in o)if(o.hasOwnProperty(l)){if(l==t)for(var s in n)n.hasOwnProperty(s)&&(i[s]=n[s]);n.hasOwnProperty(l)||(i[l]=o[l])}var u=a[e];return a[e]=i,r.languages.DFS(r.languages,(function(t,n){n===u&&t!=e&&(this[t]=i)})),i},DFS:function e(t,n,a,o){o=o||{};var i=r.util.objId;for(var l in t)if(t.hasOwnProperty(l)){n.call(t,l,t[l],a||l);var s=t[l],u=r.util.type(s);"Object"!==u||o[i(s)]?"Array"!==u||o[i(s)]||(o[i(s)]=!0,e(s,n,l,o)):(o[i(s)]=!0,e(s,n,null,o))}}},plugins:{},highlight:function(e,t,n){var o={code:e,grammar:t,language:n};return r.hooks.run("before-tokenize",o),o.tokens=r.tokenize(o.code,o.grammar),r.hooks.run("after-tokenize",o),a.stringify(r.util.encode(o.tokens),o.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var r in n)t[r]=n[r];delete t.rest}var a=new l;return s(a,a.head,e),i(e,a,t,a.head,0),function(e){var t=[],n=e.head.next;for(;n!==e.tail;)t.push(n.value),n=n.next;return t}(a)},hooks:{all:{},add:function(e,t){var n=r.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=r.hooks.all[e];if(n&&n.length)for(var a,o=0;a=n[o++];)a(t)}},Token:a};function a(e,t,n,r){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length}function o(e,t,n,r){e.lastIndex=t;var a=e.exec(n);if(a&&r&&a[1]){var o=a[1].length;a.index+=o,a[0]=a[0].slice(o)}return a}function i(e,t,n,l,c,d){for(var f in n)if(n.hasOwnProperty(f)&&n[f]){var p=n[f];p=Array.isArray(p)?p:[p];for(var m=0;m<p.length;++m){if(d&&d.cause==f+","+m)return;var h=p[m],g=h.inside,b=!!h.lookbehind,v=!!h.greedy,y=h.alias;if(v&&!h.pattern.global){var E=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,E+"g")}for(var S=h.pattern||h,_=l.next,w=c;_!==t.tail&&!(d&&w>=d.reach);w+=_.value.length,_=_.next){var T=_.value;if(t.length>e.length)return;if(!(T instanceof a)){var k,C=1;if(v){if(!(k=o(S,w,e,b))||k.index>=e.length)break;var A=k.index,I=k.index+k[0].length,O=w;for(O+=_.value.length;A>=O;)O+=(_=_.next).value.length;if(w=O-=_.value.length,_.value instanceof a)continue;for(var R=_;R!==t.tail&&(O<I||"string"==typeof R.value);R=R.next)C++,O+=R.value.length;C--,T=e.slice(w,O),k.index-=w}else if(!(k=o(S,0,T,b)))continue;A=k.index;var N=k[0],L=T.slice(0,A),P=T.slice(A+N.length),x=w+T.length;d&&x>d.reach&&(d.reach=x);var D=_.prev;if(L&&(D=s(t,D,L),w+=L.length),u(t,D,C),_=s(t,D,new a(f,g?r.tokenize(N,g):N,y,N)),P&&s(t,_,P),C>1){var M={cause:f+","+m,reach:x};i(e,t,n,_.prev,w,M),d&&M.reach>d.reach&&(d.reach=M.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function s(e,t,n){var r=t.next,a={value:n,prev:t,next:r};return t.next=a,r.prev=a,e.length++,a}function u(e,t,n){for(var r=t.next,a=0;a<n&&r!==e.tail;a++)r=r.next;t.next=r,r.prev=t,e.length-=a}return a.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var o={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},i=t.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(o.classes,i):o.classes.push(i)),r.hooks.run("wrap",o);var l="";for(var s in o.attributes)l+=" "+s+'="'+(o.attributes[s]||"").replace(/"/g,""")+'"';return"<"+o.tag+' class="'+o.classes.join(" ")+'"'+l+">"+o.content+"</"+o.tag+">"},r}(),a=r;r.default=r,a.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},a.languages.markup.tag.inside["attr-value"].inside.entity=a.languages.markup.entity,a.languages.markup.doctype.inside["internal-subset"].inside=a.languages.markup,a.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))})),Object.defineProperty(a.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:a.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var r={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};r["language-"+t]={pattern:/[\s\S]+/,inside:a.languages[t]};var o={};o[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:r},a.languages.insertBefore("markup","cdata",o)}}),Object.defineProperty(a.languages.markup.tag,"addAttribute",{value:function(e,t){a.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:a.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),a.languages.html=a.languages.markup,a.languages.mathml=a.languages.markup,a.languages.svg=a.languages.markup,a.languages.xml=a.languages.extend("markup",{}),a.languages.ssml=a.languages.xml,a.languages.atom=a.languages.xml,a.languages.rss=a.languages.xml,function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",n={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},r={bash:n,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:r},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:n}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:r},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:r.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:r.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},n.inside=e.languages.bash;for(var a=["comment","function-name","for-or-select","assign-left","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=r.variable[1].inside,i=0;i<a.length;i++)o[a[i]]=e.languages.bash[a[i]];e.languages.shell=e.languages.bash}(a),a.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},a.languages.c=a.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),a.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),a.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},a.languages.c.string],char:a.languages.c.char,comment:a.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:a.languages.c}}}}),a.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete a.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(a),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(a),function(e){var t,n=/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;e.languages.css.selector={pattern:e.languages.css.selector.pattern,lookbehind:!0,inside:t={"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+/,class:/\.[-\w]+/,id:/#[-\w]+/,attribute:{pattern:RegExp("\\[(?:[^[\\]\"']|"+n.source+")*\\]"),greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)(?:(?!\s)[-*\w\xA0-\uFFFF])*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},"attr-name":{pattern:/^(\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+/,lookbehind:!0},"attr-value":[n,{pattern:/(=\s*)(?:(?!\s)[-\w\xA0-\uFFFF])+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}},"n-th":[{pattern:/(\(\s*)[+-]?\d*[\dn](?:\s*[+-]\s*\d+)?(?=\s*\))/,lookbehind:!0,inside:{number:/[\dn]+/,operator:/[+-]/}},{pattern:/(\(\s*)(?:even|odd)(?=\s*\))/i,lookbehind:!0}],combinator:/>|\+|~|\|\|/,punctuation:/[(),]/}},e.languages.css.atrule.inside["selector-function-argument"].inside=t,e.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*/i,lookbehind:!0}});var r={pattern:/(\b\d+)(?:%|[a-z]+(?![\w-]))/,lookbehind:!0},a={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0};e.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:{pattern:/\B#[\da-f]{3,8}\b/i,alias:"color"},color:[{pattern:/(^|[^\w-])(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)(?![\w-])/i,lookbehind:!0},{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:r,number:a,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:r,number:a})}(a),a.languages.javascript=a.languages.extend("clike",{"class-name":[a.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),a.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,a.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:a.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:a.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:a.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:a.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:a.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),a.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:a.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),a.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),a.languages.markup&&(a.languages.markup.tag.addInlined("script","javascript"),a.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),a.languages.js=a.languages.javascript,function(e){var t=/#(?!\{).+/,n={pattern:/#\{[^}]+\}/,alias:"variable"};e.languages.coffeescript=e.languages.extend("javascript",{comment:t,string:[{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,inside:{interpolation:n}}],keyword:/\b(?:and|break|by|catch|class|continue|debugger|delete|do|each|else|extend|extends|false|finally|for|if|in|instanceof|is|isnt|let|loop|namespace|new|no|not|null|of|off|on|or|own|return|super|switch|then|this|throw|true|try|typeof|undefined|unless|until|when|while|window|with|yes|yield)\b/,"class-member":{pattern:/@(?!\d)\w+/,alias:"variable"}}),e.languages.insertBefore("coffeescript","comment",{"multiline-comment":{pattern:/###[\s\S]+?###/,alias:"comment"},"block-regex":{pattern:/\/{3}[\s\S]*?\/{3}/,alias:"regex",inside:{comment:t,interpolation:n}}}),e.languages.insertBefore("coffeescript","string",{"inline-javascript":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,inside:{delimiter:{pattern:/^`|`$/,alias:"punctuation"},script:{pattern:/[\s\S]+/,alias:"language-javascript",inside:e.languages.javascript}}},"multiline-string":[{pattern:/'''[\s\S]*?'''/,greedy:!0,alias:"string"},{pattern:/"""[\s\S]*?"""/,greedy:!0,alias:"string",inside:{interpolation:n}}]}),e.languages.insertBefore("coffeescript","keyword",{property:/(?!\d)\w+(?=\s*:(?!:))/}),delete e.languages.coffeescript["template-string"],e.languages.coffee=e.languages.coffeescript}(a),function(e){var t=/[*&][^\s[\]{},]+/,n=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,r="(?:"+n.source+"(?:[ \t]+"+t.source+")?|"+t.source+"(?:[ \t]+"+n.source+")?)",a=/(?:[^\s\x00-\x08\x0e-\x1f!"#%&'*,\-:>?@[\]`{|}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]|[?:-]<PLAIN>)(?:[ \t]*(?:(?![#:])<PLAIN>|:<PLAIN>))*/.source.replace(/<PLAIN>/g,(function(){return/[^\s\x00-\x08\x0e-\x1f,[\]{}\x7f-\x84\x86-\x9f\ud800-\udfff\ufffe\uffff]/.source})),o=/"(?:[^"\\\r\n]|\\.)*"|'(?:[^'\\\r\n]|\\.)*'/.source;function i(e,t){t=(t||"").replace(/m/g,"")+"m";var n=/([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<value>>/g,(function(){return e}));return RegExp(n,t)}e.languages.yaml={scalar:{pattern:RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source.replace(/<<prop>>/g,(function(){return r}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp(/((?:^|[:\-,[{\r\n?])[ \t]*(?:<<prop>>[ \t]+)?)<<key>>(?=\s*:\s)/.source.replace(/<<prop>>/g,(function(){return r})).replace(/<<key>>/g,(function(){return"(?:"+a+"|"+o+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:i(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),lookbehind:!0,alias:"number"},boolean:{pattern:i(/false|true/.source,"i"),lookbehind:!0,alias:"important"},null:{pattern:i(/null|~/.source,"i"),lookbehind:!0,alias:"important"},string:{pattern:i(o),lookbehind:!0,greedy:!0},number:{pattern:i(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source,"i"),lookbehind:!0},tag:n,important:t,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(a),function(e){var t=/(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source;function n(e){return e=e.replace(/<inner>/g,(function(){return t})),RegExp(/((?:^|[^\\])(?:\\{2})*)/.source+"(?:"+e+")")}var r=/(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source,a=/\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g,(function(){return r})),o=/\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source;e.languages.markdown=e.languages.extend("markup",{}),e.languages.insertBefore("markdown","prolog",{"front-matter-block":{pattern:/(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/,lookbehind:!0,greedy:!0,inside:{punctuation:/^---|---$/,"front-matter":{pattern:/\S+(?:\s+\S+)*/,alias:["yaml","language-yaml"],inside:e.languages.yaml}}},blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},table:{pattern:RegExp("^"+a+o+"(?:"+a+")*","m"),inside:{"table-data-rows":{pattern:RegExp("^("+a+o+")(?:"+a+")*$"),lookbehind:!0,inside:{"table-data":{pattern:RegExp(r),inside:e.languages.markdown},punctuation:/\|/}},"table-line":{pattern:RegExp("^("+a+")"+o+"$"),lookbehind:!0,inside:{punctuation:/\||:?-{3,}:?/}},"table-header-row":{pattern:RegExp("^"+a+"$"),inside:{"table-header":{pattern:RegExp(r),alias:"important",inside:e.languages.markdown},punctuation:/\|/}}}},code:[{pattern:/((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/,lookbehind:!0,alias:"keyword"},{pattern:/^```[\s\S]*?^```$/m,greedy:!0,inside:{"code-block":{pattern:/^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m,lookbehind:!0},"code-language":{pattern:/^(```).+/,lookbehind:!0},punctuation:/```/}}],title:[{pattern:/\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:n(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^..)[\s\S]+(?=..$)/,lookbehind:!0,inside:{}},punctuation:/\*\*|__/}},italic:{pattern:n(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^.)[\s\S]+(?=.$)/,lookbehind:!0,inside:{}},punctuation:/[*_]/}},strike:{pattern:n(/(~~?)(?:(?!~)<inner>)+\2/.source),lookbehind:!0,greedy:!0,inside:{content:{pattern:/(^~~?)[\s\S]+(?=\1$)/,lookbehind:!0,inside:{}},punctuation:/~~?/}},"code-snippet":{pattern:/(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/,lookbehind:!0,greedy:!0,alias:["code","keyword"]},url:{pattern:n(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source),lookbehind:!0,greedy:!0,inside:{operator:/^!/,content:{pattern:/(^\[)[^\]]+(?=\])/,lookbehind:!0,inside:{}},variable:{pattern:/(^\][ \t]?\[)[^\]]+(?=\]$)/,lookbehind:!0},url:{pattern:/(^\]\()[^\s)]+/,lookbehind:!0},string:{pattern:/(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/,lookbehind:!0}}}}),["url","bold","italic","strike"].forEach((function(t){["url","bold","italic","strike","code-snippet"].forEach((function(n){t!==n&&(e.languages.markdown[t].inside.content.inside[n]=e.languages.markdown[n])}))})),e.hooks.add("after-tokenize",(function(e){"markdown"!==e.language&&"md"!==e.language||function e(t){if(t&&"string"!=typeof t)for(var n=0,r=t.length;n<r;n++){var a=t[n];if("code"===a.type){var o=a.content[1],i=a.content[3];if(o&&i&&"code-language"===o.type&&"code-block"===i.type&&"string"==typeof o.content){var l=o.content.replace(/\b#/g,"sharp").replace(/\b\+\+/g,"pp"),s="language-"+(l=(/[a-z][\w-]*/i.exec(l)||[""])[0].toLowerCase());i.alias?"string"==typeof i.alias?i.alias=[i.alias,s]:i.alias.push(s):i.alias=[s]}}else e(a.content)}}(e.tokens)})),e.hooks.add("wrap",(function(t){if("code-block"===t.type){for(var n="",r=0,a=t.classes.length;r<a;r++){var o=t.classes[r],u=/language-(.+)/.exec(o);if(u){n=u[1];break}}var c,d=e.languages[n];if(d)t.content=e.highlight((c=t.content,c.replace(i,"").replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi,(function(e,t){var n;if("#"===(t=t.toLowerCase())[0])return n="x"===t[1]?parseInt(t.slice(2),16):Number(t.slice(1)),s(n);var r=l[t];return r||e}))),d,n);else if(n&&"none"!==n&&e.plugins.autoloader){var f="md-"+(new Date).valueOf()+"-"+Math.floor(1e16*Math.random());t.attributes.id=f,e.plugins.autoloader.loadLanguages(n,(function(){var t=document.getElementById(f);t&&(t.innerHTML=e.highlight(t.textContent,e.languages[n],n))}))}}}));var i=RegExp(e.languages.markup.tag.pattern.source,"gi"),l={amp:"&",lt:"<",gt:">",quot:'"'},s=String.fromCodePoint||String.fromCharCode;e.languages.md=e.languages.markdown}(a),a.languages.graphql={comment:/#.*/,description:{pattern:/(?:"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*")(?=\s*[a-z_])/i,greedy:!0,alias:"string",inside:{"language-markdown":{pattern:/(^"(?:"")?)(?!\1)[\s\S]+(?=\1$)/,lookbehind:!0,inside:a.languages.markdown}}},string:{pattern:/"""(?:[^"]|(?!""")")*"""|"(?:\\.|[^\\"\r\n])*"/,greedy:!0},number:/(?:\B-|\b)\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,boolean:/\b(?:false|true)\b/,variable:/\$[a-z_]\w*/i,directive:{pattern:/@[a-z_]\w*/i,alias:"function"},"attr-name":{pattern:/\b[a-z_]\w*(?=\s*(?:\((?:[^()"]|"(?:\\.|[^\\"\r\n])*")*\))?:)/i,greedy:!0},"atom-input":{pattern:/\b[A-Z]\w*Input\b/,alias:"class-name"},scalar:/\b(?:Boolean|Float|ID|Int|String)\b/,constant:/\b[A-Z][A-Z_\d]*\b/,"class-name":{pattern:/(\b(?:enum|implements|interface|on|scalar|type|union)\s+|&\s*|:\s*|\[)[A-Z_]\w*/,lookbehind:!0},fragment:{pattern:/(\bfragment\s+|\.{3}\s*(?!on\b))[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-mutation":{pattern:/(\bmutation\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},"definition-query":{pattern:/(\bquery\s+)[a-zA-Z_]\w*/,lookbehind:!0,alias:"function"},keyword:/\b(?:directive|enum|extend|fragment|implements|input|interface|mutation|on|query|repeatable|scalar|schema|subscription|type|union)\b/,operator:/[!=|&]|\.{3}/,"property-query":/\w+(?=\s*\()/,object:/\w+(?=\s*\{)/,punctuation:/[!(){}\[\]:=,]/,property:/\w+/},a.hooks.add("after-tokenize",(function(e){if("graphql"===e.language)for(var t=e.tokens.filter((function(e){return"string"!=typeof e&&"comment"!==e.type&&"scalar"!==e.type})),n=0;n<t.length;){var r=t[n++];if("keyword"===r.type&&"mutation"===r.content){var a=[];if(d(["definition-mutation","punctuation"])&&"("===c(1).content){n+=2;var o=f(/^\($/,/^\)$/);if(-1===o)continue;for(;n<o;n++){var i=c(0);"variable"===i.type&&(p(i,"variable-input"),a.push(i.content))}n=o+1}if(d(["punctuation","property-query"])&&"{"===c(0).content&&(n++,p(c(0),"property-mutation"),a.length>0)){var l=f(/^\{$/,/^\}$/);if(-1===l)continue;for(var s=n;s<l;s++){var u=t[s];"variable"===u.type&&a.indexOf(u.content)>=0&&p(u,"variable-input")}}}}function c(e){return t[n+e]}function d(e,t){t=t||0;for(var n=0;n<e.length;n++){var r=c(n+t);if(!r||r.type!==e[n])return!1}return!0}function f(e,r){for(var a=1,o=n;o<t.length;o++){var i=t[o],l=i.content;if("punctuation"===i.type&&"string"==typeof l)if(e.test(l))a++;else if(r.test(l)&&0===--a)return o}return-1}function p(e,t){var n=e.alias;n?Array.isArray(n)||(e.alias=n=[n]):e.alias=n=[],n.push(t)}})),a.languages.sql={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/,lookbehind:!0},variable:[{pattern:/@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/,greedy:!0},/@[\w.$]+/],string:{pattern:/(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/,greedy:!0,lookbehind:!0},identifier:{pattern:/(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/,greedy:!0,lookbehind:!0,inside:{punctuation:/^`|`$/}},function:/\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i,keyword:/\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i,boolean:/\b(?:FALSE|NULL|TRUE)\b/i,number:/\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i,operator:/[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i,punctuation:/[;[\]()`,.]/},function(e){var t=e.languages.javascript["template-string"],n=t.pattern.source,r=t.inside.interpolation,a=r.inside["interpolation-punctuation"],o=r.pattern.source;function i(t,r){if(e.languages[t])return{pattern:RegExp("((?:"+r+")\\s*)"+n),lookbehind:!0,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},"embedded-code":{pattern:/[\s\S]+/,alias:t}}}}function l(e,t){return"___"+t.toUpperCase()+"_"+e+"___"}function s(t,n,r){var a={code:t,grammar:n,language:r};return e.hooks.run("before-tokenize",a),a.tokens=e.tokenize(a.code,a.grammar),e.hooks.run("after-tokenize",a),a.tokens}function u(t){var n={};n["interpolation-punctuation"]=a;var o=e.tokenize(t,n);if(3===o.length){var i=[1,1];i.push.apply(i,s(o[1],e.languages.javascript,"javascript")),o.splice.apply(o,i)}return new e.Token("interpolation",o,r.alias,t)}function c(t,n,r){var a=e.tokenize(t,{interpolation:{pattern:RegExp(o),lookbehind:!0}}),i=0,c={},d=s(a.map((function(e){if("string"==typeof e)return e;for(var n,a=e.content;-1!==t.indexOf(n=l(i++,r)););return c[n]=a,n})).join(""),n,r),f=Object.keys(c);return i=0,function e(t){for(var n=0;n<t.length;n++){if(i>=f.length)return;var r=t[n];if("string"==typeof r||"string"==typeof r.content){var a=f[i],o="string"==typeof r?r:r.content,l=o.indexOf(a);if(-1!==l){++i;var s=o.substring(0,l),d=u(c[a]),p=o.substring(l+a.length),m=[];if(s&&m.push(s),m.push(d),p){var h=[p];e(h),m.push.apply(m,h)}"string"==typeof r?(t.splice.apply(t,[n,1].concat(m)),n+=m.length-1):r.content=m}}else{var g=r.content;Array.isArray(g)?e(g):e([g])}}}(d),new e.Token(r,d,"language-"+r,t)}e.languages.javascript["template-string"]=[i("css",/\b(?:styled(?:\([^)]*\))?(?:\s*\.\s*\w+(?:\([^)]*\))*)*|css(?:\s*\.\s*(?:global|resolve))?|createGlobalStyle|keyframes)/.source),i("html",/\bhtml|\.\s*(?:inner|outer)HTML\s*\+?=/.source),i("svg",/\bsvg/.source),i("markdown",/\b(?:markdown|md)/.source),i("graphql",/\b(?:gql|graphql(?:\s*\.\s*experimental)?)/.source),i("sql",/\bsql/.source),t].filter(Boolean);var d={javascript:!0,js:!0,typescript:!0,ts:!0,jsx:!0,tsx:!0};function f(e){return"string"==typeof e?e:Array.isArray(e)?e.map(f).join(""):f(e.content)}e.hooks.add("after-tokenize",(function(t){t.language in d&&function t(n){for(var r=0,a=n.length;r<a;r++){var o=n[r];if("string"!=typeof o){var i=o.content;if(Array.isArray(i))if("template-string"===o.type){var l=i[1];if(3===i.length&&"string"!=typeof l&&"embedded-code"===l.type){var s=f(l),u=l.alias,d=Array.isArray(u)?u[0]:u,p=e.languages[d];if(!p)continue;i[1]=c(s,p,d)}}else t(i);else"string"!=typeof i&&t([i])}}}(t.tokens)}))}(a),function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var t=e.languages.extend("typescript",{});delete t["class-name"],e.languages.typescript["class-name"].inside=t,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:t}}}}),e.languages.ts=e.languages.typescript}(a),function(e){function t(e,t){return RegExp(e.replace(/<ID>/g,(function(){return/(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/.source})),t)}e.languages.insertBefore("javascript","function-variable",{"method-variable":{pattern:RegExp("(\\.\\s*)"+e.languages.javascript["function-variable"].pattern.source),lookbehind:!0,alias:["function-variable","method","function","property-access"]}}),e.languages.insertBefore("javascript","function",{method:{pattern:RegExp("(\\.\\s*)"+e.languages.javascript.function.source),lookbehind:!0,alias:["function","property-access"]}}),e.languages.insertBefore("javascript","constant",{"known-class-name":[{pattern:/\b(?:(?:Float(?:32|64)|(?:Int|Uint)(?:8|16|32)|Uint8Clamped)?Array|ArrayBuffer|BigInt|Boolean|DataView|Date|Error|Function|Intl|JSON|(?:Weak)?(?:Map|Set)|Math|Number|Object|Promise|Proxy|Reflect|RegExp|String|Symbol|WebAssembly)\b/,alias:"class-name"},{pattern:/\b(?:[A-Z]\w*)Error\b/,alias:"class-name"}]}),e.languages.insertBefore("javascript","keyword",{imports:{pattern:t(/(\bimport\b\s*)(?:<ID>(?:\s*,\s*(?:\*\s*as\s+<ID>|\{[^{}]*\}))?|\*\s*as\s+<ID>|\{[^{}]*\})(?=\s*\bfrom\b)/.source),lookbehind:!0,inside:e.languages.javascript},exports:{pattern:t(/(\bexport\b\s*)(?:\*(?:\s*as\s+<ID>)?(?=\s*\bfrom\b)|\{[^{}]*\})/.source),lookbehind:!0,inside:e.languages.javascript}}),e.languages.javascript.keyword.unshift({pattern:/\b(?:as|default|export|from|import)\b/,alias:"module"},{pattern:/\b(?:await|break|catch|continue|do|else|finally|for|if|return|switch|throw|try|while|yield)\b/,alias:"control-flow"},{pattern:/\bnull\b/,alias:["null","nil"]},{pattern:/\bundefined\b/,alias:"nil"}),e.languages.insertBefore("javascript","operator",{spread:{pattern:/\.{3}/,alias:"operator"},arrow:{pattern:/=>/,alias:"operator"}}),e.languages.insertBefore("javascript","punctuation",{"property-access":{pattern:t(/(\.\s*)#?<ID>/.source),lookbehind:!0},"maybe-class-name":{pattern:/(^|[^$\w\xA0-\uFFFF])[A-Z][$\w\xA0-\uFFFF]+/,lookbehind:!0},dom:{pattern:/\b(?:document|(?:local|session)Storage|location|navigator|performance|window)\b/,alias:"variable"},console:{pattern:/\bconsole(?=\s*\.)/,alias:"class-name"}});for(var n=["function","function-variable","method","method-variable","property-access"],r=0;r<n.length;r++){var a=n[r],o=e.languages.javascript[a];"RegExp"===e.util.type(o)&&(o=e.languages.javascript[a]={pattern:o});var i=o.inside||{};o.inside=i,i["maybe-class-name"]=/^[A-Z][\s\S]*/}}(a),function(e){var t=e.util.clone(e.languages.javascript),n=/(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source,r=/(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source,a=/(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;function o(e,t){return e=e.replace(/<S>/g,(function(){return n})).replace(/<BRACES>/g,(function(){return r})).replace(/<SPREAD>/g,(function(){return a})),RegExp(e,t)}a=o(a).source,e.languages.jsx=e.languages.extend("markup",t),e.languages.jsx.tag.pattern=o(/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source),e.languages.jsx.tag.inside.tag.pattern=/^<\/?[^\s>\/]*/,e.languages.jsx.tag.inside["attr-value"].pattern=/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/,e.languages.jsx.tag.inside.tag.inside["class-name"]=/^[A-Z]\w*(?:\.[A-Z]\w*)*$/,e.languages.jsx.tag.inside.comment=t.comment,e.languages.insertBefore("inside","attr-name",{spread:{pattern:o(/<SPREAD>/.source),inside:e.languages.jsx}},e.languages.jsx.tag),e.languages.insertBefore("inside","special-attr",{script:{pattern:o(/=<BRACES>/.source),alias:"language-javascript",inside:{"script-punctuation":{pattern:/^=(?=\{)/,alias:"punctuation"},rest:e.languages.jsx}}},e.languages.jsx.tag);var i=function(e){return e?"string"==typeof e?e:"string"==typeof e.content?e.content:e.content.map(i).join(""):""},l=function(t){for(var n=[],r=0;r<t.length;r++){var a=t[r],o=!1;if("string"!=typeof a&&("tag"===a.type&&a.content[0]&&"tag"===a.content[0].type?"</"===a.content[0].content[0].content?n.length>0&&n[n.length-1].tagName===i(a.content[0].content[1])&&n.pop():"/>"===a.content[a.content.length-1].content||n.push({tagName:i(a.content[0].content[1]),openedBraces:0}):n.length>0&&"punctuation"===a.type&&"{"===a.content?n[n.length-1].openedBraces++:n.length>0&&n[n.length-1].openedBraces>0&&"punctuation"===a.type&&"}"===a.content?n[n.length-1].openedBraces--:o=!0),(o||"string"==typeof a)&&n.length>0&&0===n[n.length-1].openedBraces){var s=i(a);r<t.length-1&&("string"==typeof t[r+1]||"plain-text"===t[r+1].type)&&(s+=i(t[r+1]),t.splice(r+1,1)),r>0&&("string"==typeof t[r-1]||"plain-text"===t[r-1].type)&&(s=i(t[r-1])+s,t.splice(r-1,1),r--),t[r]=new e.Token("plain-text",s,null,s)}a.content&&"string"!=typeof a.content&&l(a.content)}};e.hooks.add("after-tokenize",(function(e){"jsx"!==e.language&&"tsx"!==e.language||l(e.tokens)}))}(a),function(e){e.languages.diff={coord:[/^(?:\*{3}|-{3}|\+{3}).*$/m,/^@@.*@@$/m,/^\d.*$/m]};var t={"deleted-sign":"-","deleted-arrow":"<","inserted-sign":"+","inserted-arrow":">",unchanged:" ",diff:"!"};Object.keys(t).forEach((function(n){var r=t[n],a=[];/^\w+$/.test(n)||a.push(/\w+/.exec(n)[0]),"diff"===n&&a.push("bold"),e.languages.diff[n]={pattern:RegExp("^(?:["+r+"].*(?:\r\n?|\n|(?![\\s\\S])))+","m"),alias:a,inside:{line:{pattern:/(.)(?=[\s\S]).*(?:\r\n?|\n)?/,lookbehind:!0},prefix:{pattern:/[\s\S]/,alias:/\w+/.exec(n)[0]}}}})),Object.defineProperty(e.languages.diff,"PREFIXES",{value:t})}(a),a.languages.git={comment:/^#.*/m,deleted:/^[-\u2013].*/m,inserted:/^\+.*/m,string:/("|')(?:\\.|(?!\1)[^\\\r\n])*\1/,command:{pattern:/^.*\$ git .*$/m,inside:{parameter:/\s--?\w+/}},coord:/^@@.*@@$/m,"commit-sha1":/^commit \w{40}$/m},a.languages.go=a.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/,lookbehind:!0,greedy:!0},keyword:/\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/,boolean:/\b(?:_|false|iota|nil|true)\b/,number:[/\b0(?:b[01_]+|o[0-7_]+)i?\b/i,/\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i,/(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i],operator:/[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./,builtin:/\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/}),a.languages.insertBefore("go","string",{char:{pattern:/'(?:\\.|[^'\\\r\n]){0,10}'/,greedy:!0}}),delete a.languages.go["class-name"],function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,r,a,o){if(n.language===r){var i=n.tokenStack=[];n.code=n.code.replace(a,(function(e){if("function"==typeof o&&!o(e))return e;for(var a,l=i.length;-1!==n.code.indexOf(a=t(r,l));)++l;return i[l]=e,a})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,r){if(n.language===r&&n.tokenStack){n.grammar=e.languages[r];var a=0,o=Object.keys(n.tokenStack);!function i(l){for(var s=0;s<l.length&&!(a>=o.length);s++){var u=l[s];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=o[a],d=n.tokenStack[c],f="string"==typeof u?u:u.content,p=t(r,c),m=f.indexOf(p);if(m>-1){++a;var h=f.substring(0,m),g=new e.Token(r,e.tokenize(d,n.grammar),"language-"+r,d),b=f.substring(m+p.length),v=[];h&&v.push.apply(v,i([h])),v.push(g),b&&v.push.apply(v,i([b])),"string"==typeof u?l.splice.apply(l,[s,1].concat(v)):u.content=v}}else u.content&&i(u.content)}return l}(n.tokens)}}}})}(a),function(e){e.languages.handlebars={comment:/\{\{![\s\S]*?\}\}/,delimiter:{pattern:/^\{\{\{?|\}\}\}?$/,alias:"punctuation"},string:/(["'])(?:\\.|(?!\1)[^\\\r\n])*\1/,number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee][+-]?\d+)?/,boolean:/\b(?:false|true)\b/,block:{pattern:/^(\s*(?:~\s*)?)[#\/]\S+?(?=\s*(?:~\s*)?$|\s)/,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\s\S]+/}},punctuation:/[!"#%&':()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,\/;<=>@\[\\\]^`{|}~\s]+/},e.hooks.add("before-tokenize",(function(t){e.languages["markup-templating"].buildPlaceholders(t,"handlebars",/\{\{\{[\s\S]+?\}\}\}|\{\{[\s\S]+?\}\}/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"handlebars")})),e.languages.hbs=e.languages.handlebars}(a),a.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}},a.languages.webmanifest=a.languages.json,a.languages.less=a.languages.extend("css",{comment:[/\/\*[\s\S]*?\*\//,{pattern:/(^|[^\\])\/\/.*/,lookbehind:!0}],atrule:{pattern:/@[\w-](?:\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{punctuation:/[:()]/}},selector:{pattern:/(?:@\{[\w-]+\}|[^{};\s@])(?:@\{[\w-]+\}|\((?:[^(){}]|\([^(){}]*\))*\)|[^(){};@\s]|\s+(?!\s))*?(?=\s*\{)/,inside:{variable:/@+[\w-]+/}},property:/(?:@\{[\w-]+\}|[\w-])+(?:\+_?)?(?=\s*:)/,operator:/[+\-*\/]/}),a.languages.insertBefore("less","property",{variable:[{pattern:/@[\w-]+\s*:/,inside:{punctuation:/:/}},/@@?[\w-]+/],"mixin-usage":{pattern:/([{;]\s*)[.#](?!\d)[\w-].*?(?=[(;])/,lookbehind:!0,alias:"function"}}),a.languages.makefile={comment:{pattern:/(^|[^\\])#(?:\\(?:\r\n|[\s\S])|[^\\\r\n])*/,lookbehind:!0},string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"builtin-target":{pattern:/\.[A-Z][^:#=\s]+(?=\s*:(?!=))/,alias:"builtin"},target:{pattern:/^(?:[^:=\s]|[ \t]+(?![\s:]))+(?=\s*:(?!=))/m,alias:"symbol",inside:{variable:/\$+(?:(?!\$)[^(){}:#=\s]+|(?=[({]))/}},variable:/\$+(?:(?!\$)[^(){}:#=\s]+|\([@*%<^+?][DF]\)|(?=[({]))/,keyword:/-include\b|\b(?:define|else|endef|endif|export|ifn?def|ifn?eq|include|override|private|sinclude|undefine|unexport|vpath)\b/,function:{pattern:/(\()(?:abspath|addsuffix|and|basename|call|dir|error|eval|file|filter(?:-out)?|findstring|firstword|flavor|foreach|guile|if|info|join|lastword|load|notdir|or|origin|patsubst|realpath|shell|sort|strip|subst|suffix|value|warning|wildcard|word(?:list|s)?)(?=[ \t])/,lookbehind:!0},operator:/(?:::|[?:+!])?=|[|@]/,punctuation:/[:;(){}]/},a.languages.objectivec=a.languages.extend("c",{string:{pattern:/@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},keyword:/\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/,operator:/-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/}),delete a.languages.objectivec["class-name"],a.languages.objc=a.languages.objectivec,a.languages.ocaml={comment:{pattern:/\(\*[\s\S]*?\*\)/,greedy:!0},char:{pattern:/'(?:[^\\\r\n']|\\(?:.|[ox]?[0-9a-f]{1,3}))'/i,greedy:!0},string:[{pattern:/"(?:\\(?:[\s\S]|\r\n)|[^\\\r\n"])*"/,greedy:!0},{pattern:/\{([a-z_]*)\|[\s\S]*?\|\1\}/,greedy:!0}],number:[/\b(?:0b[01][01_]*|0o[0-7][0-7_]*)\b/i,/\b0x[a-f0-9][a-f0-9_]*(?:\.[a-f0-9_]*)?(?:p[+-]?\d[\d_]*)?(?!\w)/i,/\b\d[\d_]*(?:\.[\d_]*)?(?:e[+-]?\d[\d_]*)?(?!\w)/i],directive:{pattern:/\B#\w+/,alias:"property"},label:{pattern:/\B~\w+/,alias:"property"},"type-variable":{pattern:/\B'\w+/,alias:"function"},variant:{pattern:/`\w+/,alias:"symbol"},keyword:/\b(?:as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|nonrec|object|of|open|private|rec|sig|struct|then|to|try|type|val|value|virtual|when|where|while|with)\b/,boolean:/\b(?:false|true)\b/,"operator-like-punctuation":{pattern:/\[[<>|]|[>|]\]|\{<|>\}/,alias:"punctuation"},operator:/\.[.~]|:[=>]|[=<>@^|&+\-*\/$%!?~][!$%&*+\-.\/:<=>?@^|~]*|\b(?:and|asr|land|lor|lsl|lsr|lxor|mod|or)\b/,punctuation:/;;|::|[(){}\[\].,:;#]|\b_\b/},a.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},a.languages.python["string-interpolation"].inside.interpolation.inside.rest=a.languages.python,a.languages.py=a.languages.python,a.languages.reason=a.languages.extend("clike",{string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^\\\r\n"])*"/,greedy:!0},"class-name":/\b[A-Z]\w*/,keyword:/\b(?:and|as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|method|module|mutable|new|nonrec|object|of|open|or|private|rec|sig|struct|switch|then|to|try|type|val|virtual|when|while|with)\b/,operator:/\.{3}|:[:=]|\|>|->|=(?:==?|>)?|<=?|>=?|[|^?'#!~`]|[+\-*\/]\.?|\b(?:asr|land|lor|lsl|lsr|lxor|mod)\b/}),a.languages.insertBefore("reason","class-name",{char:{pattern:/'(?:\\x[\da-f]{2}|\\o[0-3][0-7][0-7]|\\\d{3}|\\.|[^'\\\r\n])'/,greedy:!0},constructor:/\b[A-Z]\w*\b(?!\s*\.)/,label:{pattern:/\b[a-z]\w*(?=::)/,alias:"symbol"}}),delete a.languages.reason.function,function(e){e.languages.sass=e.languages.extend("css",{comment:{pattern:/^([ \t]*)\/[\/*].*(?:(?:\r?\n|\r)\1[ \t].+)*/m,lookbehind:!0,greedy:!0}}),e.languages.insertBefore("sass","atrule",{"atrule-line":{pattern:/^(?:[ \t]*)[@+=].+/m,greedy:!0,inside:{atrule:/(?:@[\w-]+|[+=])/}}}),delete e.languages.sass.atrule;var t=/\$[-\w]+|#\{\$[-\w]+\}/,n=[/[+*\/%]|[=!]=|<=?|>=?|\b(?:and|not|or)\b/,{pattern:/(\s)-(?=\s)/,lookbehind:!0}];e.languages.insertBefore("sass","property",{"variable-line":{pattern:/^[ \t]*\$.+/m,greedy:!0,inside:{punctuation:/:/,variable:t,operator:n}},"property-line":{pattern:/^[ \t]*(?:[^:\s]+ *:.*|:[^:\s].*)/m,greedy:!0,inside:{property:[/[^:\s]+(?=\s*:)/,{pattern:/(:)[^:\s]+/,lookbehind:!0}],punctuation:/:/,variable:t,operator:n,important:e.languages.sass.important}}}),delete e.languages.sass.property,delete e.languages.sass.important,e.languages.insertBefore("sass","punctuation",{selector:{pattern:/^([ \t]*)\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*(?:,(?:\r?\n|\r)\1[ \t]+\S(?:,[^,\r\n]+|[^,\r\n]*)(?:,[^,\r\n]+)*)*/m,lookbehind:!0,greedy:!0}})}(a),a.languages.scss=a.languages.extend("css",{comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},atrule:{pattern:/@[\w-](?:\([^()]+\)|[^()\s]|\s+(?!\s))*?(?=\s+[{;])/,inside:{rule:/@[\w-]+/}},url:/(?:[-a-z]+-)?url(?=\()/i,selector:{pattern:/(?=\S)[^@;{}()]?(?:[^@;{}()\s]|\s+(?!\s)|#\{\$[-\w]+\})+(?=\s*\{(?:\}|\s|[^}][^:{}]*[:{][^}]))/,inside:{parent:{pattern:/&/,alias:"important"},placeholder:/%[-\w]+/,variable:/\$[-\w]+|#\{\$[-\w]+\}/}},property:{pattern:/(?:[-\w]|\$[-\w]|#\{\$[-\w]+\})+(?=\s*:)/,inside:{variable:/\$[-\w]+|#\{\$[-\w]+\}/}}}),a.languages.insertBefore("scss","atrule",{keyword:[/@(?:content|debug|each|else(?: if)?|extend|for|forward|function|if|import|include|mixin|return|use|warn|while)\b/i,{pattern:/( )(?:from|through)(?= )/,lookbehind:!0}]}),a.languages.insertBefore("scss","important",{variable:/\$[-\w]+|#\{\$[-\w]+\}/}),a.languages.insertBefore("scss","function",{"module-modifier":{pattern:/\b(?:as|hide|show|with)\b/i,alias:"keyword"},placeholder:{pattern:/%[-\w]+/,alias:"selector"},statement:{pattern:/\B!(?:default|optional)\b/i,alias:"keyword"},boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"},operator:{pattern:/(\s)(?:[-+*\/%]|[=!]=|<=?|>=?|and|not|or)(?=\s)/,lookbehind:!0}}),a.languages.scss.atrule.inside.rest=a.languages.scss,function(e){var t={pattern:/(\b\d+)(?:%|[a-z]+)/,lookbehind:!0},n={pattern:/(^|[^\w.-])-?(?:\d+(?:\.\d+)?|\.\d+)/,lookbehind:!0},r={comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0},url:{pattern:/\burl\((["']?).*?\1\)/i,greedy:!0},string:{pattern:/("|')(?:(?!\1)[^\\\r\n]|\\(?:\r\n|[\s\S]))*\1/,greedy:!0},interpolation:null,func:null,important:/\B!(?:important|optional)\b/i,keyword:{pattern:/(^|\s+)(?:(?:else|for|if|return|unless)(?=\s|$)|@[\w-]+)/,lookbehind:!0},hexcode:/#[\da-f]{3,6}/i,color:[/\b(?:AliceBlue|AntiqueWhite|Aqua|Aquamarine|Azure|Beige|Bisque|Black|BlanchedAlmond|Blue|BlueViolet|Brown|BurlyWood|CadetBlue|Chartreuse|Chocolate|Coral|CornflowerBlue|Cornsilk|Crimson|Cyan|DarkBlue|DarkCyan|DarkGoldenRod|DarkGr[ae]y|DarkGreen|DarkKhaki|DarkMagenta|DarkOliveGreen|DarkOrange|DarkOrchid|DarkRed|DarkSalmon|DarkSeaGreen|DarkSlateBlue|DarkSlateGr[ae]y|DarkTurquoise|DarkViolet|DeepPink|DeepSkyBlue|DimGr[ae]y|DodgerBlue|FireBrick|FloralWhite|ForestGreen|Fuchsia|Gainsboro|GhostWhite|Gold|GoldenRod|Gr[ae]y|Green|GreenYellow|HoneyDew|HotPink|IndianRed|Indigo|Ivory|Khaki|Lavender|LavenderBlush|LawnGreen|LemonChiffon|LightBlue|LightCoral|LightCyan|LightGoldenRodYellow|LightGr[ae]y|LightGreen|LightPink|LightSalmon|LightSeaGreen|LightSkyBlue|LightSlateGr[ae]y|LightSteelBlue|LightYellow|Lime|LimeGreen|Linen|Magenta|Maroon|MediumAquaMarine|MediumBlue|MediumOrchid|MediumPurple|MediumSeaGreen|MediumSlateBlue|MediumSpringGreen|MediumTurquoise|MediumVioletRed|MidnightBlue|MintCream|MistyRose|Moccasin|NavajoWhite|Navy|OldLace|Olive|OliveDrab|Orange|OrangeRed|Orchid|PaleGoldenRod|PaleGreen|PaleTurquoise|PaleVioletRed|PapayaWhip|PeachPuff|Peru|Pink|Plum|PowderBlue|Purple|Red|RosyBrown|RoyalBlue|SaddleBrown|Salmon|SandyBrown|SeaGreen|SeaShell|Sienna|Silver|SkyBlue|SlateBlue|SlateGr[ae]y|Snow|SpringGreen|SteelBlue|Tan|Teal|Thistle|Tomato|Transparent|Turquoise|Violet|Wheat|White|WhiteSmoke|Yellow|YellowGreen)\b/i,{pattern:/\b(?:hsl|rgb)\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*\)\B|\b(?:hsl|rgb)a\(\s*\d{1,3}\s*,\s*\d{1,3}%?\s*,\s*\d{1,3}%?\s*,\s*(?:0|0?\.\d+|1)\s*\)\B/i,inside:{unit:t,number:n,function:/[\w-]+(?=\()/,punctuation:/[(),]/}}],entity:/\\[\da-f]{1,8}/i,unit:t,boolean:/\b(?:false|true)\b/,operator:[/~|[+!\/%<>?=]=?|[-:]=|\*[*=]?|\.{2,3}|&&|\|\||\B-\B|\b(?:and|in|is(?: a| defined| not|nt)?|not|or)\b/],number:n,punctuation:/[{}()\[\];:,]/};r.interpolation={pattern:/\{[^\r\n}:]+\}/,alias:"variable",inside:{delimiter:{pattern:/^\{|\}$/,alias:"punctuation"},rest:r}},r.func={pattern:/[\w-]+\([^)]*\).*/,inside:{function:/^[^(]+/,rest:r}},e.languages.stylus={"atrule-declaration":{pattern:/(^[ \t]*)@.+/m,lookbehind:!0,inside:{atrule:/^@[\w-]+/,rest:r}},"variable-declaration":{pattern:/(^[ \t]*)[\w$-]+\s*.?=[ \t]*(?:\{[^{}]*\}|\S.*|$)/m,lookbehind:!0,inside:{variable:/^\S+/,rest:r}},statement:{pattern:/(^[ \t]*)(?:else|for|if|return|unless)[ \t].+/m,lookbehind:!0,inside:{keyword:/^\S+/,rest:r}},"property-declaration":{pattern:/((?:^|\{)([ \t]*))(?:[\w-]|\{[^}\r\n]+\})+(?:\s*:\s*|[ \t]+)(?!\s)[^{\r\n]*(?:;|[^{\r\n,]$(?!(?:\r?\n|\r)(?:\{|\2[ \t])))/m,lookbehind:!0,inside:{property:{pattern:/^[^\s:]+/,inside:{interpolation:r.interpolation}},rest:r}},selector:{pattern:/(^[ \t]*)(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)(?:(?:\r?\n|\r)(?:\1(?:(?=\S)(?:[^{}\r\n:()]|::?[\w-]+(?:\([^)\r\n]*\)|(?![\w-]))|\{[^}\r\n]+\})+)))*(?:,$|\{|(?=(?:\r?\n|\r)(?:\{|\1[ \t])))/m,lookbehind:!0,inside:{interpolation:r.interpolation,comment:r.comment,punctuation:/[{},]/}},func:r.func,string:r.string,comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0,greedy:!0},interpolation:r.interpolation,punctuation:/[{}()\[\];:.]/}}(a),function(e){var t=e.util.clone(e.languages.typescript);e.languages.tsx=e.languages.extend("jsx",t),delete e.languages.tsx.parameter,delete e.languages.tsx["literal-property"];var n=e.languages.tsx.tag;n.pattern=RegExp(/(^|[^\w$]|(?=<\/))/.source+"(?:"+n.pattern.source+")",n.pattern.flags),n.lookbehind=!0}(a),a.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|neg?|nearest|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|sqrt|store(?:8|16|32)?|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^`|~]+/,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};const o=a},4225:()=>{Prism.languages.cmake={comment:/#.*/,string:{pattern:/"(?:[^\\"]|\\.)*"/,greedy:!0,inside:{interpolation:{pattern:/\$\{(?:[^{}$]|\$\{[^{}$]*\})*\}/,inside:{punctuation:/\$\{|\}/,variable:/\w+/}}}},variable:/\b(?:CMAKE_\w+|\w+_(?:(?:BINARY|SOURCE)_DIR|DESCRIPTION|HOMEPAGE_URL|ROOT|VERSION(?:_MAJOR|_MINOR|_PATCH|_TWEAK)?)|(?:ANDROID|APPLE|BORLAND|BUILD_SHARED_LIBS|CACHE|CPACK_(?:ABSOLUTE_DESTINATION_FILES|COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY|ERROR_ON_ABSOLUTE_INSTALL_DESTINATION|INCLUDE_TOPLEVEL_DIRECTORY|INSTALL_DEFAULT_DIRECTORY_PERMISSIONS|INSTALL_SCRIPT|PACKAGING_INSTALL_PREFIX|SET_DESTDIR|WARN_ON_ABSOLUTE_INSTALL_DESTINATION)|CTEST_(?:BINARY_DIRECTORY|BUILD_COMMAND|BUILD_NAME|BZR_COMMAND|BZR_UPDATE_OPTIONS|CHANGE_ID|CHECKOUT_COMMAND|CONFIGURATION_TYPE|CONFIGURE_COMMAND|COVERAGE_COMMAND|COVERAGE_EXTRA_FLAGS|CURL_OPTIONS|CUSTOM_(?:COVERAGE_EXCLUDE|ERROR_EXCEPTION|ERROR_MATCH|ERROR_POST_CONTEXT|ERROR_PRE_CONTEXT|MAXIMUM_FAILED_TEST_OUTPUT_SIZE|MAXIMUM_NUMBER_OF_(?:ERRORS|WARNINGS)|MAXIMUM_PASSED_TEST_OUTPUT_SIZE|MEMCHECK_IGNORE|POST_MEMCHECK|POST_TEST|PRE_MEMCHECK|PRE_TEST|TESTS_IGNORE|WARNING_EXCEPTION|WARNING_MATCH)|CVS_CHECKOUT|CVS_COMMAND|CVS_UPDATE_OPTIONS|DROP_LOCATION|DROP_METHOD|DROP_SITE|DROP_SITE_CDASH|DROP_SITE_PASSWORD|DROP_SITE_USER|EXTRA_COVERAGE_GLOB|GIT_COMMAND|GIT_INIT_SUBMODULES|GIT_UPDATE_CUSTOM|GIT_UPDATE_OPTIONS|HG_COMMAND|HG_UPDATE_OPTIONS|LABELS_FOR_SUBPROJECTS|MEMORYCHECK_(?:COMMAND|COMMAND_OPTIONS|SANITIZER_OPTIONS|SUPPRESSIONS_FILE|TYPE)|NIGHTLY_START_TIME|P4_CLIENT|P4_COMMAND|P4_OPTIONS|P4_UPDATE_OPTIONS|RUN_CURRENT_SCRIPT|SCP_COMMAND|SITE|SOURCE_DIRECTORY|SUBMIT_URL|SVN_COMMAND|SVN_OPTIONS|SVN_UPDATE_OPTIONS|TEST_LOAD|TEST_TIMEOUT|TRIGGER_SITE|UPDATE_COMMAND|UPDATE_OPTIONS|UPDATE_VERSION_ONLY|USE_LAUNCHERS)|CYGWIN|ENV|EXECUTABLE_OUTPUT_PATH|GHS-MULTI|IOS|LIBRARY_OUTPUT_PATH|MINGW|MSVC(?:10|11|12|14|60|70|71|80|90|_IDE|_TOOLSET_VERSION|_VERSION)?|MSYS|PROJECT_NAME|UNIX|WIN32|WINCE|WINDOWS_PHONE|WINDOWS_STORE|XCODE))\b/,property:/\b(?:cxx_\w+|(?:ARCHIVE_OUTPUT_(?:DIRECTORY|NAME)|COMPILE_DEFINITIONS|COMPILE_PDB_NAME|COMPILE_PDB_OUTPUT_DIRECTORY|EXCLUDE_FROM_DEFAULT_BUILD|IMPORTED_(?:IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_LANGUAGES|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|NO_SONAME|OBJECTS|SONAME)|INTERPROCEDURAL_OPTIMIZATION|LIBRARY_OUTPUT_DIRECTORY|LIBRARY_OUTPUT_NAME|LINK_FLAGS|LINK_INTERFACE_LIBRARIES|LINK_INTERFACE_MULTIPLICITY|LOCATION|MAP_IMPORTED_CONFIG|OSX_ARCHITECTURES|OUTPUT_NAME|PDB_NAME|PDB_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_DIRECTORY|RUNTIME_OUTPUT_NAME|STATIC_LIBRARY_FLAGS|VS_CSHARP|VS_DOTNET_REFERENCEPROP|VS_DOTNET_REFERENCE|VS_GLOBAL_SECTION_POST|VS_GLOBAL_SECTION_PRE|VS_GLOBAL|XCODE_ATTRIBUTE)_\w+|\w+_(?:CLANG_TIDY|COMPILER_LAUNCHER|CPPCHECK|CPPLINT|INCLUDE_WHAT_YOU_USE|OUTPUT_NAME|POSTFIX|VISIBILITY_PRESET)|ABSTRACT|ADDITIONAL_MAKE_CLEAN_FILES|ADVANCED|ALIASED_TARGET|ALLOW_DUPLICATE_CUSTOM_TARGETS|ANDROID_(?:ANT_ADDITIONAL_OPTIONS|API|API_MIN|ARCH|ASSETS_DIRECTORIES|GUI|JAR_DEPENDENCIES|NATIVE_LIB_DEPENDENCIES|NATIVE_LIB_DIRECTORIES|PROCESS_MAX|PROGUARD|PROGUARD_CONFIG_PATH|SECURE_PROPS_PATH|SKIP_ANT_STEP|STL_TYPE)|ARCHIVE_OUTPUT_DIRECTORY|ATTACHED_FILES|ATTACHED_FILES_ON_FAIL|AUTOGEN_(?:BUILD_DIR|ORIGIN_DEPENDS|PARALLEL|SOURCE_GROUP|TARGETS_FOLDER|TARGET_DEPENDS)|AUTOMOC|AUTOMOC_(?:COMPILER_PREDEFINES|DEPEND_FILTERS|EXECUTABLE|MACRO_NAMES|MOC_OPTIONS|SOURCE_GROUP|TARGETS_FOLDER)|AUTORCC|AUTORCC_EXECUTABLE|AUTORCC_OPTIONS|AUTORCC_SOURCE_GROUP|AUTOUIC|AUTOUIC_EXECUTABLE|AUTOUIC_OPTIONS|AUTOUIC_SEARCH_PATHS|BINARY_DIR|BUILDSYSTEM_TARGETS|BUILD_RPATH|BUILD_RPATH_USE_ORIGIN|BUILD_WITH_INSTALL_NAME_DIR|BUILD_WITH_INSTALL_RPATH|BUNDLE|BUNDLE_EXTENSION|CACHE_VARIABLES|CLEAN_NO_CUSTOM|COMMON_LANGUAGE_RUNTIME|COMPATIBLE_INTERFACE_(?:BOOL|NUMBER_MAX|NUMBER_MIN|STRING)|COMPILE_(?:DEFINITIONS|FEATURES|FLAGS|OPTIONS|PDB_NAME|PDB_OUTPUT_DIRECTORY)|COST|CPACK_DESKTOP_SHORTCUTS|CPACK_NEVER_OVERWRITE|CPACK_PERMANENT|CPACK_STARTUP_SHORTCUTS|CPACK_START_MENU_SHORTCUTS|CPACK_WIX_ACL|CROSSCOMPILING_EMULATOR|CUDA_EXTENSIONS|CUDA_PTX_COMPILATION|CUDA_RESOLVE_DEVICE_SYMBOLS|CUDA_SEPARABLE_COMPILATION|CUDA_STANDARD|CUDA_STANDARD_REQUIRED|CXX_EXTENSIONS|CXX_STANDARD|CXX_STANDARD_REQUIRED|C_EXTENSIONS|C_STANDARD|C_STANDARD_REQUIRED|DEBUG_CONFIGURATIONS|DEFINE_SYMBOL|DEFINITIONS|DEPENDS|DEPLOYMENT_ADDITIONAL_FILES|DEPLOYMENT_REMOTE_DIRECTORY|DISABLED|DISABLED_FEATURES|ECLIPSE_EXTRA_CPROJECT_CONTENTS|ECLIPSE_EXTRA_NATURES|ENABLED_FEATURES|ENABLED_LANGUAGES|ENABLE_EXPORTS|ENVIRONMENT|EXCLUDE_FROM_ALL|EXCLUDE_FROM_DEFAULT_BUILD|EXPORT_NAME|EXPORT_PROPERTIES|EXTERNAL_OBJECT|EchoString|FAIL_REGULAR_EXPRESSION|FIND_LIBRARY_USE_LIB32_PATHS|FIND_LIBRARY_USE_LIB64_PATHS|FIND_LIBRARY_USE_LIBX32_PATHS|FIND_LIBRARY_USE_OPENBSD_VERSIONING|FIXTURES_CLEANUP|FIXTURES_REQUIRED|FIXTURES_SETUP|FOLDER|FRAMEWORK|Fortran_FORMAT|Fortran_MODULE_DIRECTORY|GENERATED|GENERATOR_FILE_NAME|GENERATOR_IS_MULTI_CONFIG|GHS_INTEGRITY_APP|GHS_NO_SOURCE_GROUP_FILE|GLOBAL_DEPENDS_DEBUG_MODE|GLOBAL_DEPENDS_NO_CYCLES|GNUtoMS|HAS_CXX|HEADER_FILE_ONLY|HELPSTRING|IMPLICIT_DEPENDS_INCLUDE_TRANSFORM|IMPORTED|IMPORTED_(?:COMMON_LANGUAGE_RUNTIME|CONFIGURATIONS|GLOBAL|IMPLIB|LIBNAME|LINK_DEPENDENT_LIBRARIES|LINK_INTERFACE_(?:LANGUAGES|LIBRARIES|MULTIPLICITY)|LOCATION|NO_SONAME|OBJECTS|SONAME)|IMPORT_PREFIX|IMPORT_SUFFIX|INCLUDE_DIRECTORIES|INCLUDE_REGULAR_EXPRESSION|INSTALL_NAME_DIR|INSTALL_RPATH|INSTALL_RPATH_USE_LINK_PATH|INTERFACE_(?:AUTOUIC_OPTIONS|COMPILE_DEFINITIONS|COMPILE_FEATURES|COMPILE_OPTIONS|INCLUDE_DIRECTORIES|LINK_DEPENDS|LINK_DIRECTORIES|LINK_LIBRARIES|LINK_OPTIONS|POSITION_INDEPENDENT_CODE|SOURCES|SYSTEM_INCLUDE_DIRECTORIES)|INTERPROCEDURAL_OPTIMIZATION|IN_TRY_COMPILE|IOS_INSTALL_COMBINED|JOB_POOLS|JOB_POOL_COMPILE|JOB_POOL_LINK|KEEP_EXTENSION|LABELS|LANGUAGE|LIBRARY_OUTPUT_DIRECTORY|LINKER_LANGUAGE|LINK_(?:DEPENDS|DEPENDS_NO_SHARED|DIRECTORIES|FLAGS|INTERFACE_LIBRARIES|INTERFACE_MULTIPLICITY|LIBRARIES|OPTIONS|SEARCH_END_STATIC|SEARCH_START_STATIC|WHAT_YOU_USE)|LISTFILE_STACK|LOCATION|MACOSX_BUNDLE|MACOSX_BUNDLE_INFO_PLIST|MACOSX_FRAMEWORK_INFO_PLIST|MACOSX_PACKAGE_LOCATION|MACOSX_RPATH|MACROS|MANUALLY_ADDED_DEPENDENCIES|MEASUREMENT|MODIFIED|NAME|NO_SONAME|NO_SYSTEM_FROM_IMPORTED|OBJECT_DEPENDS|OBJECT_OUTPUTS|OSX_ARCHITECTURES|OUTPUT_NAME|PACKAGES_FOUND|PACKAGES_NOT_FOUND|PARENT_DIRECTORY|PASS_REGULAR_EXPRESSION|PDB_NAME|PDB_OUTPUT_DIRECTORY|POSITION_INDEPENDENT_CODE|POST_INSTALL_SCRIPT|PREDEFINED_TARGETS_FOLDER|PREFIX|PRE_INSTALL_SCRIPT|PRIVATE_HEADER|PROCESSORS|PROCESSOR_AFFINITY|PROJECT_LABEL|PUBLIC_HEADER|REPORT_UNDEFINED_PROPERTIES|REQUIRED_FILES|RESOURCE|RESOURCE_LOCK|RULE_LAUNCH_COMPILE|RULE_LAUNCH_CUSTOM|RULE_LAUNCH_LINK|RULE_MESSAGES|RUNTIME_OUTPUT_DIRECTORY|RUN_SERIAL|SKIP_AUTOGEN|SKIP_AUTOMOC|SKIP_AUTORCC|SKIP_AUTOUIC|SKIP_BUILD_RPATH|SKIP_RETURN_CODE|SOURCES|SOURCE_DIR|SOVERSION|STATIC_LIBRARY_FLAGS|STATIC_LIBRARY_OPTIONS|STRINGS|SUBDIRECTORIES|SUFFIX|SYMBOLIC|TARGET_ARCHIVES_MAY_BE_SHARED_LIBS|TARGET_MESSAGES|TARGET_SUPPORTS_SHARED_LIBS|TESTS|TEST_INCLUDE_FILE|TEST_INCLUDE_FILES|TIMEOUT|TIMEOUT_AFTER_MATCH|TYPE|USE_FOLDERS|VALUE|VARIABLES|VERSION|VISIBILITY_INLINES_HIDDEN|VS_(?:CONFIGURATION_TYPE|COPY_TO_OUT_DIR|DEBUGGER_(?:COMMAND|COMMAND_ARGUMENTS|ENVIRONMENT|WORKING_DIRECTORY)|DEPLOYMENT_CONTENT|DEPLOYMENT_LOCATION|DOTNET_REFERENCES|DOTNET_REFERENCES_COPY_LOCAL|INCLUDE_IN_VSIX|IOT_STARTUP_TASK|KEYWORD|RESOURCE_GENERATOR|SCC_AUXPATH|SCC_LOCALPATH|SCC_PROJECTNAME|SCC_PROVIDER|SDK_REFERENCES|SHADER_(?:DISABLE_OPTIMIZATIONS|ENABLE_DEBUG|ENTRYPOINT|FLAGS|MODEL|OBJECT_FILE_NAME|OUTPUT_HEADER_FILE|TYPE|VARIABLE_NAME)|STARTUP_PROJECT|TOOL_OVERRIDE|USER_PROPS|WINRT_COMPONENT|WINRT_EXTENSIONS|WINRT_REFERENCES|XAML_TYPE)|WILL_FAIL|WIN32_EXECUTABLE|WINDOWS_EXPORT_ALL_SYMBOLS|WORKING_DIRECTORY|WRAP_EXCLUDE|XCODE_(?:EMIT_EFFECTIVE_PLATFORM_NAME|EXPLICIT_FILE_TYPE|FILE_ATTRIBUTES|LAST_KNOWN_FILE_TYPE|PRODUCT_TYPE|SCHEME_(?:ADDRESS_SANITIZER|ADDRESS_SANITIZER_USE_AFTER_RETURN|ARGUMENTS|DISABLE_MAIN_THREAD_CHECKER|DYNAMIC_LIBRARY_LOADS|DYNAMIC_LINKER_API_USAGE|ENVIRONMENT|EXECUTABLE|GUARD_MALLOC|MAIN_THREAD_CHECKER_STOP|MALLOC_GUARD_EDGES|MALLOC_SCRIBBLE|MALLOC_STACK|THREAD_SANITIZER(?:_STOP)?|UNDEFINED_BEHAVIOUR_SANITIZER(?:_STOP)?|ZOMBIE_OBJECTS))|XCTEST)\b/,keyword:/\b(?:add_compile_definitions|add_compile_options|add_custom_command|add_custom_target|add_definitions|add_dependencies|add_executable|add_library|add_link_options|add_subdirectory|add_test|aux_source_directory|break|build_command|build_name|cmake_host_system_information|cmake_minimum_required|cmake_parse_arguments|cmake_policy|configure_file|continue|create_test_sourcelist|ctest_build|ctest_configure|ctest_coverage|ctest_empty_binary_directory|ctest_memcheck|ctest_read_custom_files|ctest_run_script|ctest_sleep|ctest_start|ctest_submit|ctest_test|ctest_update|ctest_upload|define_property|else|elseif|enable_language|enable_testing|endforeach|endfunction|endif|endmacro|endwhile|exec_program|execute_process|export|export_library_dependencies|file|find_file|find_library|find_package|find_path|find_program|fltk_wrap_ui|foreach|function|get_cmake_property|get_directory_property|get_filename_component|get_property|get_source_file_property|get_target_property|get_test_property|if|include|include_directories|include_external_msproject|include_guard|include_regular_expression|install|install_files|install_programs|install_targets|link_directories|link_libraries|list|load_cache|load_command|macro|make_directory|mark_as_advanced|math|message|option|output_required_files|project|qt_wrap_cpp|qt_wrap_ui|remove|remove_definitions|return|separate_arguments|set|set_directory_properties|set_property|set_source_files_properties|set_target_properties|set_tests_properties|site_name|source_group|string|subdir_depends|subdirs|target_compile_definitions|target_compile_features|target_compile_options|target_include_directories|target_link_directories|target_link_libraries|target_link_options|target_sources|try_compile|try_run|unset|use_mangled_mesa|utility_source|variable_requires|variable_watch|while|write_file)(?=\s*\()\b/,boolean:/\b(?:FALSE|OFF|ON|TRUE)\b/,namespace:/\b(?:INTERFACE|PRIVATE|PROPERTIES|PUBLIC|SHARED|STATIC|TARGET_OBJECTS)\b/,operator:/\b(?:AND|DEFINED|EQUAL|GREATER|LESS|MATCHES|NOT|OR|STREQUAL|STRGREATER|STRLESS|VERSION_EQUAL|VERSION_GREATER|VERSION_LESS)\b/,inserted:{pattern:/\b\w+::\w+\b/,alias:"class-name"},number:/\b\d+(?:\.\d+)*\b/,function:/\b[a-z_]\w*(?=\s*\()\b/i,punctuation:/[()>}]|\$[<{]/}},6862:()=>{!function(e){var t=e.languages.powershell={comment:[{pattern:/(^|[^`])<#[\s\S]*?#>/,lookbehind:!0},{pattern:/(^|[^`])#.*/,lookbehind:!0}],string:[{pattern:/"(?:`[\s\S]|[^`"])*"/,greedy:!0,inside:null},{pattern:/'(?:[^']|'')*'/,greedy:!0}],namespace:/\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i,boolean:/\$(?:false|true)\b/i,variable:/\$\w+\b/,function:[/\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i,/\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i],keyword:/\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i,operator:{pattern:/(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i,lookbehind:!0},punctuation:/[|{}[\];(),.]/};t.string[0].inside={function:{pattern:/(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/,lookbehind:!0,inside:t},boolean:t.boolean,variable:t.variable}}(Prism)},2295:(e,t,n)=>{var r={"./prism-cmake":4225,"./prism-powershell":6862};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=2295},2703:(e,t,n)=>{"use strict";var r=n(414);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},5697:(e,t,n)=>{e.exports=n(2703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},4448:(e,t,n)=>{"use strict";var r=n(7294),a=n(7418),o=n(3840);function i(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}if(!r)throw Error(i(227));var l=new Set,s={};function u(e,t){c(e,t),c(e+"Capture",t)}function c(e,t){for(s[e]=t,e=0;e<t.length;e++)l.add(t[e])}var d=!("undefined"==typeof window||void 0===window.document||void 0===window.document.createElement),f=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,p=Object.prototype.hasOwnProperty,m={},h={};function g(e,t,n,r,a,o,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=a,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=o,this.removeEmptyString=i}var b={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach((function(e){b[e]=new g(e,0,!1,e,null,!1,!1)})),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach((function(e){var t=e[0];b[t]=new g(t,1,!1,e[1],null,!1,!1)})),["contentEditable","draggable","spellCheck","value"].forEach((function(e){b[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)})),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach((function(e){b[e]=new g(e,2,!1,e,null,!1,!1)})),"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach((function(e){b[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)})),["checked","multiple","muted","selected"].forEach((function(e){b[e]=new g(e,3,!0,e,null,!1,!1)})),["capture","download"].forEach((function(e){b[e]=new g(e,4,!1,e,null,!1,!1)})),["cols","rows","size","span"].forEach((function(e){b[e]=new g(e,6,!1,e,null,!1,!1)})),["rowSpan","start"].forEach((function(e){b[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)}));var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}function E(e,t,n,r){var a=b.hasOwnProperty(t)?b[t]:null;(null!==a?0===a.type:!r&&(2<t.length&&("o"===t[0]||"O"===t[0])&&("n"===t[1]||"N"===t[1])))||(function(e,t,n,r){if(null==t||function(e,t,n,r){if(null!==n&&0===n.type)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return!r&&(null!==n?!n.acceptsBooleans:"data-"!==(e=e.toLowerCase().slice(0,5))&&"aria-"!==e);default:return!1}}(e,t,n,r))return!0;if(r)return!1;if(null!==n)switch(n.type){case 3:return!t;case 4:return!1===t;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}(t,n,a,r)&&(n=null),r||null===a?function(e){return!!p.call(h,e)||!p.call(m,e)&&(f.test(e)?h[e]=!0:(m[e]=!0,!1))}(t)&&(null===n?e.removeAttribute(t):e.setAttribute(t,""+n)):a.mustUseProperty?e[a.propertyName]=null===n?3!==a.type&&"":n:(t=a.attributeName,r=a.attributeNamespace,null===n?e.removeAttribute(t):(n=3===(a=a.type)||4===a&&!0===n?"":""+n,r?e.setAttributeNS(r,t,n):e.setAttribute(t,n))))}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,null,!1,!1)})),"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)})),["xml:base","xml:lang","xml:space"].forEach((function(e){var t=e.replace(v,y);b[t]=new g(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)})),["tabIndex","crossOrigin"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)})),b.xlinkHref=new g("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach((function(e){b[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)}));var S=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,_=60103,w=60106,T=60107,k=60108,C=60114,A=60109,I=60110,O=60112,R=60113,N=60120,L=60115,P=60116,x=60121,D=60128,M=60129,U=60130,F=60131;if("function"==typeof Symbol&&Symbol.for){var B=Symbol.for;_=B("react.element"),w=B("react.portal"),T=B("react.fragment"),k=B("react.strict_mode"),C=B("react.profiler"),A=B("react.provider"),I=B("react.context"),O=B("react.forward_ref"),R=B("react.suspense"),N=B("react.suspense_list"),L=B("react.memo"),P=B("react.lazy"),x=B("react.block"),B("react.scope"),D=B("react.opaque.id"),M=B("react.debug_trace_mode"),U=B("react.offscreen"),F=B("react.legacy_hidden")}var $,z="function"==typeof Symbol&&Symbol.iterator;function H(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=z&&e[z]||e["@@iterator"])?e:null}function j(e){if(void 0===$)try{throw Error()}catch(n){var t=n.stack.trim().match(/\n( *(at )?)/);$=t&&t[1]||""}return"\n"+$+e}var G=!1;function Z(e,t){if(!e||G)return"";G=!0;var n=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(t)if(t=function(){throw Error()},Object.defineProperty(t.prototype,"props",{set:function(){throw Error()}}),"object"==typeof Reflect&&Reflect.construct){try{Reflect.construct(t,[])}catch(s){var r=s}Reflect.construct(e,[],t)}else{try{t.call()}catch(s){r=s}e.call(t.prototype)}else{try{throw Error()}catch(s){r=s}e()}}catch(s){if(s&&r&&"string"==typeof s.stack){for(var a=s.stack.split("\n"),o=r.stack.split("\n"),i=a.length-1,l=o.length-1;1<=i&&0<=l&&a[i]!==o[l];)l--;for(;1<=i&&0<=l;i--,l--)if(a[i]!==o[l]){if(1!==i||1!==l)do{if(i--,0>--l||a[i]!==o[l])return"\n"+a[i].replace(" at new "," at ")}while(1<=i&&0<=l);break}}}finally{G=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?j(e):""}function V(e){switch(e.tag){case 5:return j(e.type);case 16:return j("Lazy");case 13:return j("Suspense");case 19:return j("SuspenseList");case 0:case 2:case 15:return e=Z(e.type,!1);case 11:return e=Z(e.type.render,!1);case 22:return e=Z(e.type._render,!1);case 1:return e=Z(e.type,!0);default:return""}}function W(e){if(null==e)return null;if("function"==typeof e)return e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case T:return"Fragment";case w:return"Portal";case C:return"Profiler";case k:return"StrictMode";case R:return"Suspense";case N:return"SuspenseList"}if("object"==typeof e)switch(e.$$typeof){case I:return(e.displayName||"Context")+".Consumer";case A:return(e._context.displayName||"Context")+".Provider";case O:var t=e.render;return t=t.displayName||t.name||"",e.displayName||(""!==t?"ForwardRef("+t+")":"ForwardRef");case L:return W(e.type);case x:return W(e._render);case P:t=e._payload,e=e._init;try{return W(e(t))}catch(n){}}return null}function Y(e){switch(typeof e){case"boolean":case"number":case"object":case"string":case"undefined":return e;default:return""}}function K(e){var t=e.type;return(e=e.nodeName)&&"input"===e.toLowerCase()&&("checkbox"===t||"radio"===t)}function X(e){e._valueTracker||(e._valueTracker=function(e){var t=K(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&void 0!==n&&"function"==typeof n.get&&"function"==typeof n.set){var a=n.get,o=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return a.call(this)},set:function(e){r=""+e,o.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=""+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}(e))}function q(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=K(e)?e.checked?"true":"false":e.value),(e=r)!==n&&(t.setValue(e),!0)}function Q(e){if(void 0===(e=e||("undefined"!=typeof document?document:void 0)))return null;try{return e.activeElement||e.body}catch(t){return e.body}}function J(e,t){var n=t.checked;return a({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=n?n:e._wrapperState.initialChecked})}function ee(e,t){var n=null==t.defaultValue?"":t.defaultValue,r=null!=t.checked?t.checked:t.defaultChecked;n=Y(null!=t.value?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:"checkbox"===t.type||"radio"===t.type?null!=t.checked:null!=t.value}}function te(e,t){null!=(t=t.checked)&&E(e,"checked",t,!1)}function ne(e,t){te(e,t);var n=Y(t.value),r=t.type;if(null!=n)"number"===r?(0===n&&""===e.value||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if("submit"===r||"reset"===r)return void e.removeAttribute("value");t.hasOwnProperty("value")?ae(e,t.type,n):t.hasOwnProperty("defaultValue")&&ae(e,t.type,Y(t.defaultValue)),null==t.checked&&null!=t.defaultChecked&&(e.defaultChecked=!!t.defaultChecked)}function re(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!("submit"!==r&&"reset"!==r||void 0!==t.value&&null!==t.value))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}""!==(n=e.name)&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,""!==n&&(e.name=n)}function ae(e,t,n){"number"===t&&Q(e.ownerDocument)===e||(null==n?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}function oe(e,t){return e=a({children:void 0},t),(t=function(e){var t="";return r.Children.forEach(e,(function(e){null!=e&&(t+=e)})),t}(t.children))&&(e.children=t),e}function ie(e,t,n,r){if(e=e.options,t){t={};for(var a=0;a<n.length;a++)t["$"+n[a]]=!0;for(n=0;n<e.length;n++)a=t.hasOwnProperty("$"+e[n].value),e[n].selected!==a&&(e[n].selected=a),a&&r&&(e[n].defaultSelected=!0)}else{for(n=""+Y(n),t=null,a=0;a<e.length;a++){if(e[a].value===n)return e[a].selected=!0,void(r&&(e[a].defaultSelected=!0));null!==t||e[a].disabled||(t=e[a])}null!==t&&(t.selected=!0)}}function le(e,t){if(null!=t.dangerouslySetInnerHTML)throw Error(i(91));return a({},t,{value:void 0,defaultValue:void 0,children:""+e._wrapperState.initialValue})}function se(e,t){var n=t.value;if(null==n){if(n=t.children,t=t.defaultValue,null!=n){if(null!=t)throw Error(i(92));if(Array.isArray(n)){if(!(1>=n.length))throw Error(i(93));n=n[0]}t=n}null==t&&(t=""),n=t}e._wrapperState={initialValue:Y(n)}}function ue(e,t){var n=Y(t.value),r=Y(t.defaultValue);null!=n&&((n=""+n)!==e.value&&(e.value=n),null==t.defaultValue&&e.defaultValue!==n&&(e.defaultValue=n)),null!=r&&(e.defaultValue=""+r)}function ce(e){var t=e.textContent;t===e._wrapperState.initialValue&&""!==t&&null!==t&&(e.value=t)}var de={html:"http://www.w3.org/1999/xhtml",mathml:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg"};function fe(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function pe(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?fe(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}var me,he,ge=(he=function(e,t){if(e.namespaceURI!==de.svg||"innerHTML"in e)e.innerHTML=t;else{for((me=me||document.createElement("div")).innerHTML="<svg>"+t.valueOf().toString()+"</svg>",t=me.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}},"undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction?function(e,t,n,r){MSApp.execUnsafeLocalFunction((function(){return he(e,t)}))}:he);function be(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}var ve={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},ye=["Webkit","ms","Moz","O"];function Ee(e,t,n){return null==t||"boolean"==typeof t||""===t?"":n||"number"!=typeof t||0===t||ve.hasOwnProperty(e)&&ve[e]?(""+t).trim():t+"px"}function Se(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),a=Ee(n,t[n],r);"float"===n&&(n="cssFloat"),r?e.setProperty(n,a):e[n]=a}}Object.keys(ve).forEach((function(e){ye.forEach((function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ve[t]=ve[e]}))}));var _e=a({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function we(e,t){if(t){if(_e[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML))throw Error(i(137,e));if(null!=t.dangerouslySetInnerHTML){if(null!=t.children)throw Error(i(60));if("object"!=typeof t.dangerouslySetInnerHTML||!("__html"in t.dangerouslySetInnerHTML))throw Error(i(61))}if(null!=t.style&&"object"!=typeof t.style)throw Error(i(62))}}function Te(e,t){if(-1===e.indexOf("-"))return"string"==typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function ke(e){return(e=e.target||e.srcElement||window).correspondingUseElement&&(e=e.correspondingUseElement),3===e.nodeType?e.parentNode:e}var Ce=null,Ae=null,Ie=null;function Oe(e){if(e=na(e)){if("function"!=typeof Ce)throw Error(i(280));var t=e.stateNode;t&&(t=aa(t),Ce(e.stateNode,e.type,t))}}function Re(e){Ae?Ie?Ie.push(e):Ie=[e]:Ae=e}function Ne(){if(Ae){var e=Ae,t=Ie;if(Ie=Ae=null,Oe(e),t)for(e=0;e<t.length;e++)Oe(t[e])}}function Le(e,t){return e(t)}function Pe(e,t,n,r,a){return e(t,n,r,a)}function xe(){}var De=Le,Me=!1,Ue=!1;function Fe(){null===Ae&&null===Ie||(xe(),Ne())}function Be(e,t){var n=e.stateNode;if(null===n)return null;var r=aa(n);if(null===r)return null;n=r[t];e:switch(t){case"onClick":case"onClickCapture":case"onDoubleClick":case"onDoubleClickCapture":case"onMouseDown":case"onMouseDownCapture":case"onMouseMove":case"onMouseMoveCapture":case"onMouseUp":case"onMouseUpCapture":case"onMouseEnter":(r=!r.disabled)||(r=!("button"===(e=e.type)||"input"===e||"select"===e||"textarea"===e)),e=!r;break e;default:e=!1}if(e)return null;if(n&&"function"!=typeof n)throw Error(i(231,t,typeof n));return n}var $e=!1;if(d)try{var ze={};Object.defineProperty(ze,"passive",{get:function(){$e=!0}}),window.addEventListener("test",ze,ze),window.removeEventListener("test",ze,ze)}catch(he){$e=!1}function He(e,t,n,r,a,o,i,l,s){var u=Array.prototype.slice.call(arguments,3);try{t.apply(n,u)}catch(c){this.onError(c)}}var je=!1,Ge=null,Ze=!1,Ve=null,We={onError:function(e){je=!0,Ge=e}};function Ye(e,t,n,r,a,o,i,l,s){je=!1,Ge=null,He.apply(We,arguments)}function Ke(e){var t=e,n=e;if(e.alternate)for(;t.return;)t=t.return;else{e=t;do{0!=(1026&(t=e).flags)&&(n=t.return),e=t.return}while(e)}return 3===t.tag?n:null}function Xe(e){if(13===e.tag){var t=e.memoizedState;if(null===t&&(null!==(e=e.alternate)&&(t=e.memoizedState)),null!==t)return t.dehydrated}return null}function qe(e){if(Ke(e)!==e)throw Error(i(188))}function Qe(e){if(e=function(e){var t=e.alternate;if(!t){if(null===(t=Ke(e)))throw Error(i(188));return t!==e?null:e}for(var n=e,r=t;;){var a=n.return;if(null===a)break;var o=a.alternate;if(null===o){if(null!==(r=a.return)){n=r;continue}break}if(a.child===o.child){for(o=a.child;o;){if(o===n)return qe(a),e;if(o===r)return qe(a),t;o=o.sibling}throw Error(i(188))}if(n.return!==r.return)n=a,r=o;else{for(var l=!1,s=a.child;s;){if(s===n){l=!0,n=a,r=o;break}if(s===r){l=!0,r=a,n=o;break}s=s.sibling}if(!l){for(s=o.child;s;){if(s===n){l=!0,n=o,r=a;break}if(s===r){l=!0,r=o,n=a;break}s=s.sibling}if(!l)throw Error(i(189))}}if(n.alternate!==r)throw Error(i(190))}if(3!==n.tag)throw Error(i(188));return n.stateNode.current===n?e:t}(e),!e)return null;for(var t=e;;){if(5===t.tag||6===t.tag)return t;if(t.child)t.child.return=t,t=t.child;else{if(t===e)break;for(;!t.sibling;){if(!t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}}return null}function Je(e,t){for(var n=e.alternate;null!==t;){if(t===e||t===n)return!0;t=t.return}return!1}var et,tt,nt,rt,at=!1,ot=[],it=null,lt=null,st=null,ut=new Map,ct=new Map,dt=[],ft="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" ");function pt(e,t,n,r,a){return{blockedOn:e,domEventName:t,eventSystemFlags:16|n,nativeEvent:a,targetContainers:[r]}}function mt(e,t){switch(e){case"focusin":case"focusout":it=null;break;case"dragenter":case"dragleave":lt=null;break;case"mouseover":case"mouseout":st=null;break;case"pointerover":case"pointerout":ut.delete(t.pointerId);break;case"gotpointercapture":case"lostpointercapture":ct.delete(t.pointerId)}}function ht(e,t,n,r,a,o){return null===e||e.nativeEvent!==o?(e=pt(t,n,r,a,o),null!==t&&(null!==(t=na(t))&&tt(t)),e):(e.eventSystemFlags|=r,t=e.targetContainers,null!==a&&-1===t.indexOf(a)&&t.push(a),e)}function gt(e){var t=ta(e.target);if(null!==t){var n=Ke(t);if(null!==n)if(13===(t=n.tag)){if(null!==(t=Xe(n)))return e.blockedOn=t,void rt(e.lanePriority,(function(){o.unstable_runWithPriority(e.priority,(function(){nt(n)}))}))}else if(3===t&&n.stateNode.hydrate)return void(e.blockedOn=3===n.tag?n.stateNode.containerInfo:null)}e.blockedOn=null}function bt(e){if(null!==e.blockedOn)return!1;for(var t=e.targetContainers;0<t.length;){var n=Qt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n)return null!==(t=na(n))&&tt(t),e.blockedOn=n,!1;t.shift()}return!0}function vt(e,t,n){bt(e)&&n.delete(t)}function yt(){for(at=!1;0<ot.length;){var e=ot[0];if(null!==e.blockedOn){null!==(e=na(e.blockedOn))&&et(e);break}for(var t=e.targetContainers;0<t.length;){var n=Qt(e.domEventName,e.eventSystemFlags,t[0],e.nativeEvent);if(null!==n){e.blockedOn=n;break}t.shift()}null===e.blockedOn&&ot.shift()}null!==it&&bt(it)&&(it=null),null!==lt&&bt(lt)&&(lt=null),null!==st&&bt(st)&&(st=null),ut.forEach(vt),ct.forEach(vt)}function Et(e,t){e.blockedOn===t&&(e.blockedOn=null,at||(at=!0,o.unstable_scheduleCallback(o.unstable_NormalPriority,yt)))}function St(e){function t(t){return Et(t,e)}if(0<ot.length){Et(ot[0],e);for(var n=1;n<ot.length;n++){var r=ot[n];r.blockedOn===e&&(r.blockedOn=null)}}for(null!==it&&Et(it,e),null!==lt&&Et(lt,e),null!==st&&Et(st,e),ut.forEach(t),ct.forEach(t),n=0;n<dt.length;n++)(r=dt[n]).blockedOn===e&&(r.blockedOn=null);for(;0<dt.length&&null===(n=dt[0]).blockedOn;)gt(n),null===n.blockedOn&&dt.shift()}function _t(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit"+e]="webkit"+t,n["Moz"+e]="moz"+t,n}var wt={animationend:_t("Animation","AnimationEnd"),animationiteration:_t("Animation","AnimationIteration"),animationstart:_t("Animation","AnimationStart"),transitionend:_t("Transition","TransitionEnd")},Tt={},kt={};function Ct(e){if(Tt[e])return Tt[e];if(!wt[e])return e;var t,n=wt[e];for(t in n)if(n.hasOwnProperty(t)&&t in kt)return Tt[e]=n[t];return e}d&&(kt=document.createElement("div").style,"AnimationEvent"in window||(delete wt.animationend.animation,delete wt.animationiteration.animation,delete wt.animationstart.animation),"TransitionEvent"in window||delete wt.transitionend.transition);var At=Ct("animationend"),It=Ct("animationiteration"),Ot=Ct("animationstart"),Rt=Ct("transitionend"),Nt=new Map,Lt=new Map,Pt=["abort","abort",At,"animationEnd",It,"animationIteration",Ot,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata","loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",Rt,"transitionEnd","waiting","waiting"];function xt(e,t){for(var n=0;n<e.length;n+=2){var r=e[n],a=e[n+1];a="on"+(a[0].toUpperCase()+a.slice(1)),Lt.set(r,t),Nt.set(r,a),u(a,[r])}}(0,o.unstable_now)();var Dt=8;function Mt(e){if(0!=(1&e))return Dt=15,1;if(0!=(2&e))return Dt=14,2;if(0!=(4&e))return Dt=13,4;var t=24&e;return 0!==t?(Dt=12,t):0!=(32&e)?(Dt=11,32):0!==(t=192&e)?(Dt=10,t):0!=(256&e)?(Dt=9,256):0!==(t=3584&e)?(Dt=8,t):0!=(4096&e)?(Dt=7,4096):0!==(t=4186112&e)?(Dt=6,t):0!==(t=62914560&e)?(Dt=5,t):67108864&e?(Dt=4,67108864):0!=(134217728&e)?(Dt=3,134217728):0!==(t=805306368&e)?(Dt=2,t):0!=(1073741824&e)?(Dt=1,1073741824):(Dt=8,e)}function Ut(e,t){var n=e.pendingLanes;if(0===n)return Dt=0;var r=0,a=0,o=e.expiredLanes,i=e.suspendedLanes,l=e.pingedLanes;if(0!==o)r=o,a=Dt=15;else if(0!==(o=134217727&n)){var s=o&~i;0!==s?(r=Mt(s),a=Dt):0!==(l&=o)&&(r=Mt(l),a=Dt)}else 0!==(o=n&~i)?(r=Mt(o),a=Dt):0!==l&&(r=Mt(l),a=Dt);if(0===r)return 0;if(r=n&((0>(r=31-jt(r))?0:1<<r)<<1)-1,0!==t&&t!==r&&0==(t&i)){if(Mt(t),a<=Dt)return t;Dt=a}if(0!==(t=e.entangledLanes))for(e=e.entanglements,t&=r;0<t;)a=1<<(n=31-jt(t)),r|=e[n],t&=~a;return r}function Ft(e){return 0!==(e=-1073741825&e.pendingLanes)?e:1073741824&e?1073741824:0}function Bt(e,t){switch(e){case 15:return 1;case 14:return 2;case 12:return 0===(e=$t(24&~t))?Bt(10,t):e;case 10:return 0===(e=$t(192&~t))?Bt(8,t):e;case 8:return 0===(e=$t(3584&~t))&&(0===(e=$t(4186112&~t))&&(e=512)),e;case 2:return 0===(t=$t(805306368&~t))&&(t=268435456),t}throw Error(i(358,e))}function $t(e){return e&-e}function zt(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Ht(e,t,n){e.pendingLanes|=t;var r=t-1;e.suspendedLanes&=r,e.pingedLanes&=r,(e=e.eventTimes)[t=31-jt(t)]=n}var jt=Math.clz32?Math.clz32:function(e){return 0===e?32:31-(Gt(e)/Zt|0)|0},Gt=Math.log,Zt=Math.LN2;var Vt=o.unstable_UserBlockingPriority,Wt=o.unstable_runWithPriority,Yt=!0;function Kt(e,t,n,r){Me||xe();var a=qt,o=Me;Me=!0;try{Pe(a,e,t,n,r)}finally{(Me=o)||Fe()}}function Xt(e,t,n,r){Wt(Vt,qt.bind(null,e,t,n,r))}function qt(e,t,n,r){var a;if(Yt)if((a=0==(4&t))&&0<ot.length&&-1<ft.indexOf(e))e=pt(null,e,t,n,r),ot.push(e);else{var o=Qt(e,t,n,r);if(null===o)a&&mt(e,r);else{if(a){if(-1<ft.indexOf(e))return e=pt(o,e,t,n,r),void ot.push(e);if(function(e,t,n,r,a){switch(t){case"focusin":return it=ht(it,e,t,n,r,a),!0;case"dragenter":return lt=ht(lt,e,t,n,r,a),!0;case"mouseover":return st=ht(st,e,t,n,r,a),!0;case"pointerover":var o=a.pointerId;return ut.set(o,ht(ut.get(o)||null,e,t,n,r,a)),!0;case"gotpointercapture":return o=a.pointerId,ct.set(o,ht(ct.get(o)||null,e,t,n,r,a)),!0}return!1}(o,e,t,n,r))return;mt(e,r)}xr(e,t,r,null,n)}}}function Qt(e,t,n,r){var a=ke(r);if(null!==(a=ta(a))){var o=Ke(a);if(null===o)a=null;else{var i=o.tag;if(13===i){if(null!==(a=Xe(o)))return a;a=null}else if(3===i){if(o.stateNode.hydrate)return 3===o.tag?o.stateNode.containerInfo:null;a=null}else o!==a&&(a=null)}}return xr(e,t,r,a,n),null}var Jt=null,en=null,tn=null;function nn(){if(tn)return tn;var e,t,n=en,r=n.length,a="value"in Jt?Jt.value:Jt.textContent,o=a.length;for(e=0;e<r&&n[e]===a[e];e++);var i=r-e;for(t=1;t<=i&&n[r-t]===a[o-t];t++);return tn=a.slice(e,1<t?1-t:void 0)}function rn(e){var t=e.keyCode;return"charCode"in e?0===(e=e.charCode)&&13===t&&(e=13):e=t,10===e&&(e=13),32<=e||13===e?e:0}function an(){return!0}function on(){return!1}function ln(e){function t(t,n,r,a,o){for(var i in this._reactName=t,this._targetInst=r,this.type=n,this.nativeEvent=a,this.target=o,this.currentTarget=null,e)e.hasOwnProperty(i)&&(t=e[i],this[i]=t?t(a):a[i]);return this.isDefaultPrevented=(null!=a.defaultPrevented?a.defaultPrevented:!1===a.returnValue)?an:on,this.isPropagationStopped=on,this}return a(t.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!=typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=an)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!=typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=an)},persist:function(){},isPersistent:an}),t}var sn,un,cn,dn={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},fn=ln(dn),pn=a({},dn,{view:0,detail:0}),mn=ln(pn),hn=a({},pn,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:An,button:0,buttons:0,relatedTarget:function(e){return void 0===e.relatedTarget?e.fromElement===e.srcElement?e.toElement:e.fromElement:e.relatedTarget},movementX:function(e){return"movementX"in e?e.movementX:(e!==cn&&(cn&&"mousemove"===e.type?(sn=e.screenX-cn.screenX,un=e.screenY-cn.screenY):un=sn=0,cn=e),sn)},movementY:function(e){return"movementY"in e?e.movementY:un}}),gn=ln(hn),bn=ln(a({},hn,{dataTransfer:0})),vn=ln(a({},pn,{relatedTarget:0})),yn=ln(a({},dn,{animationName:0,elapsedTime:0,pseudoElement:0})),En=a({},dn,{clipboardData:function(e){return"clipboardData"in e?e.clipboardData:window.clipboardData}}),Sn=ln(En),_n=ln(a({},dn,{data:0})),wn={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},Tn={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},kn={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};function Cn(e){var t=this.nativeEvent;return t.getModifierState?t.getModifierState(e):!!(e=kn[e])&&!!t[e]}function An(){return Cn}var In=a({},pn,{key:function(e){if(e.key){var t=wn[e.key]||e.key;if("Unidentified"!==t)return t}return"keypress"===e.type?13===(e=rn(e))?"Enter":String.fromCharCode(e):"keydown"===e.type||"keyup"===e.type?Tn[e.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,repeat:0,locale:0,getModifierState:An,charCode:function(e){return"keypress"===e.type?rn(e):0},keyCode:function(e){return"keydown"===e.type||"keyup"===e.type?e.keyCode:0},which:function(e){return"keypress"===e.type?rn(e):"keydown"===e.type||"keyup"===e.type?e.keyCode:0}}),On=ln(In),Rn=ln(a({},hn,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0})),Nn=ln(a({},pn,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,ctrlKey:0,shiftKey:0,getModifierState:An})),Ln=ln(a({},dn,{propertyName:0,elapsedTime:0,pseudoElement:0})),Pn=a({},hn,{deltaX:function(e){return"deltaX"in e?e.deltaX:"wheelDeltaX"in e?-e.wheelDeltaX:0},deltaY:function(e){return"deltaY"in e?e.deltaY:"wheelDeltaY"in e?-e.wheelDeltaY:"wheelDelta"in e?-e.wheelDelta:0},deltaZ:0,deltaMode:0}),xn=ln(Pn),Dn=[9,13,27,32],Mn=d&&"CompositionEvent"in window,Un=null;d&&"documentMode"in document&&(Un=document.documentMode);var Fn=d&&"TextEvent"in window&&!Un,Bn=d&&(!Mn||Un&&8<Un&&11>=Un),$n=String.fromCharCode(32),zn=!1;function Hn(e,t){switch(e){case"keyup":return-1!==Dn.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function jn(e){return"object"==typeof(e=e.detail)&&"data"in e?e.data:null}var Gn=!1;var Zn={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};function Vn(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return"input"===t?!!Zn[e.type]:"textarea"===t}function Wn(e,t,n,r){Re(r),0<(t=Mr(t,"onChange")).length&&(n=new fn("onChange","change",null,n,r),e.push({event:n,listeners:t}))}var Yn=null,Kn=null;function Xn(e){Ir(e,0)}function qn(e){if(q(ra(e)))return e}function Qn(e,t){if("change"===e)return t}var Jn=!1;if(d){var er;if(d){var tr="oninput"in document;if(!tr){var nr=document.createElement("div");nr.setAttribute("oninput","return;"),tr="function"==typeof nr.oninput}er=tr}else er=!1;Jn=er&&(!document.documentMode||9<document.documentMode)}function rr(){Yn&&(Yn.detachEvent("onpropertychange",ar),Kn=Yn=null)}function ar(e){if("value"===e.propertyName&&qn(Kn)){var t=[];if(Wn(t,Kn,e,ke(e)),e=Xn,Me)e(t);else{Me=!0;try{Le(e,t)}finally{Me=!1,Fe()}}}}function or(e,t,n){"focusin"===e?(rr(),Kn=n,(Yn=t).attachEvent("onpropertychange",ar)):"focusout"===e&&rr()}function ir(e){if("selectionchange"===e||"keyup"===e||"keydown"===e)return qn(Kn)}function lr(e,t){if("click"===e)return qn(t)}function sr(e,t){if("input"===e||"change"===e)return qn(t)}var ur="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},cr=Object.prototype.hasOwnProperty;function dr(e,t){if(ur(e,t))return!0;if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(r=0;r<n.length;r++)if(!cr.call(t,n[r])||!ur(e[n[r]],t[n[r]]))return!1;return!0}function fr(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function pr(e,t){var n,r=fr(e);for(e=0;r;){if(3===r.nodeType){if(n=e+r.textContent.length,e<=t&&n>=t)return{node:r,offset:t-e};e=n}e:{for(;r;){if(r.nextSibling){r=r.nextSibling;break e}r=r.parentNode}r=void 0}r=fr(r)}}function mr(e,t){return!(!e||!t)&&(e===t||(!e||3!==e.nodeType)&&(t&&3===t.nodeType?mr(e,t.parentNode):"contains"in e?e.contains(t):!!e.compareDocumentPosition&&!!(16&e.compareDocumentPosition(t))))}function hr(){for(var e=window,t=Q();t instanceof e.HTMLIFrameElement;){try{var n="string"==typeof t.contentWindow.location.href}catch(r){n=!1}if(!n)break;t=Q((e=t.contentWindow).document)}return t}function gr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&("text"===e.type||"search"===e.type||"tel"===e.type||"url"===e.type||"password"===e.type)||"textarea"===t||"true"===e.contentEditable)}var br=d&&"documentMode"in document&&11>=document.documentMode,vr=null,yr=null,Er=null,Sr=!1;function _r(e,t,n){var r=n.window===n?n.document:9===n.nodeType?n:n.ownerDocument;Sr||null==vr||vr!==Q(r)||("selectionStart"in(r=vr)&&gr(r)?r={start:r.selectionStart,end:r.selectionEnd}:r={anchorNode:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection()).anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset},Er&&dr(Er,r)||(Er=r,0<(r=Mr(yr,"onSelect")).length&&(t=new fn("onSelect","select",null,t,n),e.push({event:t,listeners:r}),t.target=vr)))}xt("cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focusin focus focusout blur input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),0),xt("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1),xt(Pt,2);for(var wr="change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),Tr=0;Tr<wr.length;Tr++)Lt.set(wr[Tr],0);c("onMouseEnter",["mouseout","mouseover"]),c("onMouseLeave",["mouseout","mouseover"]),c("onPointerEnter",["pointerout","pointerover"]),c("onPointerLeave",["pointerout","pointerover"]),u("onChange","change click focusin focusout input keydown keyup selectionchange".split(" ")),u("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" ")),u("onBeforeInput",["compositionend","keypress","textInput","paste"]),u("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" ")),u("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" ")),u("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));var kr="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Cr=new Set("cancel close invalid load scroll toggle".split(" ").concat(kr));function Ar(e,t,n){var r=e.type||"unknown-event";e.currentTarget=n,function(e,t,n,r,a,o,l,s,u){if(Ye.apply(this,arguments),je){if(!je)throw Error(i(198));var c=Ge;je=!1,Ge=null,Ze||(Ze=!0,Ve=c)}}(r,t,void 0,e),e.currentTarget=null}function Ir(e,t){t=0!=(4&t);for(var n=0;n<e.length;n++){var r=e[n],a=r.event;r=r.listeners;e:{var o=void 0;if(t)for(var i=r.length-1;0<=i;i--){var l=r[i],s=l.instance,u=l.currentTarget;if(l=l.listener,s!==o&&a.isPropagationStopped())break e;Ar(a,l,u),o=s}else for(i=0;i<r.length;i++){if(s=(l=r[i]).instance,u=l.currentTarget,l=l.listener,s!==o&&a.isPropagationStopped())break e;Ar(a,l,u),o=s}}}if(Ze)throw e=Ve,Ze=!1,Ve=null,e}function Or(e,t){var n=oa(t),r=e+"__bubble";n.has(r)||(Pr(t,e,2,!1),n.add(r))}var Rr="_reactListening"+Math.random().toString(36).slice(2);function Nr(e){e[Rr]||(e[Rr]=!0,l.forEach((function(t){Cr.has(t)||Lr(t,!1,e,null),Lr(t,!0,e,null)})))}function Lr(e,t,n,r){var a=4<arguments.length&&void 0!==arguments[4]?arguments[4]:0,o=n;if("selectionchange"===e&&9!==n.nodeType&&(o=n.ownerDocument),null!==r&&!t&&Cr.has(e)){if("scroll"!==e)return;a|=2,o=r}var i=oa(o),l=e+"__"+(t?"capture":"bubble");i.has(l)||(t&&(a|=4),Pr(o,e,a,t),i.add(l))}function Pr(e,t,n,r){var a=Lt.get(t);switch(void 0===a?2:a){case 0:a=Kt;break;case 1:a=Xt;break;default:a=qt}n=a.bind(null,t,n,e),a=void 0,!$e||"touchstart"!==t&&"touchmove"!==t&&"wheel"!==t||(a=!0),r?void 0!==a?e.addEventListener(t,n,{capture:!0,passive:a}):e.addEventListener(t,n,!0):void 0!==a?e.addEventListener(t,n,{passive:a}):e.addEventListener(t,n,!1)}function xr(e,t,n,r,a){var o=r;if(0==(1&t)&&0==(2&t)&&null!==r)e:for(;;){if(null===r)return;var i=r.tag;if(3===i||4===i){var l=r.stateNode.containerInfo;if(l===a||8===l.nodeType&&l.parentNode===a)break;if(4===i)for(i=r.return;null!==i;){var s=i.tag;if((3===s||4===s)&&((s=i.stateNode.containerInfo)===a||8===s.nodeType&&s.parentNode===a))return;i=i.return}for(;null!==l;){if(null===(i=ta(l)))return;if(5===(s=i.tag)||6===s){r=o=i;continue e}l=l.parentNode}}r=r.return}!function(e,t,n){if(Ue)return e(t,n);Ue=!0;try{return De(e,t,n)}finally{Ue=!1,Fe()}}((function(){var r=o,a=ke(n),i=[];e:{var l=Nt.get(e);if(void 0!==l){var s=fn,u=e;switch(e){case"keypress":if(0===rn(n))break e;case"keydown":case"keyup":s=On;break;case"focusin":u="focus",s=vn;break;case"focusout":u="blur",s=vn;break;case"beforeblur":case"afterblur":s=vn;break;case"click":if(2===n.button)break e;case"auxclick":case"dblclick":case"mousedown":case"mousemove":case"mouseup":case"mouseout":case"mouseover":case"contextmenu":s=gn;break;case"drag":case"dragend":case"dragenter":case"dragexit":case"dragleave":case"dragover":case"dragstart":case"drop":s=bn;break;case"touchcancel":case"touchend":case"touchmove":case"touchstart":s=Nn;break;case At:case It:case Ot:s=yn;break;case Rt:s=Ln;break;case"scroll":s=mn;break;case"wheel":s=xn;break;case"copy":case"cut":case"paste":s=Sn;break;case"gotpointercapture":case"lostpointercapture":case"pointercancel":case"pointerdown":case"pointermove":case"pointerout":case"pointerover":case"pointerup":s=Rn}var c=0!=(4&t),d=!c&&"scroll"===e,f=c?null!==l?l+"Capture":null:l;c=[];for(var p,m=r;null!==m;){var h=(p=m).stateNode;if(5===p.tag&&null!==h&&(p=h,null!==f&&(null!=(h=Be(m,f))&&c.push(Dr(m,h,p)))),d)break;m=m.return}0<c.length&&(l=new s(l,u,null,n,a),i.push({event:l,listeners:c}))}}if(0==(7&t)){if(s="mouseout"===e||"pointerout"===e,(!(l="mouseover"===e||"pointerover"===e)||0!=(16&t)||!(u=n.relatedTarget||n.fromElement)||!ta(u)&&!u[Jr])&&(s||l)&&(l=a.window===a?a:(l=a.ownerDocument)?l.defaultView||l.parentWindow:window,s?(s=r,null!==(u=(u=n.relatedTarget||n.toElement)?ta(u):null)&&(u!==(d=Ke(u))||5!==u.tag&&6!==u.tag)&&(u=null)):(s=null,u=r),s!==u)){if(c=gn,h="onMouseLeave",f="onMouseEnter",m="mouse","pointerout"!==e&&"pointerover"!==e||(c=Rn,h="onPointerLeave",f="onPointerEnter",m="pointer"),d=null==s?l:ra(s),p=null==u?l:ra(u),(l=new c(h,m+"leave",s,n,a)).target=d,l.relatedTarget=p,h=null,ta(a)===r&&((c=new c(f,m+"enter",u,n,a)).target=p,c.relatedTarget=d,h=c),d=h,s&&u)e:{for(f=u,m=0,p=c=s;p;p=Ur(p))m++;for(p=0,h=f;h;h=Ur(h))p++;for(;0<m-p;)c=Ur(c),m--;for(;0<p-m;)f=Ur(f),p--;for(;m--;){if(c===f||null!==f&&c===f.alternate)break e;c=Ur(c),f=Ur(f)}c=null}else c=null;null!==s&&Fr(i,l,s,c,!1),null!==u&&null!==d&&Fr(i,d,u,c,!0)}if("select"===(s=(l=r?ra(r):window).nodeName&&l.nodeName.toLowerCase())||"input"===s&&"file"===l.type)var g=Qn;else if(Vn(l))if(Jn)g=sr;else{g=ir;var b=or}else(s=l.nodeName)&&"input"===s.toLowerCase()&&("checkbox"===l.type||"radio"===l.type)&&(g=lr);switch(g&&(g=g(e,r))?Wn(i,g,n,a):(b&&b(e,l,r),"focusout"===e&&(b=l._wrapperState)&&b.controlled&&"number"===l.type&&ae(l,"number",l.value)),b=r?ra(r):window,e){case"focusin":(Vn(b)||"true"===b.contentEditable)&&(vr=b,yr=r,Er=null);break;case"focusout":Er=yr=vr=null;break;case"mousedown":Sr=!0;break;case"contextmenu":case"mouseup":case"dragend":Sr=!1,_r(i,n,a);break;case"selectionchange":if(br)break;case"keydown":case"keyup":_r(i,n,a)}var v;if(Mn)e:{switch(e){case"compositionstart":var y="onCompositionStart";break e;case"compositionend":y="onCompositionEnd";break e;case"compositionupdate":y="onCompositionUpdate";break e}y=void 0}else Gn?Hn(e,n)&&(y="onCompositionEnd"):"keydown"===e&&229===n.keyCode&&(y="onCompositionStart");y&&(Bn&&"ko"!==n.locale&&(Gn||"onCompositionStart"!==y?"onCompositionEnd"===y&&Gn&&(v=nn()):(en="value"in(Jt=a)?Jt.value:Jt.textContent,Gn=!0)),0<(b=Mr(r,y)).length&&(y=new _n(y,e,null,n,a),i.push({event:y,listeners:b}),v?y.data=v:null!==(v=jn(n))&&(y.data=v))),(v=Fn?function(e,t){switch(e){case"compositionend":return jn(t);case"keypress":return 32!==t.which?null:(zn=!0,$n);case"textInput":return(e=t.data)===$n&&zn?null:e;default:return null}}(e,n):function(e,t){if(Gn)return"compositionend"===e||!Mn&&Hn(e,t)?(e=nn(),tn=en=Jt=null,Gn=!1,e):null;switch(e){case"paste":default:return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1<t.char.length)return t.char;if(t.which)return String.fromCharCode(t.which)}return null;case"compositionend":return Bn&&"ko"!==t.locale?null:t.data}}(e,n))&&(0<(r=Mr(r,"onBeforeInput")).length&&(a=new _n("onBeforeInput","beforeinput",null,n,a),i.push({event:a,listeners:r}),a.data=v))}Ir(i,t)}))}function Dr(e,t,n){return{instance:e,listener:t,currentTarget:n}}function Mr(e,t){for(var n=t+"Capture",r=[];null!==e;){var a=e,o=a.stateNode;5===a.tag&&null!==o&&(a=o,null!=(o=Be(e,n))&&r.unshift(Dr(e,o,a)),null!=(o=Be(e,t))&&r.push(Dr(e,o,a))),e=e.return}return r}function Ur(e){if(null===e)return null;do{e=e.return}while(e&&5!==e.tag);return e||null}function Fr(e,t,n,r,a){for(var o=t._reactName,i=[];null!==n&&n!==r;){var l=n,s=l.alternate,u=l.stateNode;if(null!==s&&s===r)break;5===l.tag&&null!==u&&(l=u,a?null!=(s=Be(n,o))&&i.unshift(Dr(n,s,l)):a||null!=(s=Be(n,o))&&i.push(Dr(n,s,l))),n=n.return}0!==i.length&&e.push({event:t,listeners:i})}function Br(){}var $r=null,zr=null;function Hr(e,t){switch(e){case"button":case"input":case"select":case"textarea":return!!t.autoFocus}return!1}function jr(e,t){return"textarea"===e||"option"===e||"noscript"===e||"string"==typeof t.children||"number"==typeof t.children||"object"==typeof t.dangerouslySetInnerHTML&&null!==t.dangerouslySetInnerHTML&&null!=t.dangerouslySetInnerHTML.__html}var Gr="function"==typeof setTimeout?setTimeout:void 0,Zr="function"==typeof clearTimeout?clearTimeout:void 0;function Vr(e){1===e.nodeType?e.textContent="":9===e.nodeType&&(null!=(e=e.body)&&(e.textContent=""))}function Wr(e){for(;null!=e;e=e.nextSibling){var t=e.nodeType;if(1===t||3===t)break}return e}function Yr(e){e=e.previousSibling;for(var t=0;e;){if(8===e.nodeType){var n=e.data;if("$"===n||"$!"===n||"$?"===n){if(0===t)return e;t--}else"/$"===n&&t++}e=e.previousSibling}return null}var Kr=0;var Xr=Math.random().toString(36).slice(2),qr="__reactFiber$"+Xr,Qr="__reactProps$"+Xr,Jr="__reactContainer$"+Xr,ea="__reactEvents$"+Xr;function ta(e){var t=e[qr];if(t)return t;for(var n=e.parentNode;n;){if(t=n[Jr]||n[qr]){if(n=t.alternate,null!==t.child||null!==n&&null!==n.child)for(e=Yr(e);null!==e;){if(n=e[qr])return n;e=Yr(e)}return t}n=(e=n).parentNode}return null}function na(e){return!(e=e[qr]||e[Jr])||5!==e.tag&&6!==e.tag&&13!==e.tag&&3!==e.tag?null:e}function ra(e){if(5===e.tag||6===e.tag)return e.stateNode;throw Error(i(33))}function aa(e){return e[Qr]||null}function oa(e){var t=e[ea];return void 0===t&&(t=e[ea]=new Set),t}var ia=[],la=-1;function sa(e){return{current:e}}function ua(e){0>la||(e.current=ia[la],ia[la]=null,la--)}function ca(e,t){la++,ia[la]=e.current,e.current=t}var da={},fa=sa(da),pa=sa(!1),ma=da;function ha(e,t){var n=e.type.contextTypes;if(!n)return da;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var a,o={};for(a in n)o[a]=t[a];return r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function ga(e){return null!=(e=e.childContextTypes)}function ba(){ua(pa),ua(fa)}function va(e,t,n){if(fa.current!==da)throw Error(i(168));ca(fa,t),ca(pa,n)}function ya(e,t,n){var r=e.stateNode;if(e=t.childContextTypes,"function"!=typeof r.getChildContext)return n;for(var o in r=r.getChildContext())if(!(o in e))throw Error(i(108,W(t)||"Unknown",o));return a({},n,r)}function Ea(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||da,ma=fa.current,ca(fa,e),ca(pa,pa.current),!0}function Sa(e,t,n){var r=e.stateNode;if(!r)throw Error(i(169));n?(e=ya(e,t,ma),r.__reactInternalMemoizedMergedChildContext=e,ua(pa),ua(fa),ca(fa,e)):ua(pa),ca(pa,n)}var _a=null,wa=null,Ta=o.unstable_runWithPriority,ka=o.unstable_scheduleCallback,Ca=o.unstable_cancelCallback,Aa=o.unstable_shouldYield,Ia=o.unstable_requestPaint,Oa=o.unstable_now,Ra=o.unstable_getCurrentPriorityLevel,Na=o.unstable_ImmediatePriority,La=o.unstable_UserBlockingPriority,Pa=o.unstable_NormalPriority,xa=o.unstable_LowPriority,Da=o.unstable_IdlePriority,Ma={},Ua=void 0!==Ia?Ia:function(){},Fa=null,Ba=null,$a=!1,za=Oa(),Ha=1e4>za?Oa:function(){return Oa()-za};function ja(){switch(Ra()){case Na:return 99;case La:return 98;case Pa:return 97;case xa:return 96;case Da:return 95;default:throw Error(i(332))}}function Ga(e){switch(e){case 99:return Na;case 98:return La;case 97:return Pa;case 96:return xa;case 95:return Da;default:throw Error(i(332))}}function Za(e,t){return e=Ga(e),Ta(e,t)}function Va(e,t,n){return e=Ga(e),ka(e,t,n)}function Wa(){if(null!==Ba){var e=Ba;Ba=null,Ca(e)}Ya()}function Ya(){if(!$a&&null!==Fa){$a=!0;var e=0;try{var t=Fa;Za(99,(function(){for(;e<t.length;e++){var n=t[e];do{n=n(!0)}while(null!==n)}})),Fa=null}catch(n){throw null!==Fa&&(Fa=Fa.slice(e+1)),ka(Na,Wa),n}finally{$a=!1}}}var Ka=S.ReactCurrentBatchConfig;function Xa(e,t){if(e&&e.defaultProps){for(var n in t=a({},t),e=e.defaultProps)void 0===t[n]&&(t[n]=e[n]);return t}return t}var qa=sa(null),Qa=null,Ja=null,eo=null;function to(){eo=Ja=Qa=null}function no(e){var t=qa.current;ua(qa),e.type._context._currentValue=t}function ro(e,t){for(;null!==e;){var n=e.alternate;if((e.childLanes&t)===t){if(null===n||(n.childLanes&t)===t)break;n.childLanes|=t}else e.childLanes|=t,null!==n&&(n.childLanes|=t);e=e.return}}function ao(e,t){Qa=e,eo=Ja=null,null!==(e=e.dependencies)&&null!==e.firstContext&&(0!=(e.lanes&t)&&(Mi=!0),e.firstContext=null)}function oo(e,t){if(eo!==e&&!1!==t&&0!==t)if("number"==typeof t&&1073741823!==t||(eo=e,t=1073741823),t={context:e,observedBits:t,next:null},null===Ja){if(null===Qa)throw Error(i(308));Ja=t,Qa.dependencies={lanes:0,firstContext:t,responders:null}}else Ja=Ja.next=t;return e._currentValue}var io=!1;function lo(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null},effects:null}}function so(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function uo(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function co(e,t){if(null!==(e=e.updateQueue)){var n=(e=e.shared).pending;null===n?t.next=t:(t.next=n.next,n.next=t),e.pending=t}}function fo(e,t){var n=e.updateQueue,r=e.alternate;if(null!==r&&n===(r=r.updateQueue)){var a=null,o=null;if(null!==(n=n.firstBaseUpdate)){do{var i={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};null===o?a=o=i:o=o.next=i,n=n.next}while(null!==n);null===o?a=o=t:o=o.next=t}else a=o=t;return n={baseState:r.baseState,firstBaseUpdate:a,lastBaseUpdate:o,shared:r.shared,effects:r.effects},void(e.updateQueue=n)}null===(e=n.lastBaseUpdate)?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function po(e,t,n,r){var o=e.updateQueue;io=!1;var i=o.firstBaseUpdate,l=o.lastBaseUpdate,s=o.shared.pending;if(null!==s){o.shared.pending=null;var u=s,c=u.next;u.next=null,null===l?i=c:l.next=c,l=u;var d=e.alternate;if(null!==d){var f=(d=d.updateQueue).lastBaseUpdate;f!==l&&(null===f?d.firstBaseUpdate=c:f.next=c,d.lastBaseUpdate=u)}}if(null!==i){for(f=o.baseState,l=0,d=c=u=null;;){s=i.lane;var p=i.eventTime;if((r&s)===s){null!==d&&(d=d.next={eventTime:p,lane:0,tag:i.tag,payload:i.payload,callback:i.callback,next:null});e:{var m=e,h=i;switch(s=t,p=n,h.tag){case 1:if("function"==typeof(m=h.payload)){f=m.call(p,f,s);break e}f=m;break e;case 3:m.flags=-4097&m.flags|64;case 0:if(null==(s="function"==typeof(m=h.payload)?m.call(p,f,s):m))break e;f=a({},f,s);break e;case 2:io=!0}}null!==i.callback&&(e.flags|=32,null===(s=o.effects)?o.effects=[i]:s.push(i))}else p={eventTime:p,lane:s,tag:i.tag,payload:i.payload,callback:i.callback,next:null},null===d?(c=d=p,u=f):d=d.next=p,l|=s;if(null===(i=i.next)){if(null===(s=o.shared.pending))break;i=s.next,s.next=null,o.lastBaseUpdate=s,o.shared.pending=null}}null===d&&(u=f),o.baseState=u,o.firstBaseUpdate=c,o.lastBaseUpdate=d,zl|=l,e.lanes=l,e.memoizedState=f}}function mo(e,t,n){if(e=t.effects,t.effects=null,null!==e)for(t=0;t<e.length;t++){var r=e[t],a=r.callback;if(null!==a){if(r.callback=null,r=n,"function"!=typeof a)throw Error(i(191,a));a.call(r)}}}var ho=(new r.Component).refs;function go(e,t,n,r){n=null==(n=n(r,t=e.memoizedState))?t:a({},t,n),e.memoizedState=n,0===e.lanes&&(e.updateQueue.baseState=n)}var bo={isMounted:function(e){return!!(e=e._reactInternals)&&Ke(e)===e},enqueueSetState:function(e,t,n){e=e._reactInternals;var r=fs(),a=ps(e),o=uo(r,a);o.payload=t,null!=n&&(o.callback=n),co(e,o),ms(e,a,r)},enqueueReplaceState:function(e,t,n){e=e._reactInternals;var r=fs(),a=ps(e),o=uo(r,a);o.tag=1,o.payload=t,null!=n&&(o.callback=n),co(e,o),ms(e,a,r)},enqueueForceUpdate:function(e,t){e=e._reactInternals;var n=fs(),r=ps(e),a=uo(n,r);a.tag=2,null!=t&&(a.callback=t),co(e,a),ms(e,r,n)}};function vo(e,t,n,r,a,o,i){return"function"==typeof(e=e.stateNode).shouldComponentUpdate?e.shouldComponentUpdate(r,o,i):!t.prototype||!t.prototype.isPureReactComponent||(!dr(n,r)||!dr(a,o))}function yo(e,t,n){var r=!1,a=da,o=t.contextType;return"object"==typeof o&&null!==o?o=oo(o):(a=ga(t)?ma:fa.current,o=(r=null!=(r=t.contextTypes))?ha(e,a):da),t=new t(n,o),e.memoizedState=null!==t.state&&void 0!==t.state?t.state:null,t.updater=bo,e.stateNode=t,t._reactInternals=e,r&&((e=e.stateNode).__reactInternalMemoizedUnmaskedChildContext=a,e.__reactInternalMemoizedMaskedChildContext=o),t}function Eo(e,t,n,r){e=t.state,"function"==typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"==typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&bo.enqueueReplaceState(t,t.state,null)}function So(e,t,n,r){var a=e.stateNode;a.props=n,a.state=e.memoizedState,a.refs=ho,lo(e);var o=t.contextType;"object"==typeof o&&null!==o?a.context=oo(o):(o=ga(t)?ma:fa.current,a.context=ha(e,o)),po(e,n,a,r),a.state=e.memoizedState,"function"==typeof(o=t.getDerivedStateFromProps)&&(go(e,t,o,n),a.state=e.memoizedState),"function"==typeof t.getDerivedStateFromProps||"function"==typeof a.getSnapshotBeforeUpdate||"function"!=typeof a.UNSAFE_componentWillMount&&"function"!=typeof a.componentWillMount||(t=a.state,"function"==typeof a.componentWillMount&&a.componentWillMount(),"function"==typeof a.UNSAFE_componentWillMount&&a.UNSAFE_componentWillMount(),t!==a.state&&bo.enqueueReplaceState(a,a.state,null),po(e,n,a,r),a.state=e.memoizedState),"function"==typeof a.componentDidMount&&(e.flags|=4)}var _o=Array.isArray;function wo(e,t,n){if(null!==(e=n.ref)&&"function"!=typeof e&&"object"!=typeof e){if(n._owner){if(n=n._owner){if(1!==n.tag)throw Error(i(309));var r=n.stateNode}if(!r)throw Error(i(147,e));var a=""+e;return null!==t&&null!==t.ref&&"function"==typeof t.ref&&t.ref._stringRef===a?t.ref:(t=function(e){var t=r.refs;t===ho&&(t=r.refs={}),null===e?delete t[a]:t[a]=e},t._stringRef=a,t)}if("string"!=typeof e)throw Error(i(284));if(!n._owner)throw Error(i(290,e))}return e}function To(e,t){if("textarea"!==e.type)throw Error(i(31,"[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t))}function ko(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.flags=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function r(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function a(e,t){return(e=Vs(e,t)).index=0,e.sibling=null,e}function o(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index)<n?(t.flags=2,n):r:(t.flags=2,n):n}function l(t){return e&&null===t.alternate&&(t.flags=2),t}function s(e,t,n,r){return null===t||6!==t.tag?((t=Xs(n,e.mode,r)).return=e,t):((t=a(t,n)).return=e,t)}function u(e,t,n,r){return null!==t&&t.elementType===n.type?((r=a(t,n.props)).ref=wo(e,t,n),r.return=e,r):((r=Ws(n.type,n.key,n.props,null,e.mode,r)).ref=wo(e,t,n),r.return=e,r)}function c(e,t,n,r){return null===t||4!==t.tag||t.stateNode.containerInfo!==n.containerInfo||t.stateNode.implementation!==n.implementation?((t=qs(n,e.mode,r)).return=e,t):((t=a(t,n.children||[])).return=e,t)}function d(e,t,n,r,o){return null===t||7!==t.tag?((t=Ys(n,e.mode,r,o)).return=e,t):((t=a(t,n)).return=e,t)}function f(e,t,n){if("string"==typeof t||"number"==typeof t)return(t=Xs(""+t,e.mode,n)).return=e,t;if("object"==typeof t&&null!==t){switch(t.$$typeof){case _:return(n=Ws(t.type,t.key,t.props,null,e.mode,n)).ref=wo(e,null,t),n.return=e,n;case w:return(t=qs(t,e.mode,n)).return=e,t}if(_o(t)||H(t))return(t=Ys(t,e.mode,n,null)).return=e,t;To(e,t)}return null}function p(e,t,n,r){var a=null!==t?t.key:null;if("string"==typeof n||"number"==typeof n)return null!==a?null:s(e,t,""+n,r);if("object"==typeof n&&null!==n){switch(n.$$typeof){case _:return n.key===a?n.type===T?d(e,t,n.props.children,r,a):u(e,t,n,r):null;case w:return n.key===a?c(e,t,n,r):null}if(_o(n)||H(n))return null!==a?null:d(e,t,n,r,null);To(e,n)}return null}function m(e,t,n,r,a){if("string"==typeof r||"number"==typeof r)return s(t,e=e.get(n)||null,""+r,a);if("object"==typeof r&&null!==r){switch(r.$$typeof){case _:return e=e.get(null===r.key?n:r.key)||null,r.type===T?d(t,e,r.props.children,a,r.key):u(t,e,r,a);case w:return c(t,e=e.get(null===r.key?n:r.key)||null,r,a)}if(_o(r)||H(r))return d(t,e=e.get(n)||null,r,a,null);To(t,r)}return null}function h(a,i,l,s){for(var u=null,c=null,d=i,h=i=0,g=null;null!==d&&h<l.length;h++){d.index>h?(g=d,d=null):g=d.sibling;var b=p(a,d,l[h],s);if(null===b){null===d&&(d=g);break}e&&d&&null===b.alternate&&t(a,d),i=o(b,i,h),null===c?u=b:c.sibling=b,c=b,d=g}if(h===l.length)return n(a,d),u;if(null===d){for(;h<l.length;h++)null!==(d=f(a,l[h],s))&&(i=o(d,i,h),null===c?u=d:c.sibling=d,c=d);return u}for(d=r(a,d);h<l.length;h++)null!==(g=m(d,a,h,l[h],s))&&(e&&null!==g.alternate&&d.delete(null===g.key?h:g.key),i=o(g,i,h),null===c?u=g:c.sibling=g,c=g);return e&&d.forEach((function(e){return t(a,e)})),u}function g(a,l,s,u){var c=H(s);if("function"!=typeof c)throw Error(i(150));if(null==(s=c.call(s)))throw Error(i(151));for(var d=c=null,h=l,g=l=0,b=null,v=s.next();null!==h&&!v.done;g++,v=s.next()){h.index>g?(b=h,h=null):b=h.sibling;var y=p(a,h,v.value,u);if(null===y){null===h&&(h=b);break}e&&h&&null===y.alternate&&t(a,h),l=o(y,l,g),null===d?c=y:d.sibling=y,d=y,h=b}if(v.done)return n(a,h),c;if(null===h){for(;!v.done;g++,v=s.next())null!==(v=f(a,v.value,u))&&(l=o(v,l,g),null===d?c=v:d.sibling=v,d=v);return c}for(h=r(a,h);!v.done;g++,v=s.next())null!==(v=m(h,a,g,v.value,u))&&(e&&null!==v.alternate&&h.delete(null===v.key?g:v.key),l=o(v,l,g),null===d?c=v:d.sibling=v,d=v);return e&&h.forEach((function(e){return t(a,e)})),c}return function(e,r,o,s){var u="object"==typeof o&&null!==o&&o.type===T&&null===o.key;u&&(o=o.props.children);var c="object"==typeof o&&null!==o;if(c)switch(o.$$typeof){case _:e:{for(c=o.key,u=r;null!==u;){if(u.key===c){if(7===u.tag){if(o.type===T){n(e,u.sibling),(r=a(u,o.props.children)).return=e,e=r;break e}}else if(u.elementType===o.type){n(e,u.sibling),(r=a(u,o.props)).ref=wo(e,u,o),r.return=e,e=r;break e}n(e,u);break}t(e,u),u=u.sibling}o.type===T?((r=Ys(o.props.children,e.mode,s,o.key)).return=e,e=r):((s=Ws(o.type,o.key,o.props,null,e.mode,s)).ref=wo(e,r,o),s.return=e,e=s)}return l(e);case w:e:{for(u=o.key;null!==r;){if(r.key===u){if(4===r.tag&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),(r=a(r,o.children||[])).return=e,e=r;break e}n(e,r);break}t(e,r),r=r.sibling}(r=qs(o,e.mode,s)).return=e,e=r}return l(e)}if("string"==typeof o||"number"==typeof o)return o=""+o,null!==r&&6===r.tag?(n(e,r.sibling),(r=a(r,o)).return=e,e=r):(n(e,r),(r=Xs(o,e.mode,s)).return=e,e=r),l(e);if(_o(o))return h(e,r,o,s);if(H(o))return g(e,r,o,s);if(c&&To(e,o),void 0===o&&!u)switch(e.tag){case 1:case 22:case 0:case 11:case 15:throw Error(i(152,W(e.type)||"Component"))}return n(e,r)}}var Co=ko(!0),Ao=ko(!1),Io={},Oo=sa(Io),Ro=sa(Io),No=sa(Io);function Lo(e){if(e===Io)throw Error(i(174));return e}function Po(e,t){switch(ca(No,t),ca(Ro,e),ca(Oo,Io),e=t.nodeType){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:pe(null,"");break;default:t=pe(t=(e=8===e?t.parentNode:t).namespaceURI||null,e=e.tagName)}ua(Oo),ca(Oo,t)}function xo(){ua(Oo),ua(Ro),ua(No)}function Do(e){Lo(No.current);var t=Lo(Oo.current),n=pe(t,e.type);t!==n&&(ca(Ro,e),ca(Oo,n))}function Mo(e){Ro.current===e&&(ua(Oo),ua(Ro))}var Uo=sa(0);function Fo(e){for(var t=e;null!==t;){if(13===t.tag){var n=t.memoizedState;if(null!==n&&(null===(n=n.dehydrated)||"$?"===n.data||"$!"===n.data))return t}else if(19===t.tag&&void 0!==t.memoizedProps.revealOrder){if(0!=(64&t.flags))return t}else if(null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Bo=null,$o=null,zo=!1;function Ho(e,t){var n=Gs(5,null,null,0);n.elementType="DELETED",n.type="DELETED",n.stateNode=t,n.return=e,n.flags=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function jo(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function Go(e){if(zo){var t=$o;if(t){var n=t;if(!jo(e,t)){if(!(t=Wr(n.nextSibling))||!jo(e,t))return e.flags=-1025&e.flags|2,zo=!1,void(Bo=e);Ho(Bo,n)}Bo=e,$o=Wr(t.firstChild)}else e.flags=-1025&e.flags|2,zo=!1,Bo=e}}function Zo(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag&&13!==e.tag;)e=e.return;Bo=e}function Vo(e){if(e!==Bo)return!1;if(!zo)return Zo(e),zo=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!jr(t,e.memoizedProps))for(t=$o;t;)Ho(e,t),t=Wr(t.nextSibling);if(Zo(e),13===e.tag){if(!(e=null!==(e=e.memoizedState)?e.dehydrated:null))throw Error(i(317));e:{for(e=e.nextSibling,t=0;e;){if(8===e.nodeType){var n=e.data;if("/$"===n){if(0===t){$o=Wr(e.nextSibling);break e}t--}else"$"!==n&&"$!"!==n&&"$?"!==n||t++}e=e.nextSibling}$o=null}}else $o=Bo?Wr(e.stateNode.nextSibling):null;return!0}function Wo(){$o=Bo=null,zo=!1}var Yo=[];function Ko(){for(var e=0;e<Yo.length;e++)Yo[e]._workInProgressVersionPrimary=null;Yo.length=0}var Xo=S.ReactCurrentDispatcher,qo=S.ReactCurrentBatchConfig,Qo=0,Jo=null,ei=null,ti=null,ni=!1,ri=!1;function ai(){throw Error(i(321))}function oi(e,t){if(null===t)return!1;for(var n=0;n<t.length&&n<e.length;n++)if(!ur(e[n],t[n]))return!1;return!0}function ii(e,t,n,r,a,o){if(Qo=o,Jo=t,t.memoizedState=null,t.updateQueue=null,t.lanes=0,Xo.current=null===e||null===e.memoizedState?Li:Pi,e=n(r,a),ri){o=0;do{if(ri=!1,!(25>o))throw Error(i(301));o+=1,ti=ei=null,t.updateQueue=null,Xo.current=xi,e=n(r,a)}while(ri)}if(Xo.current=Ni,t=null!==ei&&null!==ei.next,Qo=0,ti=ei=Jo=null,ni=!1,t)throw Error(i(300));return e}function li(){var e={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};return null===ti?Jo.memoizedState=ti=e:ti=ti.next=e,ti}function si(){if(null===ei){var e=Jo.alternate;e=null!==e?e.memoizedState:null}else e=ei.next;var t=null===ti?Jo.memoizedState:ti.next;if(null!==t)ti=t,ei=e;else{if(null===e)throw Error(i(310));e={memoizedState:(ei=e).memoizedState,baseState:ei.baseState,baseQueue:ei.baseQueue,queue:ei.queue,next:null},null===ti?Jo.memoizedState=ti=e:ti=ti.next=e}return ti}function ui(e,t){return"function"==typeof t?t(e):t}function ci(e){var t=si(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=ei,a=r.baseQueue,o=n.pending;if(null!==o){if(null!==a){var l=a.next;a.next=o.next,o.next=l}r.baseQueue=a=o,n.pending=null}if(null!==a){a=a.next,r=r.baseState;var s=l=o=null,u=a;do{var c=u.lane;if((Qo&c)===c)null!==s&&(s=s.next={lane:0,action:u.action,eagerReducer:u.eagerReducer,eagerState:u.eagerState,next:null}),r=u.eagerReducer===e?u.eagerState:e(r,u.action);else{var d={lane:c,action:u.action,eagerReducer:u.eagerReducer,eagerState:u.eagerState,next:null};null===s?(l=s=d,o=r):s=s.next=d,Jo.lanes|=c,zl|=c}u=u.next}while(null!==u&&u!==a);null===s?o=r:s.next=l,ur(r,t.memoizedState)||(Mi=!0),t.memoizedState=r,t.baseState=o,t.baseQueue=s,n.lastRenderedState=r}return[t.memoizedState,n.dispatch]}function di(e){var t=si(),n=t.queue;if(null===n)throw Error(i(311));n.lastRenderedReducer=e;var r=n.dispatch,a=n.pending,o=t.memoizedState;if(null!==a){n.pending=null;var l=a=a.next;do{o=e(o,l.action),l=l.next}while(l!==a);ur(o,t.memoizedState)||(Mi=!0),t.memoizedState=o,null===t.baseQueue&&(t.baseState=o),n.lastRenderedState=o}return[o,r]}function fi(e,t,n){var r=t._getVersion;r=r(t._source);var a=t._workInProgressVersionPrimary;if(null!==a?e=a===r:(e=e.mutableReadLanes,(e=(Qo&e)===e)&&(t._workInProgressVersionPrimary=r,Yo.push(t))),e)return n(t._source);throw Yo.push(t),Error(i(350))}function pi(e,t,n,r){var a=Pl;if(null===a)throw Error(i(349));var o=t._getVersion,l=o(t._source),s=Xo.current,u=s.useState((function(){return fi(a,t,n)})),c=u[1],d=u[0];u=ti;var f=e.memoizedState,p=f.refs,m=p.getSnapshot,h=f.source;f=f.subscribe;var g=Jo;return e.memoizedState={refs:p,source:t,subscribe:r},s.useEffect((function(){p.getSnapshot=n,p.setSnapshot=c;var e=o(t._source);if(!ur(l,e)){e=n(t._source),ur(d,e)||(c(e),e=ps(g),a.mutableReadLanes|=e&a.pendingLanes),e=a.mutableReadLanes,a.entangledLanes|=e;for(var r=a.entanglements,i=e;0<i;){var s=31-jt(i),u=1<<s;r[s]|=e,i&=~u}}}),[n,t,r]),s.useEffect((function(){return r(t._source,(function(){var e=p.getSnapshot,n=p.setSnapshot;try{n(e(t._source));var r=ps(g);a.mutableReadLanes|=r&a.pendingLanes}catch(o){n((function(){throw o}))}}))}),[t,r]),ur(m,n)&&ur(h,t)&&ur(f,r)||((e={pending:null,dispatch:null,lastRenderedReducer:ui,lastRenderedState:d}).dispatch=c=Ri.bind(null,Jo,e),u.queue=e,u.baseQueue=null,d=fi(a,t,n),u.memoizedState=u.baseState=d),d}function mi(e,t,n){return pi(si(),e,t,n)}function hi(e){var t=li();return"function"==typeof e&&(e=e()),t.memoizedState=t.baseState=e,e=(e=t.queue={pending:null,dispatch:null,lastRenderedReducer:ui,lastRenderedState:e}).dispatch=Ri.bind(null,Jo,e),[t.memoizedState,e]}function gi(e,t,n,r){return e={tag:e,create:t,destroy:n,deps:r,next:null},null===(t=Jo.updateQueue)?(t={lastEffect:null},Jo.updateQueue=t,t.lastEffect=e.next=e):null===(n=t.lastEffect)?t.lastEffect=e.next=e:(r=n.next,n.next=e,e.next=r,t.lastEffect=e),e}function bi(e){return e={current:e},li().memoizedState=e}function vi(){return si().memoizedState}function yi(e,t,n,r){var a=li();Jo.flags|=e,a.memoizedState=gi(1|t,n,void 0,void 0===r?null:r)}function Ei(e,t,n,r){var a=si();r=void 0===r?null:r;var o=void 0;if(null!==ei){var i=ei.memoizedState;if(o=i.destroy,null!==r&&oi(r,i.deps))return void gi(t,n,o,r)}Jo.flags|=e,a.memoizedState=gi(1|t,n,o,r)}function Si(e,t){return yi(516,4,e,t)}function _i(e,t){return Ei(516,4,e,t)}function wi(e,t){return Ei(4,2,e,t)}function Ti(e,t){return"function"==typeof t?(e=e(),t(e),function(){t(null)}):null!=t?(e=e(),t.current=e,function(){t.current=null}):void 0}function ki(e,t,n){return n=null!=n?n.concat([e]):null,Ei(4,2,Ti.bind(null,t,e),n)}function Ci(){}function Ai(e,t){var n=si();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&oi(t,r[1])?r[0]:(n.memoizedState=[e,t],e)}function Ii(e,t){var n=si();t=void 0===t?null:t;var r=n.memoizedState;return null!==r&&null!==t&&oi(t,r[1])?r[0]:(e=e(),n.memoizedState=[e,t],e)}function Oi(e,t){var n=ja();Za(98>n?98:n,(function(){e(!0)})),Za(97<n?97:n,(function(){var n=qo.transition;qo.transition=1;try{e(!1),t()}finally{qo.transition=n}}))}function Ri(e,t,n){var r=fs(),a=ps(e),o={lane:a,action:n,eagerReducer:null,eagerState:null,next:null},i=t.pending;if(null===i?o.next=o:(o.next=i.next,i.next=o),t.pending=o,i=e.alternate,e===Jo||null!==i&&i===Jo)ri=ni=!0;else{if(0===e.lanes&&(null===i||0===i.lanes)&&null!==(i=t.lastRenderedReducer))try{var l=t.lastRenderedState,s=i(l,n);if(o.eagerReducer=i,o.eagerState=s,ur(s,l))return}catch(u){}ms(e,a,r)}}var Ni={readContext:oo,useCallback:ai,useContext:ai,useEffect:ai,useImperativeHandle:ai,useLayoutEffect:ai,useMemo:ai,useReducer:ai,useRef:ai,useState:ai,useDebugValue:ai,useDeferredValue:ai,useTransition:ai,useMutableSource:ai,useOpaqueIdentifier:ai,unstable_isNewReconciler:!1},Li={readContext:oo,useCallback:function(e,t){return li().memoizedState=[e,void 0===t?null:t],e},useContext:oo,useEffect:Si,useImperativeHandle:function(e,t,n){return n=null!=n?n.concat([e]):null,yi(4,2,Ti.bind(null,t,e),n)},useLayoutEffect:function(e,t){return yi(4,2,e,t)},useMemo:function(e,t){var n=li();return t=void 0===t?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=li();return t=void 0!==n?n(t):t,r.memoizedState=r.baseState=t,e=(e=r.queue={pending:null,dispatch:null,lastRenderedReducer:e,lastRenderedState:t}).dispatch=Ri.bind(null,Jo,e),[r.memoizedState,e]},useRef:bi,useState:hi,useDebugValue:Ci,useDeferredValue:function(e){var t=hi(e),n=t[0],r=t[1];return Si((function(){var t=qo.transition;qo.transition=1;try{r(e)}finally{qo.transition=t}}),[e]),n},useTransition:function(){var e=hi(!1),t=e[0];return bi(e=Oi.bind(null,e[1])),[e,t]},useMutableSource:function(e,t,n){var r=li();return r.memoizedState={refs:{getSnapshot:t,setSnapshot:null},source:e,subscribe:n},pi(r,e,t,n)},useOpaqueIdentifier:function(){if(zo){var e=!1,t=function(e){return{$$typeof:D,toString:e,valueOf:e}}((function(){throw e||(e=!0,n("r:"+(Kr++).toString(36))),Error(i(355))})),n=hi(t)[1];return 0==(2&Jo.mode)&&(Jo.flags|=516,gi(5,(function(){n("r:"+(Kr++).toString(36))}),void 0,null)),t}return hi(t="r:"+(Kr++).toString(36)),t},unstable_isNewReconciler:!1},Pi={readContext:oo,useCallback:Ai,useContext:oo,useEffect:_i,useImperativeHandle:ki,useLayoutEffect:wi,useMemo:Ii,useReducer:ci,useRef:vi,useState:function(){return ci(ui)},useDebugValue:Ci,useDeferredValue:function(e){var t=ci(ui),n=t[0],r=t[1];return _i((function(){var t=qo.transition;qo.transition=1;try{r(e)}finally{qo.transition=t}}),[e]),n},useTransition:function(){var e=ci(ui)[0];return[vi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return ci(ui)[0]},unstable_isNewReconciler:!1},xi={readContext:oo,useCallback:Ai,useContext:oo,useEffect:_i,useImperativeHandle:ki,useLayoutEffect:wi,useMemo:Ii,useReducer:di,useRef:vi,useState:function(){return di(ui)},useDebugValue:Ci,useDeferredValue:function(e){var t=di(ui),n=t[0],r=t[1];return _i((function(){var t=qo.transition;qo.transition=1;try{r(e)}finally{qo.transition=t}}),[e]),n},useTransition:function(){var e=di(ui)[0];return[vi().current,e]},useMutableSource:mi,useOpaqueIdentifier:function(){return di(ui)[0]},unstable_isNewReconciler:!1},Di=S.ReactCurrentOwner,Mi=!1;function Ui(e,t,n,r){t.child=null===e?Ao(t,null,n,r):Co(t,e.child,n,r)}function Fi(e,t,n,r,a){n=n.render;var o=t.ref;return ao(t,a),r=ii(e,t,n,r,o,a),null===e||Mi?(t.flags|=1,Ui(e,t,r,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,ol(e,t,a))}function Bi(e,t,n,r,a,o){if(null===e){var i=n.type;return"function"!=typeof i||Zs(i)||void 0!==i.defaultProps||null!==n.compare||void 0!==n.defaultProps?((e=Ws(n.type,null,r,t,t.mode,o)).ref=t.ref,e.return=t,t.child=e):(t.tag=15,t.type=i,$i(e,t,i,r,a,o))}return i=e.child,0==(a&o)&&(a=i.memoizedProps,(n=null!==(n=n.compare)?n:dr)(a,r)&&e.ref===t.ref)?ol(e,t,o):(t.flags|=1,(e=Vs(i,r)).ref=t.ref,e.return=t,t.child=e)}function $i(e,t,n,r,a,o){if(null!==e&&dr(e.memoizedProps,r)&&e.ref===t.ref){if(Mi=!1,0==(o&a))return t.lanes=e.lanes,ol(e,t,o);0!=(16384&e.flags)&&(Mi=!0)}return ji(e,t,n,r,o)}function zi(e,t,n){var r=t.pendingProps,a=r.children,o=null!==e?e.memoizedState:null;if("hidden"===r.mode||"unstable-defer-without-hiding"===r.mode)if(0==(4&t.mode))t.memoizedState={baseLanes:0},_s(t,n);else{if(0==(1073741824&n))return e=null!==o?o.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e},_s(t,e),null;t.memoizedState={baseLanes:0},_s(t,null!==o?o.baseLanes:n)}else null!==o?(r=o.baseLanes|n,t.memoizedState=null):r=n,_s(t,r);return Ui(e,t,a,n),t.child}function Hi(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.flags|=128)}function ji(e,t,n,r,a){var o=ga(n)?ma:fa.current;return o=ha(t,o),ao(t,a),n=ii(e,t,n,r,o,a),null===e||Mi?(t.flags|=1,Ui(e,t,n,a),t.child):(t.updateQueue=e.updateQueue,t.flags&=-517,e.lanes&=~a,ol(e,t,a))}function Gi(e,t,n,r,a){if(ga(n)){var o=!0;Ea(t)}else o=!1;if(ao(t,a),null===t.stateNode)null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),yo(t,n,r),So(t,n,r,a),r=!0;else if(null===e){var i=t.stateNode,l=t.memoizedProps;i.props=l;var s=i.context,u=n.contextType;"object"==typeof u&&null!==u?u=oo(u):u=ha(t,u=ga(n)?ma:fa.current);var c=n.getDerivedStateFromProps,d="function"==typeof c||"function"==typeof i.getSnapshotBeforeUpdate;d||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==r||s!==u)&&Eo(t,i,r,u),io=!1;var f=t.memoizedState;i.state=f,po(t,r,i,a),s=t.memoizedState,l!==r||f!==s||pa.current||io?("function"==typeof c&&(go(t,n,c,r),s=t.memoizedState),(l=io||vo(t,n,l,r,f,s,u))?(d||"function"!=typeof i.UNSAFE_componentWillMount&&"function"!=typeof i.componentWillMount||("function"==typeof i.componentWillMount&&i.componentWillMount(),"function"==typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"==typeof i.componentDidMount&&(t.flags|=4)):("function"==typeof i.componentDidMount&&(t.flags|=4),t.memoizedProps=r,t.memoizedState=s),i.props=r,i.state=s,i.context=u,r=l):("function"==typeof i.componentDidMount&&(t.flags|=4),r=!1)}else{i=t.stateNode,so(e,t),l=t.memoizedProps,u=t.type===t.elementType?l:Xa(t.type,l),i.props=u,d=t.pendingProps,f=i.context,"object"==typeof(s=n.contextType)&&null!==s?s=oo(s):s=ha(t,s=ga(n)?ma:fa.current);var p=n.getDerivedStateFromProps;(c="function"==typeof p||"function"==typeof i.getSnapshotBeforeUpdate)||"function"!=typeof i.UNSAFE_componentWillReceiveProps&&"function"!=typeof i.componentWillReceiveProps||(l!==d||f!==s)&&Eo(t,i,r,s),io=!1,f=t.memoizedState,i.state=f,po(t,r,i,a);var m=t.memoizedState;l!==d||f!==m||pa.current||io?("function"==typeof p&&(go(t,n,p,r),m=t.memoizedState),(u=io||vo(t,n,u,r,f,m,s))?(c||"function"!=typeof i.UNSAFE_componentWillUpdate&&"function"!=typeof i.componentWillUpdate||("function"==typeof i.componentWillUpdate&&i.componentWillUpdate(r,m,s),"function"==typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(r,m,s)),"function"==typeof i.componentDidUpdate&&(t.flags|=4),"function"==typeof i.getSnapshotBeforeUpdate&&(t.flags|=256)):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=256),t.memoizedProps=r,t.memoizedState=m),i.props=r,i.state=m,i.context=s,r=u):("function"!=typeof i.componentDidUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=4),"function"!=typeof i.getSnapshotBeforeUpdate||l===e.memoizedProps&&f===e.memoizedState||(t.flags|=256),r=!1)}return Zi(e,t,n,r,o,a)}function Zi(e,t,n,r,a,o){Hi(e,t);var i=0!=(64&t.flags);if(!r&&!i)return a&&Sa(t,n,!1),ol(e,t,o);r=t.stateNode,Di.current=t;var l=i&&"function"!=typeof n.getDerivedStateFromError?null:r.render();return t.flags|=1,null!==e&&i?(t.child=Co(t,e.child,null,o),t.child=Co(t,null,l,o)):Ui(e,t,l,o),t.memoizedState=r.state,a&&Sa(t,n,!0),t.child}function Vi(e){var t=e.stateNode;t.pendingContext?va(0,t.pendingContext,t.pendingContext!==t.context):t.context&&va(0,t.context,!1),Po(e,t.containerInfo)}var Wi,Yi,Ki,Xi,qi={dehydrated:null,retryLane:0};function Qi(e,t,n){var r,a=t.pendingProps,o=Uo.current,i=!1;return(r=0!=(64&t.flags))||(r=(null===e||null!==e.memoizedState)&&0!=(2&o)),r?(i=!0,t.flags&=-65):null!==e&&null===e.memoizedState||void 0===a.fallback||!0===a.unstable_avoidThisFallback||(o|=1),ca(Uo,1&o),null===e?(void 0!==a.fallback&&Go(t),e=a.children,o=a.fallback,i?(e=Ji(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=qi,e):"number"==typeof a.unstable_expectedLoadTime?(e=Ji(t,e,o,n),t.child.memoizedState={baseLanes:n},t.memoizedState=qi,t.lanes=33554432,e):((n=Ks({mode:"visible",children:e},t.mode,n,null)).return=t,t.child=n)):(e.memoizedState,i?(a=tl(e,t,a.children,a.fallback,n),i=t.child,o=e.child.memoizedState,i.memoizedState=null===o?{baseLanes:n}:{baseLanes:o.baseLanes|n},i.childLanes=e.childLanes&~n,t.memoizedState=qi,a):(n=el(e,t,a.children,n),t.memoizedState=null,n))}function Ji(e,t,n,r){var a=e.mode,o=e.child;return t={mode:"hidden",children:t},0==(2&a)&&null!==o?(o.childLanes=0,o.pendingProps=t):o=Ks(t,a,0,null),n=Ys(n,a,r,null),o.return=e,n.return=e,o.sibling=n,e.child=o,n}function el(e,t,n,r){var a=e.child;return e=a.sibling,n=Vs(a,{mode:"visible",children:n}),0==(2&t.mode)&&(n.lanes=r),n.return=t,n.sibling=null,null!==e&&(e.nextEffect=null,e.flags=8,t.firstEffect=t.lastEffect=e),t.child=n}function tl(e,t,n,r,a){var o=t.mode,i=e.child;e=i.sibling;var l={mode:"hidden",children:n};return 0==(2&o)&&t.child!==i?((n=t.child).childLanes=0,n.pendingProps=l,null!==(i=n.lastEffect)?(t.firstEffect=n.firstEffect,t.lastEffect=i,i.nextEffect=null):t.firstEffect=t.lastEffect=null):n=Vs(i,l),null!==e?r=Vs(e,r):(r=Ys(r,o,a,null)).flags|=2,r.return=t,n.return=t,n.sibling=r,t.child=n,r}function nl(e,t){e.lanes|=t;var n=e.alternate;null!==n&&(n.lanes|=t),ro(e.return,t)}function rl(e,t,n,r,a,o){var i=e.memoizedState;null===i?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:a,lastEffect:o}:(i.isBackwards=t,i.rendering=null,i.renderingStartTime=0,i.last=r,i.tail=n,i.tailMode=a,i.lastEffect=o)}function al(e,t,n){var r=t.pendingProps,a=r.revealOrder,o=r.tail;if(Ui(e,t,r.children,n),0!=(2&(r=Uo.current)))r=1&r|2,t.flags|=64;else{if(null!==e&&0!=(64&e.flags))e:for(e=t.child;null!==e;){if(13===e.tag)null!==e.memoizedState&&nl(e,n);else if(19===e.tag)nl(e,n);else if(null!==e.child){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;null===e.sibling;){if(null===e.return||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(ca(Uo,r),0==(2&t.mode))t.memoizedState=null;else switch(a){case"forwards":for(n=t.child,a=null;null!==n;)null!==(e=n.alternate)&&null===Fo(e)&&(a=n),n=n.sibling;null===(n=a)?(a=t.child,t.child=null):(a=n.sibling,n.sibling=null),rl(t,!1,a,n,o,t.lastEffect);break;case"backwards":for(n=null,a=t.child,t.child=null;null!==a;){if(null!==(e=a.alternate)&&null===Fo(e)){t.child=a;break}e=a.sibling,a.sibling=n,n=a,a=e}rl(t,!0,n,null,o,t.lastEffect);break;case"together":rl(t,!1,null,null,void 0,t.lastEffect);break;default:t.memoizedState=null}return t.child}function ol(e,t,n){if(null!==e&&(t.dependencies=e.dependencies),zl|=t.lanes,0!=(n&t.childLanes)){if(null!==e&&t.child!==e.child)throw Error(i(153));if(null!==t.child){for(n=Vs(e=t.child,e.pendingProps),t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,(n=n.sibling=Vs(e,e.pendingProps)).return=t;n.sibling=null}return t.child}return null}function il(e,t){if(!zo)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;null!==t;)null!==t.alternate&&(n=t),t=t.sibling;null===n?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;null!==n;)null!==n.alternate&&(r=n),n=n.sibling;null===r?t||null===e.tail?e.tail=null:e.tail.sibling=null:r.sibling=null}}function ll(e,t,n){var r=t.pendingProps;switch(t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:case 17:return ga(t.type)&&ba(),null;case 3:return xo(),ua(pa),ua(fa),Ko(),(r=t.stateNode).pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),null!==e&&null!==e.child||(Vo(t)?t.flags|=4:r.hydrate||(t.flags|=256)),Yi(t),null;case 5:Mo(t);var o=Lo(No.current);if(n=t.type,null!==e&&null!=t.stateNode)Ki(e,t,n,r,o),e.ref!==t.ref&&(t.flags|=128);else{if(!r){if(null===t.stateNode)throw Error(i(166));return null}if(e=Lo(Oo.current),Vo(t)){r=t.stateNode,n=t.type;var l=t.memoizedProps;switch(r[qr]=t,r[Qr]=l,n){case"dialog":Or("cancel",r),Or("close",r);break;case"iframe":case"object":case"embed":Or("load",r);break;case"video":case"audio":for(e=0;e<kr.length;e++)Or(kr[e],r);break;case"source":Or("error",r);break;case"img":case"image":case"link":Or("error",r),Or("load",r);break;case"details":Or("toggle",r);break;case"input":ee(r,l),Or("invalid",r);break;case"select":r._wrapperState={wasMultiple:!!l.multiple},Or("invalid",r);break;case"textarea":se(r,l),Or("invalid",r)}for(var u in we(n,l),e=null,l)l.hasOwnProperty(u)&&(o=l[u],"children"===u?"string"==typeof o?r.textContent!==o&&(e=["children",o]):"number"==typeof o&&r.textContent!==""+o&&(e=["children",""+o]):s.hasOwnProperty(u)&&null!=o&&"onScroll"===u&&Or("scroll",r));switch(n){case"input":X(r),re(r,l,!0);break;case"textarea":X(r),ce(r);break;case"select":case"option":break;default:"function"==typeof l.onClick&&(r.onclick=Br)}r=e,t.updateQueue=r,null!==r&&(t.flags|=4)}else{switch(u=9===o.nodeType?o:o.ownerDocument,e===de.html&&(e=fe(n)),e===de.html?"script"===n?((e=u.createElement("div")).innerHTML="<script><\/script>",e=e.removeChild(e.firstChild)):"string"==typeof r.is?e=u.createElement(n,{is:r.is}):(e=u.createElement(n),"select"===n&&(u=e,r.multiple?u.multiple=!0:r.size&&(u.size=r.size))):e=u.createElementNS(e,n),e[qr]=t,e[Qr]=r,Wi(e,t,!1,!1),t.stateNode=e,u=Te(n,r),n){case"dialog":Or("cancel",e),Or("close",e),o=r;break;case"iframe":case"object":case"embed":Or("load",e),o=r;break;case"video":case"audio":for(o=0;o<kr.length;o++)Or(kr[o],e);o=r;break;case"source":Or("error",e),o=r;break;case"img":case"image":case"link":Or("error",e),Or("load",e),o=r;break;case"details":Or("toggle",e),o=r;break;case"input":ee(e,r),o=J(e,r),Or("invalid",e);break;case"option":o=oe(e,r);break;case"select":e._wrapperState={wasMultiple:!!r.multiple},o=a({},r,{value:void 0}),Or("invalid",e);break;case"textarea":se(e,r),o=le(e,r),Or("invalid",e);break;default:o=r}we(n,o);var c=o;for(l in c)if(c.hasOwnProperty(l)){var d=c[l];"style"===l?Se(e,d):"dangerouslySetInnerHTML"===l?null!=(d=d?d.__html:void 0)&&ge(e,d):"children"===l?"string"==typeof d?("textarea"!==n||""!==d)&&be(e,d):"number"==typeof d&&be(e,""+d):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&(s.hasOwnProperty(l)?null!=d&&"onScroll"===l&&Or("scroll",e):null!=d&&E(e,l,d,u))}switch(n){case"input":X(e),re(e,r,!1);break;case"textarea":X(e),ce(e);break;case"option":null!=r.value&&e.setAttribute("value",""+Y(r.value));break;case"select":e.multiple=!!r.multiple,null!=(l=r.value)?ie(e,!!r.multiple,l,!1):null!=r.defaultValue&&ie(e,!!r.multiple,r.defaultValue,!0);break;default:"function"==typeof o.onClick&&(e.onclick=Br)}Hr(n,r)&&(t.flags|=4)}null!==t.ref&&(t.flags|=128)}return null;case 6:if(e&&null!=t.stateNode)Xi(e,t,e.memoizedProps,r);else{if("string"!=typeof r&&null===t.stateNode)throw Error(i(166));n=Lo(No.current),Lo(Oo.current),Vo(t)?(r=t.stateNode,n=t.memoizedProps,r[qr]=t,r.nodeValue!==n&&(t.flags|=4)):((r=(9===n.nodeType?n:n.ownerDocument).createTextNode(r))[qr]=t,t.stateNode=r)}return null;case 13:return ua(Uo),r=t.memoizedState,0!=(64&t.flags)?(t.lanes=n,t):(r=null!==r,n=!1,null===e?void 0!==t.memoizedProps.fallback&&Vo(t):n=null!==e.memoizedState,r&&!n&&0!=(2&t.mode)&&(null===e&&!0!==t.memoizedProps.unstable_avoidThisFallback||0!=(1&Uo.current)?0===Fl&&(Fl=3):(0!==Fl&&3!==Fl||(Fl=4),null===Pl||0==(134217727&zl)&&0==(134217727&Hl)||vs(Pl,Dl))),(r||n)&&(t.flags|=4),null);case 4:return xo(),Yi(t),null===e&&Nr(t.stateNode.containerInfo),null;case 10:return no(t),null;case 19:if(ua(Uo),null===(r=t.memoizedState))return null;if(l=0!=(64&t.flags),null===(u=r.rendering))if(l)il(r,!1);else{if(0!==Fl||null!==e&&0!=(64&e.flags))for(e=t.child;null!==e;){if(null!==(u=Fo(e))){for(t.flags|=64,il(r,!1),null!==(l=u.updateQueue)&&(t.updateQueue=l,t.flags|=4),null===r.lastEffect&&(t.firstEffect=null),t.lastEffect=r.lastEffect,r=n,n=t.child;null!==n;)e=r,(l=n).flags&=2,l.nextEffect=null,l.firstEffect=null,l.lastEffect=null,null===(u=l.alternate)?(l.childLanes=0,l.lanes=e,l.child=null,l.memoizedProps=null,l.memoizedState=null,l.updateQueue=null,l.dependencies=null,l.stateNode=null):(l.childLanes=u.childLanes,l.lanes=u.lanes,l.child=u.child,l.memoizedProps=u.memoizedProps,l.memoizedState=u.memoizedState,l.updateQueue=u.updateQueue,l.type=u.type,e=u.dependencies,l.dependencies=null===e?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return ca(Uo,1&Uo.current|2),t.child}e=e.sibling}null!==r.tail&&Ha()>Vl&&(t.flags|=64,l=!0,il(r,!1),t.lanes=33554432)}else{if(!l)if(null!==(e=Fo(u))){if(t.flags|=64,l=!0,null!==(n=e.updateQueue)&&(t.updateQueue=n,t.flags|=4),il(r,!0),null===r.tail&&"hidden"===r.tailMode&&!u.alternate&&!zo)return null!==(t=t.lastEffect=r.lastEffect)&&(t.nextEffect=null),null}else 2*Ha()-r.renderingStartTime>Vl&&1073741824!==n&&(t.flags|=64,l=!0,il(r,!1),t.lanes=33554432);r.isBackwards?(u.sibling=t.child,t.child=u):(null!==(n=r.last)?n.sibling=u:t.child=u,r.last=u)}return null!==r.tail?(n=r.tail,r.rendering=n,r.tail=n.sibling,r.lastEffect=t.lastEffect,r.renderingStartTime=Ha(),n.sibling=null,t=Uo.current,ca(Uo,l?1&t|2:1&t),n):null;case 23:case 24:return ws(),null!==e&&null!==e.memoizedState!=(null!==t.memoizedState)&&"unstable-defer-without-hiding"!==r.mode&&(t.flags|=4),null}throw Error(i(156,t.tag))}function sl(e){switch(e.tag){case 1:ga(e.type)&&ba();var t=e.flags;return 4096&t?(e.flags=-4097&t|64,e):null;case 3:if(xo(),ua(pa),ua(fa),Ko(),0!=(64&(t=e.flags)))throw Error(i(285));return e.flags=-4097&t|64,e;case 5:return Mo(e),null;case 13:return ua(Uo),4096&(t=e.flags)?(e.flags=-4097&t|64,e):null;case 19:return ua(Uo),null;case 4:return xo(),null;case 10:return no(e),null;case 23:case 24:return ws(),null;default:return null}}function ul(e,t){try{var n="",r=t;do{n+=V(r),r=r.return}while(r);var a=n}catch(o){a="\nError generating stack: "+o.message+"\n"+o.stack}return{value:e,source:t,stack:a}}function cl(e,t){try{console.error(t.value)}catch(n){setTimeout((function(){throw n}))}}Wi=function(e,t){for(var n=t.child;null!==n;){if(5===n.tag||6===n.tag)e.appendChild(n.stateNode);else if(4!==n.tag&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===t)break;for(;null===n.sibling;){if(null===n.return||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}},Yi=function(){},Ki=function(e,t,n,r){var o=e.memoizedProps;if(o!==r){e=t.stateNode,Lo(Oo.current);var i,l=null;switch(n){case"input":o=J(e,o),r=J(e,r),l=[];break;case"option":o=oe(e,o),r=oe(e,r),l=[];break;case"select":o=a({},o,{value:void 0}),r=a({},r,{value:void 0}),l=[];break;case"textarea":o=le(e,o),r=le(e,r),l=[];break;default:"function"!=typeof o.onClick&&"function"==typeof r.onClick&&(e.onclick=Br)}for(d in we(n,r),n=null,o)if(!r.hasOwnProperty(d)&&o.hasOwnProperty(d)&&null!=o[d])if("style"===d){var u=o[d];for(i in u)u.hasOwnProperty(i)&&(n||(n={}),n[i]="")}else"dangerouslySetInnerHTML"!==d&&"children"!==d&&"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&"autoFocus"!==d&&(s.hasOwnProperty(d)?l||(l=[]):(l=l||[]).push(d,null));for(d in r){var c=r[d];if(u=null!=o?o[d]:void 0,r.hasOwnProperty(d)&&c!==u&&(null!=c||null!=u))if("style"===d)if(u){for(i in u)!u.hasOwnProperty(i)||c&&c.hasOwnProperty(i)||(n||(n={}),n[i]="");for(i in c)c.hasOwnProperty(i)&&u[i]!==c[i]&&(n||(n={}),n[i]=c[i])}else n||(l||(l=[]),l.push(d,n)),n=c;else"dangerouslySetInnerHTML"===d?(c=c?c.__html:void 0,u=u?u.__html:void 0,null!=c&&u!==c&&(l=l||[]).push(d,c)):"children"===d?"string"!=typeof c&&"number"!=typeof c||(l=l||[]).push(d,""+c):"suppressContentEditableWarning"!==d&&"suppressHydrationWarning"!==d&&(s.hasOwnProperty(d)?(null!=c&&"onScroll"===d&&Or("scroll",e),l||u===c||(l=[])):"object"==typeof c&&null!==c&&c.$$typeof===D?c.toString():(l=l||[]).push(d,c))}n&&(l=l||[]).push("style",n);var d=l;(t.updateQueue=d)&&(t.flags|=4)}},Xi=function(e,t,n,r){n!==r&&(t.flags|=4)};var dl="function"==typeof WeakMap?WeakMap:Map;function fl(e,t,n){(n=uo(-1,n)).tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){Xl||(Xl=!0,ql=r),cl(0,t)},n}function pl(e,t,n){(n=uo(-1,n)).tag=3;var r=e.type.getDerivedStateFromError;if("function"==typeof r){var a=t.value;n.payload=function(){return cl(0,t),r(a)}}var o=e.stateNode;return null!==o&&"function"==typeof o.componentDidCatch&&(n.callback=function(){"function"!=typeof r&&(null===Ql?Ql=new Set([this]):Ql.add(this),cl(0,t));var e=t.stack;this.componentDidCatch(t.value,{componentStack:null!==e?e:""})}),n}var ml="function"==typeof WeakSet?WeakSet:Set;function hl(e){var t=e.ref;if(null!==t)if("function"==typeof t)try{t(null)}catch(n){$s(e,n)}else t.current=null}function gl(e,t){switch(t.tag){case 0:case 11:case 15:case 22:case 5:case 6:case 4:case 17:return;case 1:if(256&t.flags&&null!==e){var n=e.memoizedProps,r=e.memoizedState;t=(e=t.stateNode).getSnapshotBeforeUpdate(t.elementType===t.type?n:Xa(t.type,n),r),e.__reactInternalSnapshotBeforeUpdate=t}return;case 3:return void(256&t.flags&&Vr(t.stateNode.containerInfo))}throw Error(i(163))}function bl(e,t,n){switch(n.tag){case 0:case 11:case 15:case 22:if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{if(3==(3&e.tag)){var r=e.create;e.destroy=r()}e=e.next}while(e!==t)}if(null!==(t=null!==(t=n.updateQueue)?t.lastEffect:null)){e=t=t.next;do{var a=e;r=a.next,0!=(4&(a=a.tag))&&0!=(1&a)&&(Us(n,e),Ms(n,e)),e=r}while(e!==t)}return;case 1:return e=n.stateNode,4&n.flags&&(null===t?e.componentDidMount():(r=n.elementType===n.type?t.memoizedProps:Xa(n.type,t.memoizedProps),e.componentDidUpdate(r,t.memoizedState,e.__reactInternalSnapshotBeforeUpdate))),void(null!==(t=n.updateQueue)&&mo(n,t,e));case 3:if(null!==(t=n.updateQueue)){if(e=null,null!==n.child)switch(n.child.tag){case 5:case 1:e=n.child.stateNode}mo(n,t,e)}return;case 5:return e=n.stateNode,void(null===t&&4&n.flags&&Hr(n.type,n.memoizedProps)&&e.focus());case 6:case 4:case 12:case 19:case 17:case 20:case 21:case 23:case 24:return;case 13:return void(null===n.memoizedState&&(n=n.alternate,null!==n&&(n=n.memoizedState,null!==n&&(n=n.dehydrated,null!==n&&St(n)))))}throw Error(i(163))}function vl(e,t){for(var n=e;;){if(5===n.tag){var r=n.stateNode;if(t)"function"==typeof(r=r.style).setProperty?r.setProperty("display","none","important"):r.display="none";else{r=n.stateNode;var a=n.memoizedProps.style;a=null!=a&&a.hasOwnProperty("display")?a.display:null,r.style.display=Ee("display",a)}}else if(6===n.tag)n.stateNode.nodeValue=t?"":n.memoizedProps;else if((23!==n.tag&&24!==n.tag||null===n.memoizedState||n===e)&&null!==n.child){n.child.return=n,n=n.child;continue}if(n===e)break;for(;null===n.sibling;){if(null===n.return||n.return===e)return;n=n.return}n.sibling.return=n.return,n=n.sibling}}function yl(e,t){if(wa&&"function"==typeof wa.onCommitFiberUnmount)try{wa.onCommitFiberUnmount(_a,t)}catch(o){}switch(t.tag){case 0:case 11:case 14:case 15:case 22:if(null!==(e=t.updateQueue)&&null!==(e=e.lastEffect)){var n=e=e.next;do{var r=n,a=r.destroy;if(r=r.tag,void 0!==a)if(0!=(4&r))Us(t,n);else{r=t;try{a()}catch(o){$s(r,o)}}n=n.next}while(n!==e)}break;case 1:if(hl(t),"function"==typeof(e=t.stateNode).componentWillUnmount)try{e.props=t.memoizedProps,e.state=t.memoizedState,e.componentWillUnmount()}catch(o){$s(t,o)}break;case 5:hl(t);break;case 4:kl(e,t)}}function El(e){e.alternate=null,e.child=null,e.dependencies=null,e.firstEffect=null,e.lastEffect=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.return=null,e.updateQueue=null}function Sl(e){return 5===e.tag||3===e.tag||4===e.tag}function _l(e){e:{for(var t=e.return;null!==t;){if(Sl(t))break e;t=t.return}throw Error(i(160))}var n=t;switch(t=n.stateNode,n.tag){case 5:var r=!1;break;case 3:case 4:t=t.containerInfo,r=!0;break;default:throw Error(i(161))}16&n.flags&&(be(t,""),n.flags&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||Sl(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag&&18!==n.tag;){if(2&n.flags)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.flags)){n=n.stateNode;break e}}r?wl(e,n,t):Tl(e,n,t)}function wl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?8===n.nodeType?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(8===n.nodeType?(t=n.parentNode).insertBefore(e,n):(t=n).appendChild(e),null!=(n=n._reactRootContainer)||null!==t.onclick||(t.onclick=Br));else if(4!==r&&null!==(e=e.child))for(wl(e,t,n),e=e.sibling;null!==e;)wl(e,t,n),e=e.sibling}function Tl(e,t,n){var r=e.tag,a=5===r||6===r;if(a)e=a?e.stateNode:e.stateNode.instance,t?n.insertBefore(e,t):n.appendChild(e);else if(4!==r&&null!==(e=e.child))for(Tl(e,t,n),e=e.sibling;null!==e;)Tl(e,t,n),e=e.sibling}function kl(e,t){for(var n,r,a=t,o=!1;;){if(!o){o=a.return;e:for(;;){if(null===o)throw Error(i(160));switch(n=o.stateNode,o.tag){case 5:r=!1;break e;case 3:case 4:n=n.containerInfo,r=!0;break e}o=o.return}o=!0}if(5===a.tag||6===a.tag){e:for(var l=e,s=a,u=s;;)if(yl(l,u),null!==u.child&&4!==u.tag)u.child.return=u,u=u.child;else{if(u===s)break e;for(;null===u.sibling;){if(null===u.return||u.return===s)break e;u=u.return}u.sibling.return=u.return,u=u.sibling}r?(l=n,s=a.stateNode,8===l.nodeType?l.parentNode.removeChild(s):l.removeChild(s)):n.removeChild(a.stateNode)}else if(4===a.tag){if(null!==a.child){n=a.stateNode.containerInfo,r=!0,a.child.return=a,a=a.child;continue}}else if(yl(e,a),null!==a.child){a.child.return=a,a=a.child;continue}if(a===t)break;for(;null===a.sibling;){if(null===a.return||a.return===t)return;4===(a=a.return).tag&&(o=!1)}a.sibling.return=a.return,a=a.sibling}}function Cl(e,t){switch(t.tag){case 0:case 11:case 14:case 15:case 22:var n=t.updateQueue;if(null!==(n=null!==n?n.lastEffect:null)){var r=n=n.next;do{3==(3&r.tag)&&(e=r.destroy,r.destroy=void 0,void 0!==e&&e()),r=r.next}while(r!==n)}return;case 1:case 12:case 17:return;case 5:if(null!=(n=t.stateNode)){r=t.memoizedProps;var a=null!==e?e.memoizedProps:r;e=t.type;var o=t.updateQueue;if(t.updateQueue=null,null!==o){for(n[Qr]=r,"input"===e&&"radio"===r.type&&null!=r.name&&te(n,r),Te(e,a),t=Te(e,r),a=0;a<o.length;a+=2){var l=o[a],s=o[a+1];"style"===l?Se(n,s):"dangerouslySetInnerHTML"===l?ge(n,s):"children"===l?be(n,s):E(n,l,s,t)}switch(e){case"input":ne(n,r);break;case"textarea":ue(n,r);break;case"select":e=n._wrapperState.wasMultiple,n._wrapperState.wasMultiple=!!r.multiple,null!=(o=r.value)?ie(n,!!r.multiple,o,!1):e!==!!r.multiple&&(null!=r.defaultValue?ie(n,!!r.multiple,r.defaultValue,!0):ie(n,!!r.multiple,r.multiple?[]:"",!1))}}}return;case 6:if(null===t.stateNode)throw Error(i(162));return void(t.stateNode.nodeValue=t.memoizedProps);case 3:return void((n=t.stateNode).hydrate&&(n.hydrate=!1,St(n.containerInfo)));case 13:return null!==t.memoizedState&&(Zl=Ha(),vl(t.child,!0)),void Al(t);case 19:return void Al(t);case 23:case 24:return void vl(t,null!==t.memoizedState)}throw Error(i(163))}function Al(e){var t=e.updateQueue;if(null!==t){e.updateQueue=null;var n=e.stateNode;null===n&&(n=e.stateNode=new ml),t.forEach((function(t){var r=Hs.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))}))}}function Il(e,t){return null!==e&&(null===(e=e.memoizedState)||null!==e.dehydrated)&&(null!==(t=t.memoizedState)&&null===t.dehydrated)}var Ol=Math.ceil,Rl=S.ReactCurrentDispatcher,Nl=S.ReactCurrentOwner,Ll=0,Pl=null,xl=null,Dl=0,Ml=0,Ul=sa(0),Fl=0,Bl=null,$l=0,zl=0,Hl=0,jl=0,Gl=null,Zl=0,Vl=1/0;function Wl(){Vl=Ha()+500}var Yl,Kl=null,Xl=!1,ql=null,Ql=null,Jl=!1,es=null,ts=90,ns=[],rs=[],as=null,os=0,is=null,ls=-1,ss=0,us=0,cs=null,ds=!1;function fs(){return 0!=(48&Ll)?Ha():-1!==ls?ls:ls=Ha()}function ps(e){if(0==(2&(e=e.mode)))return 1;if(0==(4&e))return 99===ja()?1:2;if(0===ss&&(ss=$l),0!==Ka.transition){0!==us&&(us=null!==Gl?Gl.pendingLanes:0),e=ss;var t=4186112&~us;return 0===(t&=-t)&&(0===(t=(e=4186112&~e)&-e)&&(t=8192)),t}return e=ja(),0!=(4&Ll)&&98===e?e=Bt(12,ss):e=Bt(e=function(e){switch(e){case 99:return 15;case 98:return 10;case 97:case 96:return 8;case 95:return 2;default:return 0}}(e),ss),e}function ms(e,t,n){if(50<os)throw os=0,is=null,Error(i(185));if(null===(e=hs(e,t)))return null;Ht(e,t,n),e===Pl&&(Hl|=t,4===Fl&&vs(e,Dl));var r=ja();1===t?0!=(8&Ll)&&0==(48&Ll)?ys(e):(gs(e,n),0===Ll&&(Wl(),Wa())):(0==(4&Ll)||98!==r&&99!==r||(null===as?as=new Set([e]):as.add(e)),gs(e,n)),Gl=e}function hs(e,t){e.lanes|=t;var n=e.alternate;for(null!==n&&(n.lanes|=t),n=e,e=e.return;null!==e;)e.childLanes|=t,null!==(n=e.alternate)&&(n.childLanes|=t),n=e,e=e.return;return 3===n.tag?n.stateNode:null}function gs(e,t){for(var n=e.callbackNode,r=e.suspendedLanes,a=e.pingedLanes,o=e.expirationTimes,l=e.pendingLanes;0<l;){var s=31-jt(l),u=1<<s,c=o[s];if(-1===c){if(0==(u&r)||0!=(u&a)){c=t,Mt(u);var d=Dt;o[s]=10<=d?c+250:6<=d?c+5e3:-1}}else c<=t&&(e.expiredLanes|=u);l&=~u}if(r=Ut(e,e===Pl?Dl:0),t=Dt,0===r)null!==n&&(n!==Ma&&Ca(n),e.callbackNode=null,e.callbackPriority=0);else{if(null!==n){if(e.callbackPriority===t)return;n!==Ma&&Ca(n)}15===t?(n=ys.bind(null,e),null===Fa?(Fa=[n],Ba=ka(Na,Ya)):Fa.push(n),n=Ma):14===t?n=Va(99,ys.bind(null,e)):(n=function(e){switch(e){case 15:case 14:return 99;case 13:case 12:case 11:case 10:return 98;case 9:case 8:case 7:case 6:case 4:case 5:return 97;case 3:case 2:case 1:return 95;case 0:return 90;default:throw Error(i(358,e))}}(t),n=Va(n,bs.bind(null,e))),e.callbackPriority=t,e.callbackNode=n}}function bs(e){if(ls=-1,us=ss=0,0!=(48&Ll))throw Error(i(327));var t=e.callbackNode;if(Ds()&&e.callbackNode!==t)return null;var n=Ut(e,e===Pl?Dl:0);if(0===n)return null;var r=n,a=Ll;Ll|=16;var o=Cs();for(Pl===e&&Dl===r||(Wl(),Ts(e,r));;)try{Os();break}catch(s){ks(e,s)}if(to(),Rl.current=o,Ll=a,null!==xl?r=0:(Pl=null,Dl=0,r=Fl),0!=($l&Hl))Ts(e,0);else if(0!==r){if(2===r&&(Ll|=64,e.hydrate&&(e.hydrate=!1,Vr(e.containerInfo)),0!==(n=Ft(e))&&(r=As(e,n))),1===r)throw t=Bl,Ts(e,0),vs(e,n),gs(e,Ha()),t;switch(e.finishedWork=e.current.alternate,e.finishedLanes=n,r){case 0:case 1:throw Error(i(345));case 2:case 5:Ls(e);break;case 3:if(vs(e,n),(62914560&n)===n&&10<(r=Zl+500-Ha())){if(0!==Ut(e,0))break;if(((a=e.suspendedLanes)&n)!==n){fs(),e.pingedLanes|=e.suspendedLanes&a;break}e.timeoutHandle=Gr(Ls.bind(null,e),r);break}Ls(e);break;case 4:if(vs(e,n),(4186112&n)===n)break;for(r=e.eventTimes,a=-1;0<n;){var l=31-jt(n);o=1<<l,(l=r[l])>a&&(a=l),n&=~o}if(n=a,10<(n=(120>(n=Ha()-n)?120:480>n?480:1080>n?1080:1920>n?1920:3e3>n?3e3:4320>n?4320:1960*Ol(n/1960))-n)){e.timeoutHandle=Gr(Ls.bind(null,e),n);break}Ls(e);break;default:throw Error(i(329))}}return gs(e,Ha()),e.callbackNode===t?bs.bind(null,e):null}function vs(e,t){for(t&=~jl,t&=~Hl,e.suspendedLanes|=t,e.pingedLanes&=~t,e=e.expirationTimes;0<t;){var n=31-jt(t),r=1<<n;e[n]=-1,t&=~r}}function ys(e){if(0!=(48&Ll))throw Error(i(327));if(Ds(),e===Pl&&0!=(e.expiredLanes&Dl)){var t=Dl,n=As(e,t);0!=($l&Hl)&&(n=As(e,t=Ut(e,t)))}else n=As(e,t=Ut(e,0));if(0!==e.tag&&2===n&&(Ll|=64,e.hydrate&&(e.hydrate=!1,Vr(e.containerInfo)),0!==(t=Ft(e))&&(n=As(e,t))),1===n)throw n=Bl,Ts(e,0),vs(e,t),gs(e,Ha()),n;return e.finishedWork=e.current.alternate,e.finishedLanes=t,Ls(e),gs(e,Ha()),null}function Es(e,t){var n=Ll;Ll|=1;try{return e(t)}finally{0===(Ll=n)&&(Wl(),Wa())}}function Ss(e,t){var n=Ll;Ll&=-2,Ll|=8;try{return e(t)}finally{0===(Ll=n)&&(Wl(),Wa())}}function _s(e,t){ca(Ul,Ml),Ml|=t,$l|=t}function ws(){Ml=Ul.current,ua(Ul)}function Ts(e,t){e.finishedWork=null,e.finishedLanes=0;var n=e.timeoutHandle;if(-1!==n&&(e.timeoutHandle=-1,Zr(n)),null!==xl)for(n=xl.return;null!==n;){var r=n;switch(r.tag){case 1:null!=(r=r.type.childContextTypes)&&ba();break;case 3:xo(),ua(pa),ua(fa),Ko();break;case 5:Mo(r);break;case 4:xo();break;case 13:case 19:ua(Uo);break;case 10:no(r);break;case 23:case 24:ws()}n=n.return}Pl=e,xl=Vs(e.current,null),Dl=Ml=$l=t,Fl=0,Bl=null,jl=Hl=zl=0}function ks(e,t){for(;;){var n=xl;try{if(to(),Xo.current=Ni,ni){for(var r=Jo.memoizedState;null!==r;){var a=r.queue;null!==a&&(a.pending=null),r=r.next}ni=!1}if(Qo=0,ti=ei=Jo=null,ri=!1,Nl.current=null,null===n||null===n.return){Fl=1,Bl=t,xl=null;break}e:{var o=e,i=n.return,l=n,s=t;if(t=Dl,l.flags|=2048,l.firstEffect=l.lastEffect=null,null!==s&&"object"==typeof s&&"function"==typeof s.then){var u=s;if(0==(2&l.mode)){var c=l.alternate;c?(l.updateQueue=c.updateQueue,l.memoizedState=c.memoizedState,l.lanes=c.lanes):(l.updateQueue=null,l.memoizedState=null)}var d=0!=(1&Uo.current),f=i;do{var p;if(p=13===f.tag){var m=f.memoizedState;if(null!==m)p=null!==m.dehydrated;else{var h=f.memoizedProps;p=void 0!==h.fallback&&(!0!==h.unstable_avoidThisFallback||!d)}}if(p){var g=f.updateQueue;if(null===g){var b=new Set;b.add(u),f.updateQueue=b}else g.add(u);if(0==(2&f.mode)){if(f.flags|=64,l.flags|=16384,l.flags&=-2981,1===l.tag)if(null===l.alternate)l.tag=17;else{var v=uo(-1,1);v.tag=2,co(l,v)}l.lanes|=1;break e}s=void 0,l=t;var y=o.pingCache;if(null===y?(y=o.pingCache=new dl,s=new Set,y.set(u,s)):void 0===(s=y.get(u))&&(s=new Set,y.set(u,s)),!s.has(l)){s.add(l);var E=zs.bind(null,o,u,l);u.then(E,E)}f.flags|=4096,f.lanes=t;break e}f=f.return}while(null!==f);s=Error((W(l.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.")}5!==Fl&&(Fl=2),s=ul(s,l),f=i;do{switch(f.tag){case 3:o=s,f.flags|=4096,t&=-t,f.lanes|=t,fo(f,fl(0,o,t));break e;case 1:o=s;var S=f.type,_=f.stateNode;if(0==(64&f.flags)&&("function"==typeof S.getDerivedStateFromError||null!==_&&"function"==typeof _.componentDidCatch&&(null===Ql||!Ql.has(_)))){f.flags|=4096,t&=-t,f.lanes|=t,fo(f,pl(f,o,t));break e}}f=f.return}while(null!==f)}Ns(n)}catch(w){t=w,xl===n&&null!==n&&(xl=n=n.return);continue}break}}function Cs(){var e=Rl.current;return Rl.current=Ni,null===e?Ni:e}function As(e,t){var n=Ll;Ll|=16;var r=Cs();for(Pl===e&&Dl===t||Ts(e,t);;)try{Is();break}catch(a){ks(e,a)}if(to(),Ll=n,Rl.current=r,null!==xl)throw Error(i(261));return Pl=null,Dl=0,Fl}function Is(){for(;null!==xl;)Rs(xl)}function Os(){for(;null!==xl&&!Aa();)Rs(xl)}function Rs(e){var t=Yl(e.alternate,e,Ml);e.memoizedProps=e.pendingProps,null===t?Ns(e):xl=t,Nl.current=null}function Ns(e){var t=e;do{var n=t.alternate;if(e=t.return,0==(2048&t.flags)){if(null!==(n=ll(n,t,Ml)))return void(xl=n);if(24!==(n=t).tag&&23!==n.tag||null===n.memoizedState||0!=(1073741824&Ml)||0==(4&n.mode)){for(var r=0,a=n.child;null!==a;)r|=a.lanes|a.childLanes,a=a.sibling;n.childLanes=r}null!==e&&0==(2048&e.flags)&&(null===e.firstEffect&&(e.firstEffect=t.firstEffect),null!==t.lastEffect&&(null!==e.lastEffect&&(e.lastEffect.nextEffect=t.firstEffect),e.lastEffect=t.lastEffect),1<t.flags&&(null!==e.lastEffect?e.lastEffect.nextEffect=t:e.firstEffect=t,e.lastEffect=t))}else{if(null!==(n=sl(t)))return n.flags&=2047,void(xl=n);null!==e&&(e.firstEffect=e.lastEffect=null,e.flags|=2048)}if(null!==(t=t.sibling))return void(xl=t);xl=t=e}while(null!==t);0===Fl&&(Fl=5)}function Ls(e){var t=ja();return Za(99,Ps.bind(null,e,t)),null}function Ps(e,t){do{Ds()}while(null!==es);if(0!=(48&Ll))throw Error(i(327));var n=e.finishedWork;if(null===n)return null;if(e.finishedWork=null,e.finishedLanes=0,n===e.current)throw Error(i(177));e.callbackNode=null;var r=n.lanes|n.childLanes,a=r,o=e.pendingLanes&~a;e.pendingLanes=a,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=a,e.mutableReadLanes&=a,e.entangledLanes&=a,a=e.entanglements;for(var l=e.eventTimes,s=e.expirationTimes;0<o;){var u=31-jt(o),c=1<<u;a[u]=0,l[u]=-1,s[u]=-1,o&=~c}if(null!==as&&0==(24&r)&&as.has(e)&&as.delete(e),e===Pl&&(xl=Pl=null,Dl=0),1<n.flags?null!==n.lastEffect?(n.lastEffect.nextEffect=n,r=n.firstEffect):r=n:r=n.firstEffect,null!==r){if(a=Ll,Ll|=32,Nl.current=null,$r=Yt,gr(l=hr())){if("selectionStart"in l)s={start:l.selectionStart,end:l.selectionEnd};else e:if(s=(s=l.ownerDocument)&&s.defaultView||window,(c=s.getSelection&&s.getSelection())&&0!==c.rangeCount){s=c.anchorNode,o=c.anchorOffset,u=c.focusNode,c=c.focusOffset;try{s.nodeType,u.nodeType}catch(C){s=null;break e}var d=0,f=-1,p=-1,m=0,h=0,g=l,b=null;t:for(;;){for(var v;g!==s||0!==o&&3!==g.nodeType||(f=d+o),g!==u||0!==c&&3!==g.nodeType||(p=d+c),3===g.nodeType&&(d+=g.nodeValue.length),null!==(v=g.firstChild);)b=g,g=v;for(;;){if(g===l)break t;if(b===s&&++m===o&&(f=d),b===u&&++h===c&&(p=d),null!==(v=g.nextSibling))break;b=(g=b).parentNode}g=v}s=-1===f||-1===p?null:{start:f,end:p}}else s=null;s=s||{start:0,end:0}}else s=null;zr={focusedElem:l,selectionRange:s},Yt=!1,cs=null,ds=!1,Kl=r;do{try{xs()}catch(C){if(null===Kl)throw Error(i(330));$s(Kl,C),Kl=Kl.nextEffect}}while(null!==Kl);cs=null,Kl=r;do{try{for(l=e;null!==Kl;){var y=Kl.flags;if(16&y&&be(Kl.stateNode,""),128&y){var E=Kl.alternate;if(null!==E){var S=E.ref;null!==S&&("function"==typeof S?S(null):S.current=null)}}switch(1038&y){case 2:_l(Kl),Kl.flags&=-3;break;case 6:_l(Kl),Kl.flags&=-3,Cl(Kl.alternate,Kl);break;case 1024:Kl.flags&=-1025;break;case 1028:Kl.flags&=-1025,Cl(Kl.alternate,Kl);break;case 4:Cl(Kl.alternate,Kl);break;case 8:kl(l,s=Kl);var _=s.alternate;El(s),null!==_&&El(_)}Kl=Kl.nextEffect}}catch(C){if(null===Kl)throw Error(i(330));$s(Kl,C),Kl=Kl.nextEffect}}while(null!==Kl);if(S=zr,E=hr(),y=S.focusedElem,l=S.selectionRange,E!==y&&y&&y.ownerDocument&&mr(y.ownerDocument.documentElement,y)){null!==l&&gr(y)&&(E=l.start,void 0===(S=l.end)&&(S=E),"selectionStart"in y?(y.selectionStart=E,y.selectionEnd=Math.min(S,y.value.length)):(S=(E=y.ownerDocument||document)&&E.defaultView||window).getSelection&&(S=S.getSelection(),s=y.textContent.length,_=Math.min(l.start,s),l=void 0===l.end?_:Math.min(l.end,s),!S.extend&&_>l&&(s=l,l=_,_=s),s=pr(y,_),o=pr(y,l),s&&o&&(1!==S.rangeCount||S.anchorNode!==s.node||S.anchorOffset!==s.offset||S.focusNode!==o.node||S.focusOffset!==o.offset)&&((E=E.createRange()).setStart(s.node,s.offset),S.removeAllRanges(),_>l?(S.addRange(E),S.extend(o.node,o.offset)):(E.setEnd(o.node,o.offset),S.addRange(E))))),E=[];for(S=y;S=S.parentNode;)1===S.nodeType&&E.push({element:S,left:S.scrollLeft,top:S.scrollTop});for("function"==typeof y.focus&&y.focus(),y=0;y<E.length;y++)(S=E[y]).element.scrollLeft=S.left,S.element.scrollTop=S.top}Yt=!!$r,zr=$r=null,e.current=n,Kl=r;do{try{for(y=e;null!==Kl;){var w=Kl.flags;if(36&w&&bl(y,Kl.alternate,Kl),128&w){E=void 0;var T=Kl.ref;if(null!==T){var k=Kl.stateNode;Kl.tag,E=k,"function"==typeof T?T(E):T.current=E}}Kl=Kl.nextEffect}}catch(C){if(null===Kl)throw Error(i(330));$s(Kl,C),Kl=Kl.nextEffect}}while(null!==Kl);Kl=null,Ua(),Ll=a}else e.current=n;if(Jl)Jl=!1,es=e,ts=t;else for(Kl=r;null!==Kl;)t=Kl.nextEffect,Kl.nextEffect=null,8&Kl.flags&&((w=Kl).sibling=null,w.stateNode=null),Kl=t;if(0===(r=e.pendingLanes)&&(Ql=null),1===r?e===is?os++:(os=0,is=e):os=0,n=n.stateNode,wa&&"function"==typeof wa.onCommitFiberRoot)try{wa.onCommitFiberRoot(_a,n,void 0,64==(64&n.current.flags))}catch(C){}if(gs(e,Ha()),Xl)throw Xl=!1,e=ql,ql=null,e;return 0!=(8&Ll)||Wa(),null}function xs(){for(;null!==Kl;){var e=Kl.alternate;ds||null===cs||(0!=(8&Kl.flags)?Je(Kl,cs)&&(ds=!0):13===Kl.tag&&Il(e,Kl)&&Je(Kl,cs)&&(ds=!0));var t=Kl.flags;0!=(256&t)&&gl(e,Kl),0==(512&t)||Jl||(Jl=!0,Va(97,(function(){return Ds(),null}))),Kl=Kl.nextEffect}}function Ds(){if(90!==ts){var e=97<ts?97:ts;return ts=90,Za(e,Fs)}return!1}function Ms(e,t){ns.push(t,e),Jl||(Jl=!0,Va(97,(function(){return Ds(),null})))}function Us(e,t){rs.push(t,e),Jl||(Jl=!0,Va(97,(function(){return Ds(),null})))}function Fs(){if(null===es)return!1;var e=es;if(es=null,0!=(48&Ll))throw Error(i(331));var t=Ll;Ll|=32;var n=rs;rs=[];for(var r=0;r<n.length;r+=2){var a=n[r],o=n[r+1],l=a.destroy;if(a.destroy=void 0,"function"==typeof l)try{l()}catch(u){if(null===o)throw Error(i(330));$s(o,u)}}for(n=ns,ns=[],r=0;r<n.length;r+=2){a=n[r],o=n[r+1];try{var s=a.create;a.destroy=s()}catch(u){if(null===o)throw Error(i(330));$s(o,u)}}for(s=e.current.firstEffect;null!==s;)e=s.nextEffect,s.nextEffect=null,8&s.flags&&(s.sibling=null,s.stateNode=null),s=e;return Ll=t,Wa(),!0}function Bs(e,t,n){co(e,t=fl(0,t=ul(n,t),1)),t=fs(),null!==(e=hs(e,1))&&(Ht(e,1,t),gs(e,t))}function $s(e,t){if(3===e.tag)Bs(e,e,t);else for(var n=e.return;null!==n;){if(3===n.tag){Bs(n,e,t);break}if(1===n.tag){var r=n.stateNode;if("function"==typeof n.type.getDerivedStateFromError||"function"==typeof r.componentDidCatch&&(null===Ql||!Ql.has(r))){var a=pl(n,e=ul(t,e),1);if(co(n,a),a=fs(),null!==(n=hs(n,1)))Ht(n,1,a),gs(n,a);else if("function"==typeof r.componentDidCatch&&(null===Ql||!Ql.has(r)))try{r.componentDidCatch(t,e)}catch(o){}break}}n=n.return}}function zs(e,t,n){var r=e.pingCache;null!==r&&r.delete(t),t=fs(),e.pingedLanes|=e.suspendedLanes&n,Pl===e&&(Dl&n)===n&&(4===Fl||3===Fl&&(62914560&Dl)===Dl&&500>Ha()-Zl?Ts(e,0):jl|=n),gs(e,t)}function Hs(e,t){var n=e.stateNode;null!==n&&n.delete(t),0===(t=0)&&(0==(2&(t=e.mode))?t=1:0==(4&t)?t=99===ja()?1:2:(0===ss&&(ss=$l),0===(t=$t(62914560&~ss))&&(t=4194304))),n=fs(),null!==(e=hs(e,t))&&(Ht(e,t,n),gs(e,n))}function js(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.flags=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.childLanes=this.lanes=0,this.alternate=null}function Gs(e,t,n,r){return new js(e,t,n,r)}function Zs(e){return!(!(e=e.prototype)||!e.isReactComponent)}function Vs(e,t){var n=e.alternate;return null===n?((n=Gs(e.tag,t,e.key,e.mode)).elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.nextEffect=null,n.firstEffect=null,n.lastEffect=null),n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=null===t?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Ws(e,t,n,r,a,o){var l=2;if(r=e,"function"==typeof e)Zs(e)&&(l=1);else if("string"==typeof e)l=5;else e:switch(e){case T:return Ys(n.children,a,o,t);case M:l=8,a|=16;break;case k:l=8,a|=1;break;case C:return(e=Gs(12,n,t,8|a)).elementType=C,e.type=C,e.lanes=o,e;case R:return(e=Gs(13,n,t,a)).type=R,e.elementType=R,e.lanes=o,e;case N:return(e=Gs(19,n,t,a)).elementType=N,e.lanes=o,e;case U:return Ks(n,a,o,t);case F:return(e=Gs(24,n,t,a)).elementType=F,e.lanes=o,e;default:if("object"==typeof e&&null!==e)switch(e.$$typeof){case A:l=10;break e;case I:l=9;break e;case O:l=11;break e;case L:l=14;break e;case P:l=16,r=null;break e;case x:l=22;break e}throw Error(i(130,null==e?e:typeof e,""))}return(t=Gs(l,n,t,a)).elementType=e,t.type=r,t.lanes=o,t}function Ys(e,t,n,r){return(e=Gs(7,e,r,t)).lanes=n,e}function Ks(e,t,n,r){return(e=Gs(23,e,r,t)).elementType=U,e.lanes=n,e}function Xs(e,t,n){return(e=Gs(6,e,null,t)).lanes=n,e}function qs(e,t,n){return(t=Gs(4,null!==e.children?e.children:[],e.key,t)).lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Qs(e,t,n){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.pendingContext=this.context=null,this.hydrate=n,this.callbackNode=null,this.callbackPriority=0,this.eventTimes=zt(0),this.expirationTimes=zt(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=zt(0),this.mutableSourceEagerHydrationData=null}function Js(e,t,n,r){var a=t.current,o=fs(),l=ps(a);e:if(n){t:{if(Ke(n=n._reactInternals)!==n||1!==n.tag)throw Error(i(170));var s=n;do{switch(s.tag){case 3:s=s.stateNode.context;break t;case 1:if(ga(s.type)){s=s.stateNode.__reactInternalMemoizedMergedChildContext;break t}}s=s.return}while(null!==s);throw Error(i(171))}if(1===n.tag){var u=n.type;if(ga(u)){n=ya(n,u,s);break e}}n=s}else n=da;return null===t.context?t.context=n:t.pendingContext=n,(t=uo(o,l)).payload={element:e},null!==(r=void 0===r?null:r)&&(t.callback=r),co(a,t),ms(a,l,o),l}function eu(e){return(e=e.current).child?(e.child.tag,e.child.stateNode):null}function tu(e,t){if(null!==(e=e.memoizedState)&&null!==e.dehydrated){var n=e.retryLane;e.retryLane=0!==n&&n<t?n:t}}function nu(e,t){tu(e,t),(e=e.alternate)&&tu(e,t)}function ru(e,t,n){var r=null!=n&&null!=n.hydrationOptions&&n.hydrationOptions.mutableSources||null;if(n=new Qs(e,t,null!=n&&!0===n.hydrate),t=Gs(3,null,null,2===t?7:1===t?3:0),n.current=t,t.stateNode=n,lo(t),e[Jr]=n.current,Nr(8===e.nodeType?e.parentNode:e),r)for(e=0;e<r.length;e++){var a=(t=r[e])._getVersion;a=a(t._source),null==n.mutableSourceEagerHydrationData?n.mutableSourceEagerHydrationData=[t,a]:n.mutableSourceEagerHydrationData.push(t,a)}this._internalRoot=n}function au(e){return!(!e||1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType&&(8!==e.nodeType||" react-mount-point-unstable "!==e.nodeValue))}function ou(e,t,n,r,a){var o=n._reactRootContainer;if(o){var i=o._internalRoot;if("function"==typeof a){var l=a;a=function(){var e=eu(i);l.call(e)}}Js(t,i,e,a)}else{if(o=n._reactRootContainer=function(e,t){if(t||(t=!(!(t=e?9===e.nodeType?e.documentElement:e.firstChild:null)||1!==t.nodeType||!t.hasAttribute("data-reactroot"))),!t)for(var n;n=e.lastChild;)e.removeChild(n);return new ru(e,0,t?{hydrate:!0}:void 0)}(n,r),i=o._internalRoot,"function"==typeof a){var s=a;a=function(){var e=eu(i);s.call(e)}}Ss((function(){Js(t,i,e,a)}))}return eu(i)}function iu(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!au(t))throw Error(i(200));return function(e,t,n){var r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:w,key:null==r?null:""+r,children:e,containerInfo:t,implementation:n}}(e,t,null,n)}Yl=function(e,t,n){var r=t.lanes;if(null!==e)if(e.memoizedProps!==t.pendingProps||pa.current)Mi=!0;else{if(0==(n&r)){switch(Mi=!1,t.tag){case 3:Vi(t),Wo();break;case 5:Do(t);break;case 1:ga(t.type)&&Ea(t);break;case 4:Po(t,t.stateNode.containerInfo);break;case 10:r=t.memoizedProps.value;var a=t.type._context;ca(qa,a._currentValue),a._currentValue=r;break;case 13:if(null!==t.memoizedState)return 0!=(n&t.child.childLanes)?Qi(e,t,n):(ca(Uo,1&Uo.current),null!==(t=ol(e,t,n))?t.sibling:null);ca(Uo,1&Uo.current);break;case 19:if(r=0!=(n&t.childLanes),0!=(64&e.flags)){if(r)return al(e,t,n);t.flags|=64}if(null!==(a=t.memoizedState)&&(a.rendering=null,a.tail=null,a.lastEffect=null),ca(Uo,Uo.current),r)break;return null;case 23:case 24:return t.lanes=0,zi(e,t,n)}return ol(e,t,n)}Mi=0!=(16384&e.flags)}else Mi=!1;switch(t.lanes=0,t.tag){case 2:if(r=t.type,null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=ha(t,fa.current),ao(t,n),a=ii(null,t,r,e,a,n),t.flags|=1,"object"==typeof a&&null!==a&&"function"==typeof a.render&&void 0===a.$$typeof){if(t.tag=1,t.memoizedState=null,t.updateQueue=null,ga(r)){var o=!0;Ea(t)}else o=!1;t.memoizedState=null!==a.state&&void 0!==a.state?a.state:null,lo(t);var l=r.getDerivedStateFromProps;"function"==typeof l&&go(t,r,l,e),a.updater=bo,t.stateNode=a,a._reactInternals=t,So(t,r,e,n),t=Zi(null,t,r,!0,o,n)}else t.tag=0,Ui(null,t,a,n),t=t.child;return t;case 16:a=t.elementType;e:{switch(null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),e=t.pendingProps,a=(o=a._init)(a._payload),t.type=a,o=t.tag=function(e){if("function"==typeof e)return Zs(e)?1:0;if(null!=e){if((e=e.$$typeof)===O)return 11;if(e===L)return 14}return 2}(a),e=Xa(a,e),o){case 0:t=ji(null,t,a,e,n);break e;case 1:t=Gi(null,t,a,e,n);break e;case 11:t=Fi(null,t,a,e,n);break e;case 14:t=Bi(null,t,a,Xa(a.type,e),r,n);break e}throw Error(i(306,a,""))}return t;case 0:return r=t.type,a=t.pendingProps,ji(e,t,r,a=t.elementType===r?a:Xa(r,a),n);case 1:return r=t.type,a=t.pendingProps,Gi(e,t,r,a=t.elementType===r?a:Xa(r,a),n);case 3:if(Vi(t),r=t.updateQueue,null===e||null===r)throw Error(i(282));if(r=t.pendingProps,a=null!==(a=t.memoizedState)?a.element:null,so(e,t),po(t,r,null,n),(r=t.memoizedState.element)===a)Wo(),t=ol(e,t,n);else{if((o=(a=t.stateNode).hydrate)&&($o=Wr(t.stateNode.containerInfo.firstChild),Bo=t,o=zo=!0),o){if(null!=(e=a.mutableSourceEagerHydrationData))for(a=0;a<e.length;a+=2)(o=e[a])._workInProgressVersionPrimary=e[a+1],Yo.push(o);for(n=Ao(t,null,r,n),t.child=n;n;)n.flags=-3&n.flags|1024,n=n.sibling}else Ui(e,t,r,n),Wo();t=t.child}return t;case 5:return Do(t),null===e&&Go(t),r=t.type,a=t.pendingProps,o=null!==e?e.memoizedProps:null,l=a.children,jr(r,a)?l=null:null!==o&&jr(r,o)&&(t.flags|=16),Hi(e,t),Ui(e,t,l,n),t.child;case 6:return null===e&&Go(t),null;case 13:return Qi(e,t,n);case 4:return Po(t,t.stateNode.containerInfo),r=t.pendingProps,null===e?t.child=Co(t,null,r,n):Ui(e,t,r,n),t.child;case 11:return r=t.type,a=t.pendingProps,Fi(e,t,r,a=t.elementType===r?a:Xa(r,a),n);case 7:return Ui(e,t,t.pendingProps,n),t.child;case 8:case 12:return Ui(e,t,t.pendingProps.children,n),t.child;case 10:e:{r=t.type._context,a=t.pendingProps,l=t.memoizedProps,o=a.value;var s=t.type._context;if(ca(qa,s._currentValue),s._currentValue=o,null!==l)if(s=l.value,0===(o=ur(s,o)?0:0|("function"==typeof r._calculateChangedBits?r._calculateChangedBits(s,o):1073741823))){if(l.children===a.children&&!pa.current){t=ol(e,t,n);break e}}else for(null!==(s=t.child)&&(s.return=t);null!==s;){var u=s.dependencies;if(null!==u){l=s.child;for(var c=u.firstContext;null!==c;){if(c.context===r&&0!=(c.observedBits&o)){1===s.tag&&((c=uo(-1,n&-n)).tag=2,co(s,c)),s.lanes|=n,null!==(c=s.alternate)&&(c.lanes|=n),ro(s.return,n),u.lanes|=n;break}c=c.next}}else l=10===s.tag&&s.type===t.type?null:s.child;if(null!==l)l.return=s;else for(l=s;null!==l;){if(l===t){l=null;break}if(null!==(s=l.sibling)){s.return=l.return,l=s;break}l=l.return}s=l}Ui(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,r=(o=t.pendingProps).children,ao(t,n),r=r(a=oo(a,o.unstable_observedBits)),t.flags|=1,Ui(e,t,r,n),t.child;case 14:return o=Xa(a=t.type,t.pendingProps),Bi(e,t,a,o=Xa(a.type,o),r,n);case 15:return $i(e,t,t.type,t.pendingProps,r,n);case 17:return r=t.type,a=t.pendingProps,a=t.elementType===r?a:Xa(r,a),null!==e&&(e.alternate=null,t.alternate=null,t.flags|=2),t.tag=1,ga(r)?(e=!0,Ea(t)):e=!1,ao(t,n),yo(t,r,a),So(t,r,a,n),Zi(null,t,r,!0,e,n);case 19:return al(e,t,n);case 23:case 24:return zi(e,t,n)}throw Error(i(156,t.tag))},ru.prototype.render=function(e){Js(e,this._internalRoot,null,null)},ru.prototype.unmount=function(){var e=this._internalRoot,t=e.containerInfo;Js(null,e,null,(function(){t[Jr]=null}))},et=function(e){13===e.tag&&(ms(e,4,fs()),nu(e,4))},tt=function(e){13===e.tag&&(ms(e,67108864,fs()),nu(e,67108864))},nt=function(e){if(13===e.tag){var t=fs(),n=ps(e);ms(e,n,t),nu(e,n)}},rt=function(e,t){return t()},Ce=function(e,t,n){switch(t){case"input":if(ne(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t<n.length;t++){var r=n[t];if(r!==e&&r.form===e.form){var a=aa(r);if(!a)throw Error(i(90));q(r),ne(r,a)}}}break;case"textarea":ue(e,n);break;case"select":null!=(t=n.value)&&ie(e,!!n.multiple,t,!1)}},Le=Es,Pe=function(e,t,n,r,a){var o=Ll;Ll|=4;try{return Za(98,e.bind(null,t,n,r,a))}finally{0===(Ll=o)&&(Wl(),Wa())}},xe=function(){0==(49&Ll)&&(function(){if(null!==as){var e=as;as=null,e.forEach((function(e){e.expiredLanes|=24&e.pendingLanes,gs(e,Ha())}))}Wa()}(),Ds())},De=function(e,t){var n=Ll;Ll|=2;try{return e(t)}finally{0===(Ll=n)&&(Wl(),Wa())}};var lu={Events:[na,ra,aa,Re,Ne,Ds,{current:!1}]},su={findFiberByHostInstance:ta,bundleType:0,version:"17.0.2",rendererPackageName:"react-dom"},uu={bundleType:su.bundleType,version:su.version,rendererPackageName:su.rendererPackageName,rendererConfig:su.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:S.ReactCurrentDispatcher,findHostInstanceByFiber:function(e){return null===(e=Qe(e))?null:e.stateNode},findFiberByHostInstance:su.findFiberByHostInstance||function(){return null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null};if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__){var cu=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(!cu.isDisabled&&cu.supportsFiber)try{_a=cu.inject(uu),wa=cu}catch(he){}}t.createPortal=iu,t.hydrate=function(e,t,n){if(!au(t))throw Error(i(200));return ou(null,e,t,!0,n)}},3935:(e,t,n)=>{"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(4448)},9590:e=>{var t="undefined"!=typeof Element,n="function"==typeof Map,r="function"==typeof Set,a="function"==typeof ArrayBuffer&&!!ArrayBuffer.isView;function o(e,i){if(e===i)return!0;if(e&&i&&"object"==typeof e&&"object"==typeof i){if(e.constructor!==i.constructor)return!1;var l,s,u,c;if(Array.isArray(e)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(!o(e[s],i[s]))return!1;return!0}if(n&&e instanceof Map&&i instanceof Map){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;for(c=e.entries();!(s=c.next()).done;)if(!o(s.value[1],i.get(s.value[0])))return!1;return!0}if(r&&e instanceof Set&&i instanceof Set){if(e.size!==i.size)return!1;for(c=e.entries();!(s=c.next()).done;)if(!i.has(s.value[0]))return!1;return!0}if(a&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(i)){if((l=e.length)!=i.length)return!1;for(s=l;0!=s--;)if(e[s]!==i[s])return!1;return!0}if(e.constructor===RegExp)return e.source===i.source&&e.flags===i.flags;if(e.valueOf!==Object.prototype.valueOf&&"function"==typeof e.valueOf&&"function"==typeof i.valueOf)return e.valueOf()===i.valueOf();if(e.toString!==Object.prototype.toString&&"function"==typeof e.toString&&"function"==typeof i.toString)return e.toString()===i.toString();if((l=(u=Object.keys(e)).length)!==Object.keys(i).length)return!1;for(s=l;0!=s--;)if(!Object.prototype.hasOwnProperty.call(i,u[s]))return!1;if(t&&e instanceof Element)return!1;for(s=l;0!=s--;)if(("_owner"!==u[s]&&"__v"!==u[s]&&"__o"!==u[s]||!e.$$typeof)&&!o(e[u[s]],i[u[s]]))return!1;return!0}return e!=e&&i!=i}e.exports=function(e,t){try{return o(e,t)}catch(n){if((n.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw n}}},405:(e,t,n)=>{"use strict";n.d(t,{B6:()=>Z,ql:()=>J});var r=n(7294),a=n(5697),o=n.n(a),i=n(9590),l=n.n(i),s=n(1143),u=n.n(s),c=n(6774),d=n.n(c);function f(){return f=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},f.apply(this,arguments)}function p(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,m(e,t)}function m(e,t){return m=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},m(e,t)}function h(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)t.indexOf(n=o[r])>=0||(a[n]=e[n]);return a}var g={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title",FRAGMENT:"Symbol(react.fragment)"},b={rel:["amphtml","canonical","alternate"]},v={type:["application/ld+json"]},y={charset:"",name:["robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]},E=Object.keys(g).map((function(e){return g[e]})),S={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},_=Object.keys(S).reduce((function(e,t){return e[S[t]]=t,e}),{}),w=function(e,t){for(var n=e.length-1;n>=0;n-=1){var r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},T=function(e){var t=w(e,g.TITLE),n=w(e,"titleTemplate");if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,(function(){return t}));var r=w(e,"defaultTitle");return t||r||void 0},k=function(e){return w(e,"onChangeClientState")||function(){}},C=function(e,t){return t.filter((function(t){return void 0!==t[e]})).map((function(t){return t[e]})).reduce((function(e,t){return f({},e,t)}),{})},A=function(e,t){return t.filter((function(e){return void 0!==e[g.BASE]})).map((function(e){return e[g.BASE]})).reverse().reduce((function(t,n){if(!t.length)for(var r=Object.keys(n),a=0;a<r.length;a+=1){var o=r[a].toLowerCase();if(-1!==e.indexOf(o)&&n[o])return t.concat(n)}return t}),[])},I=function(e,t,n){var r={};return n.filter((function(t){return!!Array.isArray(t[e])||(void 0!==t[e]&&console&&"function"==typeof console.warn&&console.warn("Helmet: "+e+' should be of type "Array". Instead found type "'+typeof t[e]+'"'),!1)})).map((function(t){return t[e]})).reverse().reduce((function(e,n){var a={};n.filter((function(e){for(var n,o=Object.keys(e),i=0;i<o.length;i+=1){var l=o[i],s=l.toLowerCase();-1===t.indexOf(s)||"rel"===n&&"canonical"===e[n].toLowerCase()||"rel"===s&&"stylesheet"===e[s].toLowerCase()||(n=s),-1===t.indexOf(l)||"innerHTML"!==l&&"cssText"!==l&&"itemprop"!==l||(n=l)}if(!n||!e[n])return!1;var u=e[n].toLowerCase();return r[n]||(r[n]={}),a[n]||(a[n]={}),!r[n][u]&&(a[n][u]=!0,!0)})).reverse().forEach((function(t){return e.push(t)}));for(var o=Object.keys(a),i=0;i<o.length;i+=1){var l=o[i],s=f({},r[l],a[l]);r[l]=s}return e}),[]).reverse()},O=function(e,t){if(Array.isArray(e)&&e.length)for(var n=0;n<e.length;n+=1)if(e[n][t])return!0;return!1},R=function(e){return Array.isArray(e)?e.join(""):e},N=function(e,t){return Array.isArray(e)?e.reduce((function(e,n){return function(e,t){for(var n=Object.keys(e),r=0;r<n.length;r+=1)if(t[n[r]]&&t[n[r]].includes(e[n[r]]))return!0;return!1}(n,t)?e.priority.push(n):e.default.push(n),e}),{priority:[],default:[]}):{default:e}},L=function(e,t){var n;return f({},e,((n={})[t]=void 0,n))},P=[g.NOSCRIPT,g.SCRIPT,g.STYLE],x=function(e,t){return void 0===t&&(t=!0),!1===t?String(e):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")},D=function(e){return Object.keys(e).reduce((function(t,n){var r=void 0!==e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r}),"")},M=function(e,t){return void 0===t&&(t={}),Object.keys(e).reduce((function(t,n){return t[S[n]||n]=e[n],t}),t)},U=function(e,t){return t.map((function(t,n){var a,o=((a={key:n})["data-rh"]=!0,a);return Object.keys(t).forEach((function(e){var n=S[e]||e;"innerHTML"===n||"cssText"===n?o.dangerouslySetInnerHTML={__html:t.innerHTML||t.cssText}:o[n]=t[e]})),r.createElement(e,o)}))},F=function(e,t,n){switch(e){case g.TITLE:return{toComponent:function(){return n=t.titleAttributes,(a={key:e=t.title})["data-rh"]=!0,o=M(n,a),[r.createElement(g.TITLE,o,e)];var e,n,a,o},toString:function(){return function(e,t,n,r){var a=D(n),o=R(t);return a?"<"+e+' data-rh="true" '+a+">"+x(o,r)+"</"+e+">":"<"+e+' data-rh="true">'+x(o,r)+"</"+e+">"}(e,t.title,t.titleAttributes,n)}};case"bodyAttributes":case"htmlAttributes":return{toComponent:function(){return M(t)},toString:function(){return D(t)}};default:return{toComponent:function(){return U(e,t)},toString:function(){return function(e,t,n){return t.reduce((function(t,r){var a=Object.keys(r).filter((function(e){return!("innerHTML"===e||"cssText"===e)})).reduce((function(e,t){var a=void 0===r[t]?t:t+'="'+x(r[t],n)+'"';return e?e+" "+a:a}),""),o=r.innerHTML||r.cssText||"",i=-1===P.indexOf(e);return t+"<"+e+' data-rh="true" '+a+(i?"/>":">"+o+"</"+e+">")}),"")}(e,t,n)}}}},B=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,a=e.htmlAttributes,o=e.noscriptTags,i=e.styleTags,l=e.title,s=void 0===l?"":l,u=e.titleAttributes,c=e.linkTags,d=e.metaTags,f=e.scriptTags,p={toComponent:function(){},toString:function(){return""}};if(e.prioritizeSeoTags){var m=function(e){var t=e.linkTags,n=e.scriptTags,r=e.encode,a=N(e.metaTags,y),o=N(t,b),i=N(n,v);return{priorityMethods:{toComponent:function(){return[].concat(U(g.META,a.priority),U(g.LINK,o.priority),U(g.SCRIPT,i.priority))},toString:function(){return F(g.META,a.priority,r)+" "+F(g.LINK,o.priority,r)+" "+F(g.SCRIPT,i.priority,r)}},metaTags:a.default,linkTags:o.default,scriptTags:i.default}}(e);p=m.priorityMethods,c=m.linkTags,d=m.metaTags,f=m.scriptTags}return{priority:p,base:F(g.BASE,t,r),bodyAttributes:F("bodyAttributes",n,r),htmlAttributes:F("htmlAttributes",a,r),link:F(g.LINK,c,r),meta:F(g.META,d,r),noscript:F(g.NOSCRIPT,o,r),script:F(g.SCRIPT,f,r),style:F(g.STYLE,i,r),title:F(g.TITLE,{title:s,titleAttributes:u},r)}},$=[],z=function(e,t){var n=this;void 0===t&&(t="undefined"!=typeof document),this.instances=[],this.value={setHelmet:function(e){n.context.helmet=e},helmetInstances:{get:function(){return n.canUseDOM?$:n.instances},add:function(e){(n.canUseDOM?$:n.instances).push(e)},remove:function(e){var t=(n.canUseDOM?$:n.instances).indexOf(e);(n.canUseDOM?$:n.instances).splice(t,1)}}},this.context=e,this.canUseDOM=t,t||(e.helmet=B({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))},H=r.createContext({}),j=o().shape({setHelmet:o().func,helmetInstances:o().shape({get:o().func,add:o().func,remove:o().func})}),G="undefined"!=typeof document,Z=function(e){function t(n){var r;return(r=e.call(this,n)||this).helmetData=new z(r.props.context,t.canUseDOM),r}return p(t,e),t.prototype.render=function(){return r.createElement(H.Provider,{value:this.helmetData.value},this.props.children)},t}(r.Component);Z.canUseDOM=G,Z.propTypes={context:o().shape({helmet:o().shape()}),children:o().node.isRequired},Z.defaultProps={context:{}},Z.displayName="HelmetProvider";var V=function(e,t){var n,r=document.head||document.querySelector(g.HEAD),a=r.querySelectorAll(e+"[data-rh]"),o=[].slice.call(a),i=[];return t&&t.length&&t.forEach((function(t){var r=document.createElement(e);for(var a in t)Object.prototype.hasOwnProperty.call(t,a)&&("innerHTML"===a?r.innerHTML=t.innerHTML:"cssText"===a?r.styleSheet?r.styleSheet.cssText=t.cssText:r.appendChild(document.createTextNode(t.cssText)):r.setAttribute(a,void 0===t[a]?"":t[a]));r.setAttribute("data-rh","true"),o.some((function(e,t){return n=t,r.isEqualNode(e)}))?o.splice(n,1):i.push(r)})),o.forEach((function(e){return e.parentNode.removeChild(e)})),i.forEach((function(e){return r.appendChild(e)})),{oldTags:o,newTags:i}},W=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute("data-rh"),a=r?r.split(","):[],o=[].concat(a),i=Object.keys(t),l=0;l<i.length;l+=1){var s=i[l],u=t[s]||"";n.getAttribute(s)!==u&&n.setAttribute(s,u),-1===a.indexOf(s)&&a.push(s);var c=o.indexOf(s);-1!==c&&o.splice(c,1)}for(var d=o.length-1;d>=0;d-=1)n.removeAttribute(o[d]);a.length===o.length?n.removeAttribute("data-rh"):n.getAttribute("data-rh")!==i.join(",")&&n.setAttribute("data-rh",i.join(","))}},Y=function(e,t){var n=e.baseTag,r=e.htmlAttributes,a=e.linkTags,o=e.metaTags,i=e.noscriptTags,l=e.onChangeClientState,s=e.scriptTags,u=e.styleTags,c=e.title,d=e.titleAttributes;W(g.BODY,e.bodyAttributes),W(g.HTML,r),function(e,t){void 0!==e&&document.title!==e&&(document.title=R(e)),W(g.TITLE,t)}(c,d);var f={baseTag:V(g.BASE,n),linkTags:V(g.LINK,a),metaTags:V(g.META,o),noscriptTags:V(g.NOSCRIPT,i),scriptTags:V(g.SCRIPT,s),styleTags:V(g.STYLE,u)},p={},m={};Object.keys(f).forEach((function(e){var t=f[e],n=t.newTags,r=t.oldTags;n.length&&(p[e]=n),r.length&&(m[e]=f[e].oldTags)})),t&&t(),l(e,p,m)},K=null,X=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).rendered=!1,t}p(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!d()(e,this.props)},n.componentDidUpdate=function(){this.emitChange()},n.componentWillUnmount=function(){this.props.context.helmetInstances.remove(this),this.emitChange()},n.emitChange=function(){var e,t,n=this.props.context,r=n.setHelmet,a=null,o=(e=n.helmetInstances.get().map((function(e){var t=f({},e.props);return delete t.context,t})),{baseTag:A(["href"],e),bodyAttributes:C("bodyAttributes",e),defer:w(e,"defer"),encode:w(e,"encodeSpecialCharacters"),htmlAttributes:C("htmlAttributes",e),linkTags:I(g.LINK,["rel","href"],e),metaTags:I(g.META,["name","charset","http-equiv","property","itemprop"],e),noscriptTags:I(g.NOSCRIPT,["innerHTML"],e),onChangeClientState:k(e),scriptTags:I(g.SCRIPT,["src","innerHTML"],e),styleTags:I(g.STYLE,["cssText"],e),title:T(e),titleAttributes:C("titleAttributes",e),prioritizeSeoTags:O(e,"prioritizeSeoTags")});Z.canUseDOM?(t=o,K&&cancelAnimationFrame(K),t.defer?K=requestAnimationFrame((function(){Y(t,(function(){K=null}))})):(Y(t),K=null)):B&&(a=B(o)),r(a)},n.init=function(){this.rendered||(this.rendered=!0,this.props.context.helmetInstances.add(this),this.emitChange())},n.render=function(){return this.init(),null},t}(r.Component);X.propTypes={context:j.isRequired},X.displayName="HelmetDispatcher";var q=["children"],Q=["children"],J=function(e){function t(){return e.apply(this,arguments)||this}p(t,e);var n=t.prototype;return n.shouldComponentUpdate=function(e){return!l()(L(this.props,"helmetData"),L(e,"helmetData"))},n.mapNestedChildrenToProps=function(e,t){if(!t)return null;switch(e.type){case g.SCRIPT:case g.NOSCRIPT:return{innerHTML:t};case g.STYLE:return{cssText:t};default:throw new Error("<"+e.type+" /> elements are self-closing and can not contain children. Refer to our API for more information.")}},n.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren;return f({},r,((t={})[n.type]=[].concat(r[n.type]||[],[f({},e.newChildProps,this.mapNestedChildrenToProps(n,e.nestedChildren))]),t))},n.mapObjectTypeChildren=function(e){var t,n,r=e.child,a=e.newProps,o=e.newChildProps,i=e.nestedChildren;switch(r.type){case g.TITLE:return f({},a,((t={})[r.type]=i,t.titleAttributes=f({},o),t));case g.BODY:return f({},a,{bodyAttributes:f({},o)});case g.HTML:return f({},a,{htmlAttributes:f({},o)});default:return f({},a,((n={})[r.type]=f({},o),n))}},n.mapArrayTypeChildrenToProps=function(e,t){var n=f({},t);return Object.keys(e).forEach((function(t){var r;n=f({},n,((r={})[t]=e[t],r))})),n},n.warnOnInvalidChildren=function(e,t){return u()(E.some((function(t){return e.type===t})),"function"==typeof e.type?"You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.":"Only elements types "+E.join(", ")+" are allowed. Helmet does not support rendering <"+e.type+"> elements. Refer to our API for more information."),u()(!t||"string"==typeof t||Array.isArray(t)&&!t.some((function(e){return"string"!=typeof e})),"Helmet expects a string as a child of <"+e.type+">. Did you forget to wrap your children in braces? ( <"+e.type+">{``}</"+e.type+"> ) Refer to our API for more information."),!0},n.mapChildrenToProps=function(e,t){var n=this,a={};return r.Children.forEach(e,(function(e){if(e&&e.props){var r=e.props,o=r.children,i=h(r,q),l=Object.keys(i).reduce((function(e,t){return e[_[t]||t]=i[t],e}),{}),s=e.type;switch("symbol"==typeof s?s=s.toString():n.warnOnInvalidChildren(e,o),s){case g.FRAGMENT:t=n.mapChildrenToProps(o,t);break;case g.LINK:case g.META:case g.NOSCRIPT:case g.SCRIPT:case g.STYLE:a=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:a,newChildProps:l,nestedChildren:o});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:l,nestedChildren:o})}}})),this.mapArrayTypeChildrenToProps(a,t)},n.render=function(){var e=this.props,t=e.children,n=h(e,Q),a=f({},n),o=n.helmetData;return t&&(a=this.mapChildrenToProps(t,a)),!o||o instanceof z||(o=new z(o.context,o.instances)),o?r.createElement(X,f({},a,{context:o.value,helmetData:void 0})):r.createElement(H.Consumer,null,(function(e){return r.createElement(X,f({},a,{context:e}))}))},t}(r.Component);J.propTypes={base:o().object,bodyAttributes:o().object,children:o().oneOfType([o().arrayOf(o().node),o().node]),defaultTitle:o().string,defer:o().bool,encodeSpecialCharacters:o().bool,htmlAttributes:o().object,link:o().arrayOf(o().object),meta:o().arrayOf(o().object),noscript:o().arrayOf(o().object),onChangeClientState:o().func,script:o().arrayOf(o().object),style:o().arrayOf(o().object),title:o().string,titleAttributes:o().object,titleTemplate:o().string,prioritizeSeoTags:o().bool,helmetData:o().object},J.defaultProps={defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1},J.displayName="Helmet"},9921:(e,t)=>{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,a=n?Symbol.for("react.portal"):60106,o=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,u=n?Symbol.for("react.context"):60110,c=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,f=n?Symbol.for("react.forward_ref"):60112,p=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,h=n?Symbol.for("react.memo"):60115,g=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,E=n?Symbol.for("react.scope"):60119;function S(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case c:case d:case o:case l:case i:case p:return e;default:switch(e=e&&e.$$typeof){case u:case f:case g:case h:case s:return e;default:return t}}case a:return t}}}function _(e){return S(e)===d}t.AsyncMode=c,t.ConcurrentMode=d,t.ContextConsumer=u,t.ContextProvider=s,t.Element=r,t.ForwardRef=f,t.Fragment=o,t.Lazy=g,t.Memo=h,t.Portal=a,t.Profiler=l,t.StrictMode=i,t.Suspense=p,t.isAsyncMode=function(e){return _(e)||S(e)===c},t.isConcurrentMode=_,t.isContextConsumer=function(e){return S(e)===u},t.isContextProvider=function(e){return S(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return S(e)===f},t.isFragment=function(e){return S(e)===o},t.isLazy=function(e){return S(e)===g},t.isMemo=function(e){return S(e)===h},t.isPortal=function(e){return S(e)===a},t.isProfiler=function(e){return S(e)===l},t.isStrictMode=function(e){return S(e)===i},t.isSuspense=function(e){return S(e)===p},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===o||e===d||e===l||e===i||e===p||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===g||e.$$typeof===h||e.$$typeof===s||e.$$typeof===u||e.$$typeof===f||e.$$typeof===v||e.$$typeof===y||e.$$typeof===E||e.$$typeof===b)},t.typeOf=S},9864:(e,t,n)=>{"use strict";e.exports=n(9921)},8356:(e,t,n)=>{"use strict";function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,e.__proto__=t}function a(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i.apply(this,arguments)}var l=n(7294),s=n(5697),u=[],c=[];function d(e){var t=e(),n={loading:!0,loaded:null,error:null};return n.promise=t.then((function(e){return n.loading=!1,n.loaded=e,e})).catch((function(e){throw n.loading=!1,n.error=e,e})),n}function f(e){var t={loading:!1,loaded:{},error:null},n=[];try{Object.keys(e).forEach((function(r){var a=d(e[r]);a.loading?t.loading=!0:(t.loaded[r]=a.loaded,t.error=a.error),n.push(a.promise),a.promise.then((function(e){t.loaded[r]=e})).catch((function(e){t.error=e}))}))}catch(r){t.error=r}return t.promise=Promise.all(n).then((function(e){return t.loading=!1,e})).catch((function(e){throw t.loading=!1,e})),t}function p(e,t){return l.createElement((n=e)&&n.__esModule?n.default:n,t);var n}function m(e,t){var d,f;if(!t.loading)throw new Error("react-loadable requires a `loading` component");var m=i({loader:null,loading:null,delay:200,timeout:null,render:p,webpack:null,modules:null},t),h=null;function g(){return h||(h=e(m.loader)),h.promise}return u.push(g),"function"==typeof m.webpack&&c.push((function(){if((0,m.webpack)().every((function(e){return void 0!==e&&void 0!==n.m[e]})))return g()})),f=d=function(t){function n(n){var r;return o(a(a(r=t.call(this,n)||this)),"retry",(function(){r.setState({error:null,loading:!0,timedOut:!1}),h=e(m.loader),r._loadModule()})),g(),r.state={error:h.error,pastDelay:!1,timedOut:!1,loading:h.loading,loaded:h.loaded},r}r(n,t),n.preload=function(){return g()};var i=n.prototype;return i.UNSAFE_componentWillMount=function(){this._loadModule()},i.componentDidMount=function(){this._mounted=!0},i._loadModule=function(){var e=this;if(this.context.loadable&&Array.isArray(m.modules)&&m.modules.forEach((function(t){e.context.loadable.report(t)})),h.loading){var t=function(t){e._mounted&&e.setState(t)};"number"==typeof m.delay&&(0===m.delay?this.setState({pastDelay:!0}):this._delay=setTimeout((function(){t({pastDelay:!0})}),m.delay)),"number"==typeof m.timeout&&(this._timeout=setTimeout((function(){t({timedOut:!0})}),m.timeout));var n=function(){t({error:h.error,loaded:h.loaded,loading:h.loading}),e._clearTimeouts()};h.promise.then((function(){return n(),null})).catch((function(e){return n(),null}))}},i.componentWillUnmount=function(){this._mounted=!1,this._clearTimeouts()},i._clearTimeouts=function(){clearTimeout(this._delay),clearTimeout(this._timeout)},i.render=function(){return this.state.loading||this.state.error?l.createElement(m.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,retry:this.retry}):this.state.loaded?m.render(this.state.loaded,this.props):null},n}(l.Component),o(d,"contextTypes",{loadable:s.shape({report:s.func.isRequired})}),f}function h(e){return m(d,e)}h.Map=function(e){if("function"!=typeof e.render)throw new Error("LoadableMap requires a `render(loaded, props)` function");return m(f,e)};var g=function(e){function t(){return e.apply(this,arguments)||this}r(t,e);var n=t.prototype;return n.getChildContext=function(){return{loadable:{report:this.props.report}}},n.render=function(){return l.Children.only(this.props.children)},t}(l.Component);function b(e){for(var t=[];e.length;){var n=e.pop();t.push(n())}return Promise.all(t).then((function(){if(e.length)return b(e)}))}o(g,"propTypes",{report:s.func.isRequired}),o(g,"childContextTypes",{loadable:s.shape({report:s.func.isRequired}).isRequired}),h.Capture=g,h.preloadAll=function(){return new Promise((function(e,t){b(u).then(e,t)}))},h.preloadReady=function(){return new Promise((function(e,t){b(c).then(e,e)}))},e.exports=h},8790:(e,t,n)=>{"use strict";n.d(t,{H:()=>l,f:()=>i});var r=n(6550),a=n(7462),o=n(7294);function i(e,t,n){return void 0===n&&(n=[]),e.some((function(e){var a=e.path?(0,r.LX)(t,e):n.length?n[n.length-1].match:r.F0.computeRootMatch(t);return a&&(n.push({route:e,match:a}),e.routes&&i(e.routes,t,n)),a})),n}function l(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),e?o.createElement(r.rs,n,e.map((function(e,n){return o.createElement(r.AW,{key:e.key||n,path:e.path,exact:e.exact,strict:e.strict,render:function(n){return e.render?e.render((0,a.Z)({},n,{},t,{route:e})):o.createElement(e.component,(0,a.Z)({},n,t,{route:e}))}})}))):null}},3727:(e,t,n)=>{"use strict";n.d(t,{OL:()=>y,VK:()=>c,rU:()=>g});var r=n(6550),a=n(5068),o=n(7294),i=n(9318),l=n(7462),s=n(3366),u=n(8776),c=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(t=e.call.apply(e,[this].concat(r))||this).history=(0,i.lX)(t.props),t}return(0,a.Z)(t,e),t.prototype.render=function(){return o.createElement(r.F0,{history:this.history,children:this.props.children})},t}(o.Component);o.Component;var d=function(e,t){return"function"==typeof e?e(t):e},f=function(e,t){return"string"==typeof e?(0,i.ob)(e,null,null,t):e},p=function(e){return e},m=o.forwardRef;void 0===m&&(m=p);var h=m((function(e,t){var n=e.innerRef,r=e.navigate,a=e.onClick,i=(0,s.Z)(e,["innerRef","navigate","onClick"]),u=i.target,c=(0,l.Z)({},i,{onClick:function(e){try{a&&a(e)}catch(t){throw e.preventDefault(),t}e.defaultPrevented||0!==e.button||u&&"_self"!==u||function(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}(e)||(e.preventDefault(),r())}});return c.ref=p!==m&&t||n,o.createElement("a",c)}));var g=m((function(e,t){var n=e.component,a=void 0===n?h:n,c=e.replace,g=e.to,b=e.innerRef,v=(0,s.Z)(e,["component","replace","to","innerRef"]);return o.createElement(r.s6.Consumer,null,(function(e){e||(0,u.Z)(!1);var n=e.history,r=f(d(g,e.location),e.location),s=r?n.createHref(r):"",h=(0,l.Z)({},v,{href:s,navigate:function(){var t=d(g,e.location),r=(0,i.Ep)(e.location)===(0,i.Ep)(f(t));(c||r?n.replace:n.push)(t)}});return p!==m?h.ref=t||b:h.innerRef=b,o.createElement(a,h)}))})),b=function(e){return e},v=o.forwardRef;void 0===v&&(v=b);var y=v((function(e,t){var n=e["aria-current"],a=void 0===n?"page":n,i=e.activeClassName,c=void 0===i?"active":i,p=e.activeStyle,m=e.className,h=e.exact,y=e.isActive,E=e.location,S=e.sensitive,_=e.strict,w=e.style,T=e.to,k=e.innerRef,C=(0,s.Z)(e,["aria-current","activeClassName","activeStyle","className","exact","isActive","location","sensitive","strict","style","to","innerRef"]);return o.createElement(r.s6.Consumer,null,(function(e){e||(0,u.Z)(!1);var n=E||e.location,i=f(d(T,n),n),s=i.pathname,A=s&&s.replace(/([.+*?=^!:${}()[\]|/\\])/g,"\\$1"),I=A?(0,r.LX)(n.pathname,{path:A,exact:h,sensitive:S,strict:_}):null,O=!!(y?y(I,n):I),R="function"==typeof m?m(O):m,N="function"==typeof w?w(O):w;O&&(R=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}(R,c),N=(0,l.Z)({},N,p));var L=(0,l.Z)({"aria-current":O&&a||null,className:R,style:N,to:i},C);return b!==v?L.ref=t||k:L.innerRef=k,o.createElement(g,L)}))}))},6550:(e,t,n)=>{"use strict";n.d(t,{AW:()=>T,F0:()=>y,LX:()=>w,TH:()=>P,k6:()=>L,rs:()=>R,s6:()=>v});var r=n(5068),a=n(7294),o=n(5697),i=n.n(o),l=n(9318),s=n(8776),u=n(7462),c=n(4779),d=n.n(c),f=(n(9864),n(3366)),p=(n(8679),1073741823),m="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==n.g?n.g:{};var h=a.createContext||function(e,t){var n,o,l="__create-react-context-"+function(){var e="__global_unique_id__";return m[e]=(m[e]||0)+1}()+"__",s=function(e){function n(){for(var t,n,r,a=arguments.length,o=new Array(a),i=0;i<a;i++)o[i]=arguments[i];return(t=e.call.apply(e,[this].concat(o))||this).emitter=(n=t.props.value,r=[],{on:function(e){r.push(e)},off:function(e){r=r.filter((function(t){return t!==e}))},get:function(){return n},set:function(e,t){n=e,r.forEach((function(e){return e(n,t)}))}}),t}(0,r.Z)(n,e);var a=n.prototype;return a.getChildContext=function(){var e;return(e={})[l]=this.emitter,e},a.componentWillReceiveProps=function(e){if(this.props.value!==e.value){var n,r=this.props.value,a=e.value;((o=r)===(i=a)?0!==o||1/o==1/i:o!=o&&i!=i)?n=0:(n="function"==typeof t?t(r,a):p,0!==(n|=0)&&this.emitter.set(e.value,n))}var o,i},a.render=function(){return this.props.children},n}(a.Component);s.childContextTypes=((n={})[l]=i().object.isRequired,n);var u=function(t){function n(){for(var e,n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];return(e=t.call.apply(t,[this].concat(r))||this).observedBits=void 0,e.state={value:e.getValue()},e.onUpdate=function(t,n){0!=((0|e.observedBits)&n)&&e.setState({value:e.getValue()})},e}(0,r.Z)(n,t);var a=n.prototype;return a.componentWillReceiveProps=function(e){var t=e.observedBits;this.observedBits=null==t?p:t},a.componentDidMount=function(){this.context[l]&&this.context[l].on(this.onUpdate);var e=this.props.observedBits;this.observedBits=null==e?p:e},a.componentWillUnmount=function(){this.context[l]&&this.context[l].off(this.onUpdate)},a.getValue=function(){return this.context[l]?this.context[l].get():e},a.render=function(){return(e=this.props.children,Array.isArray(e)?e[0]:e)(this.state.value);var e},n}(a.Component);return u.contextTypes=((o={})[l]=i().object,o),{Provider:s,Consumer:u}},g=function(e){var t=h();return t.displayName=e,t},b=g("Router-History"),v=g("Router"),y=function(e){function t(t){var n;return(n=e.call(this,t)||this).state={location:t.history.location},n._isMounted=!1,n._pendingLocation=null,t.staticContext||(n.unlisten=t.history.listen((function(e){n._pendingLocation=e}))),n}(0,r.Z)(t,e),t.computeRootMatch=function(e){return{path:"/",url:"/",params:{},isExact:"/"===e}};var n=t.prototype;return n.componentDidMount=function(){var e=this;this._isMounted=!0,this.unlisten&&this.unlisten(),this.props.staticContext||(this.unlisten=this.props.history.listen((function(t){e._isMounted&&e.setState({location:t})}))),this._pendingLocation&&this.setState({location:this._pendingLocation})},n.componentWillUnmount=function(){this.unlisten&&(this.unlisten(),this._isMounted=!1,this._pendingLocation=null)},n.render=function(){return a.createElement(v.Provider,{value:{history:this.props.history,location:this.state.location,match:t.computeRootMatch(this.state.location.pathname),staticContext:this.props.staticContext}},a.createElement(b.Provider,{children:this.props.children||null,value:this.props.history}))},t}(a.Component);a.Component;a.Component;var E={},S=1e4,_=0;function w(e,t){void 0===t&&(t={}),("string"==typeof t||Array.isArray(t))&&(t={path:t});var n=t,r=n.path,a=n.exact,o=void 0!==a&&a,i=n.strict,l=void 0!==i&&i,s=n.sensitive,u=void 0!==s&&s;return[].concat(r).reduce((function(t,n){if(!n&&""!==n)return null;if(t)return t;var r=function(e,t){var n=""+t.end+t.strict+t.sensitive,r=E[n]||(E[n]={});if(r[e])return r[e];var a=[],o={regexp:d()(e,a,t),keys:a};return _<S&&(r[e]=o,_++),o}(n,{end:o,strict:l,sensitive:u}),a=r.regexp,i=r.keys,s=a.exec(e);if(!s)return null;var c=s[0],f=s.slice(1),p=e===c;return o&&!p?null:{path:n,url:"/"===n&&""===c?"/":c,isExact:p,params:i.reduce((function(e,t,n){return e[t.name]=f[n],e}),{})}}),null)}var T=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n=e.props.location||t.location,r=e.props.computedMatch?e.props.computedMatch:e.props.path?w(n.pathname,e.props):t.match,o=(0,u.Z)({},t,{location:n,match:r}),i=e.props,l=i.children,c=i.component,d=i.render;return Array.isArray(l)&&function(e){return 0===a.Children.count(e)}(l)&&(l=null),a.createElement(v.Provider,{value:o},o.match?l?"function"==typeof l?l(o):l:c?a.createElement(c,o):d?d(o):null:"function"==typeof l?l(o):null)}))},t}(a.Component);function k(e){return"/"===e.charAt(0)?e:"/"+e}function C(e,t){if(!e)return t;var n=k(e);return 0!==t.pathname.indexOf(n)?t:(0,u.Z)({},t,{pathname:t.pathname.substr(n.length)})}function A(e){return"string"==typeof e?e:(0,l.Ep)(e)}function I(e){return function(){(0,s.Z)(!1)}}function O(){}a.Component;var R=function(e){function t(){return e.apply(this,arguments)||this}return(0,r.Z)(t,e),t.prototype.render=function(){var e=this;return a.createElement(v.Consumer,null,(function(t){t||(0,s.Z)(!1);var n,r,o=e.props.location||t.location;return a.Children.forEach(e.props.children,(function(e){if(null==r&&a.isValidElement(e)){n=e;var i=e.props.path||e.props.from;r=i?w(o.pathname,(0,u.Z)({},e.props,{path:i})):t.match}})),r?a.cloneElement(n,{location:o,computedMatch:r}):null}))},t}(a.Component);var N=a.useContext;function L(){return N(b)}function P(){return N(v).location}},2408:(e,t,n)=>{"use strict";var r=n(7418),a=60103,o=60106;t.Fragment=60107,t.StrictMode=60108,t.Profiler=60114;var i=60109,l=60110,s=60112;t.Suspense=60113;var u=60115,c=60116;if("function"==typeof Symbol&&Symbol.for){var d=Symbol.for;a=d("react.element"),o=d("react.portal"),t.Fragment=d("react.fragment"),t.StrictMode=d("react.strict_mode"),t.Profiler=d("react.profiler"),i=d("react.provider"),l=d("react.context"),s=d("react.forward_ref"),t.Suspense=d("react.suspense"),u=d("react.memo"),c=d("react.lazy")}var f="function"==typeof Symbol&&Symbol.iterator;function p(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n<arguments.length;n++)t+="&args[]="+encodeURIComponent(arguments[n]);return"Minified React error #"+e+"; visit "+t+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h={};function g(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}function b(){}function v(e,t,n){this.props=e,this.context=t,this.refs=h,this.updater=n||m}g.prototype.isReactComponent={},g.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error(p(85));this.updater.enqueueSetState(this,e,t,"setState")},g.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},b.prototype=g.prototype;var y=v.prototype=new b;y.constructor=v,r(y,g.prototype),y.isPureReactComponent=!0;var E={current:null},S=Object.prototype.hasOwnProperty,_={key:!0,ref:!0,__self:!0,__source:!0};function w(e,t,n){var r,o={},i=null,l=null;if(null!=t)for(r in void 0!==t.ref&&(l=t.ref),void 0!==t.key&&(i=""+t.key),t)S.call(t,r)&&!_.hasOwnProperty(r)&&(o[r]=t[r]);var s=arguments.length-2;if(1===s)o.children=n;else if(1<s){for(var u=Array(s),c=0;c<s;c++)u[c]=arguments[c+2];o.children=u}if(e&&e.defaultProps)for(r in s=e.defaultProps)void 0===o[r]&&(o[r]=s[r]);return{$$typeof:a,type:e,key:i,ref:l,props:o,_owner:E.current}}function T(e){return"object"==typeof e&&null!==e&&e.$$typeof===a}var k=/\/+/g;function C(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function A(e,t,n,r,i){var l=typeof e;"undefined"!==l&&"boolean"!==l||(e=null);var s=!1;if(null===e)s=!0;else switch(l){case"string":case"number":s=!0;break;case"object":switch(e.$$typeof){case a:case o:s=!0}}if(s)return i=i(s=e),e=""===r?"."+C(s,0):r,Array.isArray(i)?(n="",null!=e&&(n=e.replace(k,"$&/")+"/"),A(i,t,n,"",(function(e){return e}))):null!=i&&(T(i)&&(i=function(e,t){return{$$typeof:a,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(i,n+(!i.key||s&&s.key===i.key?"":(""+i.key).replace(k,"$&/")+"/")+e)),t.push(i)),1;if(s=0,r=""===r?".":r+":",Array.isArray(e))for(var u=0;u<e.length;u++){var c=r+C(l=e[u],u);s+=A(l,t,n,c,i)}else if(c=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=f&&e[f]||e["@@iterator"])?e:null}(e),"function"==typeof c)for(e=c.call(e),u=0;!(l=e.next()).done;)s+=A(l=l.value,t,n,c=r+C(l,u++),i);else if("object"===l)throw t=""+e,Error(p(31,"[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t));return s}function I(e,t,n){if(null==e)return e;var r=[],a=0;return A(e,r,"","",(function(e){return t.call(n,e,a++)})),r}function O(e){if(-1===e._status){var t=e._result;t=t(),e._status=0,e._result=t,t.then((function(t){0===e._status&&(t=t.default,e._status=1,e._result=t)}),(function(t){0===e._status&&(e._status=2,e._result=t)}))}if(1===e._status)return e._result;throw e._result}var R={current:null};function N(){var e=R.current;if(null===e)throw Error(p(321));return e}var L={ReactCurrentDispatcher:R,ReactCurrentBatchConfig:{transition:0},ReactCurrentOwner:E,IsSomeRendererActing:{current:!1},assign:r};t.Children={map:I,forEach:function(e,t,n){I(e,(function(){t.apply(this,arguments)}),n)},count:function(e){var t=0;return I(e,(function(){t++})),t},toArray:function(e){return I(e,(function(e){return e}))||[]},only:function(e){if(!T(e))throw Error(p(143));return e}},t.Component=g,t.PureComponent=v,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=L,t.cloneElement=function(e,t,n){if(null==e)throw Error(p(267,e));var o=r({},e.props),i=e.key,l=e.ref,s=e._owner;if(null!=t){if(void 0!==t.ref&&(l=t.ref,s=E.current),void 0!==t.key&&(i=""+t.key),e.type&&e.type.defaultProps)var u=e.type.defaultProps;for(c in t)S.call(t,c)&&!_.hasOwnProperty(c)&&(o[c]=void 0===t[c]&&void 0!==u?u[c]:t[c])}var c=arguments.length-2;if(1===c)o.children=n;else if(1<c){u=Array(c);for(var d=0;d<c;d++)u[d]=arguments[d+2];o.children=u}return{$$typeof:a,type:e.type,key:i,ref:l,props:o,_owner:s}},t.createContext=function(e,t){return void 0===t&&(t=null),(e={$$typeof:l,_calculateChangedBits:t,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null}).Provider={$$typeof:i,_context:e},e.Consumer=e},t.createElement=w,t.createFactory=function(e){var t=w.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:s,render:e}},t.isValidElement=T,t.lazy=function(e){return{$$typeof:c,_payload:{_status:-1,_result:e},_init:O}},t.memo=function(e,t){return{$$typeof:u,type:e,compare:void 0===t?null:t}},t.useCallback=function(e,t){return N().useCallback(e,t)},t.useContext=function(e,t){return N().useContext(e,t)},t.useDebugValue=function(){},t.useEffect=function(e,t){return N().useEffect(e,t)},t.useImperativeHandle=function(e,t,n){return N().useImperativeHandle(e,t,n)},t.useLayoutEffect=function(e,t){return N().useLayoutEffect(e,t)},t.useMemo=function(e,t){return N().useMemo(e,t)},t.useReducer=function(e,t,n){return N().useReducer(e,t,n)},t.useRef=function(e){return N().useRef(e)},t.useState=function(e){return N().useState(e)},t.version="17.0.2"},7294:(e,t,n)=>{"use strict";e.exports=n(2408)},53:(e,t)=>{"use strict";var n,r,a,o;if("object"==typeof performance&&"function"==typeof performance.now){var i=performance;t.unstable_now=function(){return i.now()}}else{var l=Date,s=l.now();t.unstable_now=function(){return l.now()-s}}if("undefined"==typeof window||"function"!=typeof MessageChannel){var u=null,c=null,d=function(){if(null!==u)try{var e=t.unstable_now();u(!0,e),u=null}catch(n){throw setTimeout(d,0),n}};n=function(e){null!==u?setTimeout(n,0,e):(u=e,setTimeout(d,0))},r=function(e,t){c=setTimeout(e,t)},a=function(){clearTimeout(c)},t.unstable_shouldYield=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var m=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),"function"!=typeof m&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")}var h=!1,g=null,b=-1,v=5,y=0;t.unstable_shouldYield=function(){return t.unstable_now()>=y},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125<e?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):v=0<e?Math.floor(1e3/e):5};var E=new MessageChannel,S=E.port2;E.port1.onmessage=function(){if(null!==g){var e=t.unstable_now();y=e+v;try{g(!0,e)?S.postMessage(null):(h=!1,g=null)}catch(n){throw S.postMessage(null),n}}else h=!1},n=function(e){g=e,h||(h=!0,S.postMessage(null))},r=function(e,n){b=f((function(){e(t.unstable_now())}),n)},a=function(){p(b),b=-1}}function _(e,t){var n=e.length;e.push(t);e:for(;;){var r=n-1>>>1,a=e[r];if(!(void 0!==a&&0<k(a,t)))break e;e[r]=t,e[n]=a,n=r}}function w(e){return void 0===(e=e[0])?null:e}function T(e){var t=e[0];if(void 0!==t){var n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,a=e.length;r<a;){var o=2*(r+1)-1,i=e[o],l=o+1,s=e[l];if(void 0!==i&&0>k(i,n))void 0!==s&&0>k(s,i)?(e[r]=s,e[l]=n,r=l):(e[r]=i,e[o]=n,r=o);else{if(!(void 0!==s&&0>k(s,n)))break e;e[r]=s,e[l]=n,r=l}}}return t}return null}function k(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var C=[],A=[],I=1,O=null,R=3,N=!1,L=!1,P=!1;function x(e){for(var t=w(A);null!==t;){if(null===t.callback)T(A);else{if(!(t.startTime<=e))break;T(A),t.sortIndex=t.expirationTime,_(C,t)}t=w(A)}}function D(e){if(P=!1,x(e),!L)if(null!==w(C))L=!0,n(M);else{var t=w(A);null!==t&&r(D,t.startTime-e)}}function M(e,n){L=!1,P&&(P=!1,a()),N=!0;var o=R;try{for(x(n),O=w(C);null!==O&&(!(O.expirationTime>n)||e&&!t.unstable_shouldYield());){var i=O.callback;if("function"==typeof i){O.callback=null,R=O.priorityLevel;var l=i(O.expirationTime<=n);n=t.unstable_now(),"function"==typeof l?O.callback=l:O===w(C)&&T(C),x(n)}else T(C);O=w(C)}if(null!==O)var s=!0;else{var u=w(A);null!==u&&r(D,u.startTime-n),s=!1}return s}finally{O=null,R=o,N=!1}}var U=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){L||N||(L=!0,n(M))},t.unstable_getCurrentPriorityLevel=function(){return R},t.unstable_getFirstCallbackNode=function(){return w(C)},t.unstable_next=function(e){switch(R){case 1:case 2:case 3:var t=3;break;default:t=R}var n=R;R=t;try{return e()}finally{R=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=U,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=R;R=e;try{return t()}finally{R=n}},t.unstable_scheduleCallback=function(e,o,i){var l=t.unstable_now();switch("object"==typeof i&&null!==i?i="number"==typeof(i=i.delay)&&0<i?l+i:l:i=l,e){case 1:var s=-1;break;case 2:s=250;break;case 5:s=1073741823;break;case 4:s=1e4;break;default:s=5e3}return e={id:I++,callback:o,priorityLevel:e,startTime:i,expirationTime:s=i+s,sortIndex:-1},i>l?(e.sortIndex=i,_(A,e),null===w(C)&&e===w(A)&&(P?a():P=!0,r(D,i-l))):(e.sortIndex=s,_(C,e),L||N||(L=!0,n(M))),e},t.unstable_wrapCallback=function(e){var t=R;return function(){var n=R;R=t;try{return e.apply(this,arguments)}finally{R=n}}}},3840:(e,t,n)=>{"use strict";e.exports=n(53)},6774:e=>{e.exports=function(e,t,n,r){var a=n?n.call(r,e,t):void 0;if(void 0!==a)return!!a;if(e===t)return!0;if("object"!=typeof e||!e||"object"!=typeof t||!t)return!1;var o=Object.keys(e),i=Object.keys(t);if(o.length!==i.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(t),s=0;s<o.length;s++){var u=o[s];if(!l(u))return!1;var c=e[u],d=t[u];if(!1===(a=n?n.call(r,c,d,u):void 0)||void 0===a&&c!==d)return!1}return!0}},3250:(e,t,n)=>{"use strict";var r=n(7294);var a="function"==typeof Object.is?Object.is:function(e,t){return e===t&&(0!==e||1/e==1/t)||e!=e&&t!=t},o=r.useState,i=r.useEffect,l=r.useLayoutEffect,s=r.useDebugValue;function u(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!a(e,n)}catch(r){return!0}}var c="undefined"==typeof window||void 0===window.document||void 0===window.document.createElement?function(e,t){return t()}:function(e,t){var n=t(),r=o({inst:{value:n,getSnapshot:t}}),a=r[0].inst,c=r[1];return l((function(){a.value=n,a.getSnapshot=t,u(a)&&c({inst:a})}),[e,n,t]),i((function(){return u(a)&&c({inst:a}),e((function(){u(a)&&c({inst:a})}))}),[e]),s(n),n};t.useSyncExternalStore=void 0!==r.useSyncExternalStore?r.useSyncExternalStore:c},1688:(e,t,n)=>{"use strict";e.exports=n(3250)},7044:(e,t,n)=>{var r={"./prism-bash":8522,"./prism-bash.js":8522,"./prism-qmake":5494,"./prism-qmake.js":5494};function a(e){var t=o(e);return n(t)}function o(e){if(!n.o(r,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return r[e]}a.keys=function(){return Object.keys(r)},a.resolve=o,e.exports=a,a.id=7044},6809:(e,t,n)=>{"use strict";n.d(t,{default:()=>r});const r={title:"TinyORM",tagline:"C++ ORM library for Qt framework",url:"https://www.tinyorm.org",baseUrl:"/",onBrokenLinks:"throw",onBrokenMarkdownLinks:"throw",favicon:"img/favicon.ico",organizationName:"silverqx",projectName:"TinyORM",deploymentBranch:"gh-pages",trailingSlash:!1,titleDelimiter:"-",noIndex:!1,themeConfig:{colorMode:{defaultMode:"dark",disableSwitch:!1,respectPrefersColorScheme:!1},navbar:{hideOnScroll:!0,title:"TinyORM",logo:{alt:"TinyORM Logo",src:"img/logo.svg"},items:[{href:"https://github.com/silverqx/TinyORM",position:"right",className:"header-github-link","aria-label":"TinyORM GitHub repository",title:"TinyORM GitHub repository"}]},docs:{sidebar:{hideable:!0,autoCollapseCategories:!0},versionPersistence:"localStorage"},footer:{links:[],copyright:'<span>Copyright \xa9 2024 </span><a href="https://github.com/silverqx" target="_blank">Silver Zachara</a>',style:"light"},prism:{theme:{plain:{color:"#393A34",backgroundColor:"#f6f8fa"},styles:[{types:["comment","prolog","doctype","cdata"],style:{color:"#999988",fontStyle:"italic"}},{types:["namespace"],style:{opacity:.7}},{types:["string","attr-value"],style:{color:"#e3116c"}},{types:["punctuation","operator"],style:{color:"#393A34"}},{types:["entity","url","symbol","number","boolean","variable","constant","property","regex","inserted"],style:{color:"#36acaa"}},{types:["atrule","keyword","attr-name","selector"],style:{color:"#00a4db"}},{types:["function","deleted","tag"],style:{color:"#d73a49"}},{types:["function-variable"],style:{color:"#6f42c1"}},{types:["tag","selector","keyword"],style:{color:"#00009f"}}]},darkTheme:{plain:{color:"#F8F8F2",backgroundColor:"#282A36"},styles:[{types:["prolog","constant","builtin"],style:{color:"rgb(189, 147, 249)"}},{types:["inserted","function"],style:{color:"rgb(80, 250, 123)"}},{types:["deleted"],style:{color:"rgb(255, 85, 85)"}},{types:["changed"],style:{color:"rgb(255, 184, 108)"}},{types:["punctuation","symbol"],style:{color:"rgb(248, 248, 242)"}},{types:["string","char","tag","selector"],style:{color:"rgb(255, 121, 198)"}},{types:["keyword","variable"],style:{color:"rgb(189, 147, 249)",fontStyle:"italic"}},{types:["comment"],style:{color:"rgb(98, 114, 164)"}},{types:["attr-name"],style:{color:"rgb(241, 250, 140)"}}]},defaultLanguage:"cpp",additionalLanguages:["cmake","powershell"],magicComments:[{className:"theme-code-block-highlighted-line",line:"highlight-next-line",block:{start:"highlight-start",end:"highlight-end"}}]},algolia:{appId:"ML6TJ6GTSR",apiKey:"2d548632681c7f359587e5671f67e636",indexName:"TinyORM-github.io",contextualSearch:!1,searchParameters:{},searchPagePath:"search"},metadata:[{name:"keywords",content:"c++ orm, tinyorm"}],tableOfContents:{minHeadingLevel:2,maxHeadingLevel:3}},presets:[["@docusaurus/preset-classic",{docs:{sidebarPath:"E:\\code\\nodejs\\TinyORM-github.io\\sidebars.js",editUrl:"https://github.com/silverqx/TinyORM-github.io/edit/main/",routeBasePath:"/",exclude:["**/assets/**","building/README.md","database/README.md","tinydrivers/README.md","tinyorm/README.md"]},blog:!1,theme:{customCss:["E:\\code\\nodejs\\TinyORM-github.io\\src\\css\\custom.css"]},sitemap:{changefreq:"weekly"},gtag:{trackingID:"G-2QRS622BWQ",anonymizeIP:!1}}]],plugins:[["@docusaurus/plugin-client-redirects",{redirects:[{to:"/building/tinyorm",from:"/building"},{to:"/database/getting-started",from:"/database"},{to:"/database/query-builder",from:"/query-builder"},{to:"/tinyorm/getting-started",from:"/tinyorm"},{to:"/tinyorm/relationships",from:"/tinyorm-relationships"}]}],null,null,null],baseUrlIssueBanner:!0,i18n:{defaultLocale:"en",path:"i18n",locales:["en"],localeConfigs:{}},onDuplicateRoutes:"warn",staticDirectories:["static"],customFields:{},themes:[],scripts:[],headTags:[],stylesheets:[],clientModules:[],markdown:{mermaid:!1}}},7462:(e,t,n)=>{"use strict";function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},r.apply(this,arguments)}n.d(t,{Z:()=>r})},5068:(e,t,n)=>{"use strict";function r(e,t){return r=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},r(e,t)}function a(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,{Z:()=>a})},3366:(e,t,n)=>{"use strict";function r(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}n.d(t,{Z:()=>r})},8776:(e,t,n)=>{"use strict";n.d(t,{Z:()=>o});var r=!0,a="Invariant failed";function o(e,t){if(!e){if(r)throw new Error(a);var n="function"==typeof t?t():t,o=n?"".concat(a,": ").concat(n):a;throw new Error(o)}}},7529:e=>{"use strict";e.exports={}},6887:e=>{"use strict";e.exports=JSON.parse('{"/search-c88":{"__comp":"1a4e3797","__context":{"plugin":"cdf0eeb2"}},"/-848":{"__comp":"1be78505","__context":{"plugin":"8156e19a"},"versionMetadata":"935f2afb"},"/-b76":{"__comp":"17896441","content":"59b1a96c"},"/building/hello-world-acb":{"__comp":"17896441","content":"feaee7f3"},"/building/migrations-06d":{"__comp":"17896441","content":"8a8faf8d"},"/building/tinyorm-b42":{"__comp":"17896441","content":"0ab078a9"},"/database/getting-started-cc8":{"__comp":"17896441","content":"ba3d4959"},"/database/migrations-15a":{"__comp":"17896441","content":"21dc2778"},"/database/query-builder-258":{"__comp":"17896441","content":"cbe663fe"},"/database/seeding-358":{"__comp":"17896441","content":"a4d3e054"},"/dependencies-a89":{"__comp":"17896441","content":"e3ac21cb"},"/features-summary-652":{"__comp":"17896441","content":"fb313d4e"},"/sponsors-c1d":{"__comp":"17896441","content":"e19c288b"},"/supported-compilers-24e":{"__comp":"17896441","content":"d459b1c4"},"/tinydrivers/getting-started-d48":{"__comp":"17896441","content":"cb1e72f9"},"/tinyorm/casts-331":{"__comp":"17896441","content":"62a1276f"},"/tinyorm/collections-35b":{"__comp":"17896441","content":"3dd307b5"},"/tinyorm/getting-started-715":{"__comp":"17896441","content":"5b254f70"},"/tinyorm/relationships-04a":{"__comp":"17896441","content":"7333c691"},"/tinyorm/serialization-9c7":{"__comp":"17896441","content":"1222ea4e"}}')}},e=>{e.O(0,[532],(()=>{return t=85,e(e.s=t);var t}));e.O()}]); \ No newline at end of file diff --git a/assets/js/runtime~main.5e9866b5.js b/assets/js/runtime~main.5e9866b5.js deleted file mode 100644 index 629460ead..000000000 --- a/assets/js/runtime~main.5e9866b5.js +++ /dev/null @@ -1 +0,0 @@ -(()=>{"use strict";var e,t,r,a,o,f={},n={};function c(e){var t=n[e];if(void 0!==t)return t.exports;var r=n[e]={exports:{}};return f[e].call(r.exports,r,r.exports,c),r.exports}c.m=f,e=[],c.O=(t,r,a,o)=>{if(!r){var f=1/0;for(i=0;i<e.length;i++){r=e[i][0],a=e[i][1],o=e[i][2];for(var n=!0,d=0;d<r.length;d++)(!1&o||f>=o)&&Object.keys(c.O).every((e=>c.O[e](r[d])))?r.splice(d--,1):(n=!1,o<f&&(f=o));if(n){e.splice(i--,1);var b=a();void 0!==b&&(t=b)}}return t}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[r,a,o]},c.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return c.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);c.r(o);var f={};t=t||[null,r({}),r([]),r(r)];for(var n=2&a&&e;"object"==typeof n&&!~t.indexOf(n);n=r(n))Object.getOwnPropertyNames(n).forEach((t=>f[t]=()=>e[t]));return f.default=()=>e,c.d(o,f),o},c.d=(e,t)=>{for(var r in t)c.o(t,r)&&!c.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((t,r)=>(c.f[r](e,t),t)),[])),c.u=e=>"assets/js/"+({8:"e3ac21cb",53:"935f2afb",57:"62a1276f",67:"59b1a96c",108:"3dd307b5",113:"cdf0eeb2",116:"5b254f70",168:"feaee7f3",225:"8a8faf8d",291:"21dc2778",454:"a4d3e054",514:"1be78505",535:"1222ea4e",594:"cbe663fe",683:"8156e19a",684:"cb1e72f9",784:"ba3d4959",799:"7333c691",832:"fb313d4e",865:"e19c288b",918:"17896441",920:"1a4e3797",966:"d459b1c4",969:"0ab078a9"}[e]||e)+"."+{8:"9751aa02",53:"68cd247f",57:"732e44fe",67:"30ee1534",108:"7b464df0",113:"29f89fc3",116:"287f094d",168:"1f08f71e",176:"1f8f2d9b",225:"83cd2a22",291:"9ec72537",426:"97069429",454:"2c177800",514:"fb48f26a",535:"93c74363",594:"8fc7d46f",683:"5e01ccd6",684:"ebe13fc2",784:"86bd32f7",799:"d4a3b177",832:"246c2a2a",865:"fdce2815",894:"1afcfcdd",918:"35ffcf9d",920:"ca05490f",945:"62d4a71f",966:"7a1fface",969:"827159aa",972:"b9e804c8"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="tinyorm.org:",c.l=(e,t,r,f)=>{if(a[e])a[e].push(t);else{var n,d;if(void 0!==r)for(var b=document.getElementsByTagName("script"),i=0;i<b.length;i++){var u=b[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==o+r){n=u;break}}n||(d=!0,(n=document.createElement("script")).charset="utf-8",n.timeout=120,c.nc&&n.setAttribute("nonce",c.nc),n.setAttribute("data-webpack",o+r),n.src=e),a[e]=[t];var l=(t,r)=>{n.onerror=n.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],n.parentNode&&n.parentNode.removeChild(n),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:n}),12e4);n.onerror=l.bind(null,n.onerror),n.onload=l.bind(null,n.onload),d&&document.head.appendChild(n)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/",c.gca=function(e){return e={17896441:"918",e3ac21cb:"8","935f2afb":"53","62a1276f":"57","59b1a96c":"67","3dd307b5":"108",cdf0eeb2:"113","5b254f70":"116",feaee7f3:"168","8a8faf8d":"225","21dc2778":"291",a4d3e054:"454","1be78505":"514","1222ea4e":"535",cbe663fe:"594","8156e19a":"683",cb1e72f9:"684",ba3d4959:"784","7333c691":"799",fb313d4e:"832",e19c288b:"865","1a4e3797":"920",d459b1c4:"966","0ab078a9":"969"}[e]||e,c.p+c.u(e)},(()=>{var e={303:0,532:0};c.f.j=(t,r)=>{var a=c.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var f=c.p+c.u(t),n=new Error;c.l(f,(r=>{if(c.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),f=r&&r.target&&r.target.src;n.message="Loading chunk "+t+" failed.\n("+o+": "+f+")",n.name="ChunkLoadError",n.type=o,n.request=f,a[1](n)}}),"chunk-"+t,t)}},c.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,f=r[0],n=r[1],d=r[2],b=0;if(f.some((t=>0!==e[t]))){for(a in n)c.o(n,a)&&(c.m[a]=n[a]);if(d)var i=d(c)}for(t&&t(r);b<f.length;b++)o=f[b],c.o(e,o)&&e[o]&&e[o][0](),e[o]=0;return c.O(i)},r=self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})()})(); \ No newline at end of file diff --git a/assets/js/runtime~main.9226c6d5.js b/assets/js/runtime~main.9226c6d5.js new file mode 100644 index 000000000..638c5c1e0 --- /dev/null +++ b/assets/js/runtime~main.9226c6d5.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,a,t,r,o,n={},f={};function c(e){var a=f[e];if(void 0!==a)return a.exports;var t=f[e]={exports:{}};return n[e].call(t.exports,t,t.exports,c),t.exports}c.m=n,e=[],c.O=(a,t,r,o)=>{if(!t){var n=1/0;for(i=0;i<e.length;i++){t=e[i][0],r=e[i][1],o=e[i][2];for(var f=!0,b=0;b<t.length;b++)(!1&o||n>=o)&&Object.keys(c.O).every((e=>c.O[e](t[b])))?t.splice(b--,1):(f=!1,o<n&&(n=o));if(f){e.splice(i--,1);var d=r();void 0!==d&&(a=d)}}return a}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,r,o]},c.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return c.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var o=Object.create(null);c.r(o);var n={};a=a||[null,t({}),t([]),t(t)];for(var f=2&r&&e;"object"==typeof f&&!~a.indexOf(f);f=t(f))Object.getOwnPropertyNames(f).forEach((a=>n[a]=()=>e[a]));return n.default=()=>e,c.d(o,n),o},c.d=(e,a)=>{for(var t in a)c.o(a,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((a,t)=>(c.f[t](e,a),a)),[])),c.u=e=>"assets/js/"+({27:"d459b1c4",48:"a94703ab",69:"e19c288b",82:"5b254f70",98:"a7bd4aaa",117:"3dd307b5",129:"8a8faf8d",138:"1a4e3797",153:"1222ea4e",170:"ba3d4959",258:"cb1e72f9",295:"21dc2778",304:"62a1276f",395:"0ab078a9",401:"17896441",467:"e3ac21cb",485:"59b1a96c",638:"7333c691",647:"5e95c892",742:"aba21aa0",755:"a4d3e054",820:"6629c45f",871:"fb313d4e",957:"c141421f",983:"feaee7f3",995:"cbe663fe"}[e]||e)+"."+{27:"ebc2aae3",48:"29c38115",69:"cae4e49f",82:"84226d5d",98:"80cc43c0",117:"7d5f3256",129:"aa357c14",138:"0583fddb",153:"2cd8af81",170:"0b166b7a",237:"d109f2ba",258:"0ad8566f",295:"95e24d3c",304:"87749e65",395:"741e68ea",401:"6473f609",416:"a3ad28f7",446:"d7af1da2",462:"0011555c",467:"61732115",485:"35b999b1",638:"02799d7f",647:"7024aad0",742:"cb1d9d7d",755:"fedc061b",820:"43d6f39e",871:"1478a8fb",913:"3fa60236",957:"2356f0d5",983:"0f0c7251",995:"3147a933"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),r={},o="tinyorm.org:",c.l=(e,a,t,n)=>{if(r[e])r[e].push(a);else{var f,b;if(void 0!==t)for(var d=document.getElementsByTagName("script"),i=0;i<d.length;i++){var u=d[i];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==o+t){f=u;break}}f||(b=!0,(f=document.createElement("script")).charset="utf-8",f.timeout=120,c.nc&&f.setAttribute("nonce",c.nc),f.setAttribute("data-webpack",o+t),f.src=e),r[e]=[a];var l=(a,t)=>{f.onerror=f.onload=null,clearTimeout(s);var o=r[e];if(delete r[e],f.parentNode&&f.parentNode.removeChild(f),o&&o.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:f}),12e4);f.onerror=l.bind(null,f.onerror),f.onload=l.bind(null,f.onload),b&&document.head.appendChild(f)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/",c.gca=function(e){return e={17896441:"401",d459b1c4:"27",a94703ab:"48",e19c288b:"69","5b254f70":"82",a7bd4aaa:"98","3dd307b5":"117","8a8faf8d":"129","1a4e3797":"138","1222ea4e":"153",ba3d4959:"170",cb1e72f9:"258","21dc2778":"295","62a1276f":"304","0ab078a9":"395",e3ac21cb:"467","59b1a96c":"485","7333c691":"638","5e95c892":"647",aba21aa0:"742",a4d3e054:"755","6629c45f":"820",fb313d4e:"871",c141421f:"957",feaee7f3:"983",cbe663fe:"995"}[e]||e,c.p+c.u(e)},(()=>{var e={354:0,869:0};c.f.j=(a,t)=>{var r=c.o(e,a)?e[a]:void 0;if(0!==r)if(r)t.push(r[2]);else if(/^(354|869)$/.test(a))e[a]=0;else{var o=new Promise(((t,o)=>r=e[a]=[t,o]));t.push(r[2]=o);var n=c.p+c.u(a),f=new Error;c.l(n,(t=>{if(c.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;f.message="Loading chunk "+a+" failed.\n("+o+": "+n+")",f.name="ChunkLoadError",f.type=o,f.request=n,r[1](f)}}),"chunk-"+a,a)}},c.O.j=a=>0===e[a];var a=(a,t)=>{var r,o,n=t[0],f=t[1],b=t[2],d=0;if(n.some((a=>0!==e[a]))){for(r in f)c.o(f,r)&&(c.m[r]=f[r]);if(b)var i=b(c)}for(a&&a(t);d<n.length;d++)o=n[d],c.o(e,o)&&e[o]&&e[o][0](),e[o]=0;return c.O(i)},t=self.webpackChunktinyorm_org=self.webpackChunktinyorm_org||[];t.forEach(a.bind(null,0)),t.push=a.bind(null,t.push.bind(t))})()})(); \ No newline at end of file diff --git a/building/hello-world.html b/building/hello-world.html index 0e4f6526d..cf2debd23 100644 --- a/building/hello-world.html +++ b/building/hello-world.html @@ -1,9 +1,9 @@ <!doctype html> -<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-building/hello-world" data-has-hydrated="false"> +<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-building/hello-world" data-has-hydrated="false"> <head> <meta charset="UTF-8"> -<meta name="generator" content="Docusaurus v2.4.3"> -<title data-rh="true">Building: Hello world - TinyORM + +Building: Hello world - TinyORM @@ -13,14 +13,135 @@ - - - + + + -
-

Building: Hello world

Introduction

We will try to create the simplest working console application, in the terminal with the CMake and in the QtCreator IDE with the qmake build systems.

The HelloWorld example also expects the following folders structure, let's create them.

cd 
mkdir HelloWorld/HelloWorld
cd HelloWorld

Prepare SQLite 3 database

The easiest way to demonstrate the HelloWorld example will be with a SQLite 3 database.

Execute the following command in the terminal to create and insert two rows into the SQLite 3 database.

sqlite3 HelloWorld.sqlite3 "
create table posts(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name VARCHAR NOT NULL);
insert into posts values(1, 'First Post');
insert into posts values(2, 'Second Post');
select * from posts;"

Install dependencies

First, install the vcpkg package manager as is described here.

The range-v3 and tabulate libraries are required dependencies because TinyORM uses them in header files, you have to install them before you can use TinyORM. The tabulate library is only needed in the tom migrations it's used by the migrate:status command.

There are two ways how to install the range-v3 and tabulate libraries using vcpkg.

Using vcpkg.json (manifest mode)

Create a vcpkg.json file with the following content. CMake example below uses this method.

cd HelloWorld
vim vcpkg.json
vcpkg.json
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "tinyorm-helloworld",
"version-semver": "0.1.0",
"description": "Hello world console application for TinyORM C++ library",
"homepage": "https://github.com/silverqx/TinyORM",
"documentation": "https://www.tinyorm.org/building/hello-world",
"maintainers": "Silver Zachara <silver.zachara@gmail.com>",
"supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",
"dependencies": [
"range-v3",
"tabulate"
]
}
note

Only CMake via the toolchain file supports this method.

Using vcpkg install (manually)

This method can be used with both CMake and qmake.

cd ../../vcpkg

vcpkg search range-v3
vcpkg search tabulate
vcpkg install range-v3 tabulate
vcpkg list

Source code

Let's start in the HelloWorld project folder.

cd /HelloWorld/HelloWorld

Create main.cpp source file.

vim main.cpp
tip

To paste a source code correctly in vim, press Shift + p.

And paste the following code.

main.cpp
#include <QCoreApplication>
#include <QDebug>

#ifdef _WIN32
# include <qt_windows.h>
#endif

#include <orm/db.hpp>

using Orm::DB;

int main(int argc, char *argv[])
{
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
// SetConsoleOutputCP(1250);
#endif

/* Needed from Qt v6.5.3 to avoid:
qt.core.qobject.connect: QObject::connect(QObject, Unknown): invalid nullptr parameter */
QCoreApplication app(argc, argv);

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QSQLITE"},
{"database", qEnvironmentVariable("TINYORM_HELLOWORLD_DB_SQLITE_DATABASE",
"../../HelloWorld.sqlite3")},
{"check_database_exists", true},
});

auto posts = DB::select("select * from posts");

while(posts.next())
qDebug() << posts.value("id").toULongLong()
<< posts.value("name").toString();
}
caution

The QSqlDatabase depends on QCoreApplication from Qt v6.5.3 so you must create the QCoreApplication instance before you will call anything from the TinyORM library. 🫤 The change was made here.

Hello world with CMake

Create a folder for the CMake build.

cd ..
mkdir HelloWorld-builds-cmake/build-debug

cd HelloWorld

CMake project

Create CMakeLists.txt file with the following content.

cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)

project(HelloWorld LANGUAGES CXX)

# build tree
list(APPEND CMAKE_PREFIX_PATH "/TinyORM/TinyORM-builds-cmake/build-debug")

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(HelloWorld
main.cpp
)

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)

target_link_libraries(HelloWorld
PRIVATE
Qt${QT_VERSION_MAJOR}::Core
TinyOrm::TinyOrm
)

FetchContent

If you don't have cloned and built the TinyORM library, or you want to quickly try TinyORM without wasting time with cloning and building the TinyORM library, then you can use CMake's FetchContent module that will do all of this for you.

Instead of providing a path by the CMAKE_PREFIX_PATH (or using the User Package Registry) like in the example below:

# build tree
list(APPEND CMAKE_PREFIX_PATH "/TinyORM/TinyORM-builds-cmake/build-debug")

You can use the FetchContent module like in the following example.

cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)

project(HelloWorld LANGUAGES CXX)

# FetchContent method
include(FetchContent)
FetchContent_Declare(TinyOrm
GIT_REPOSITORY https://github.com/silverqx/TinyORM.git
GIT_TAG origin/main
OVERRIDE_FIND_PACKAGE
)
# Here you can configure TinyORM CMake options
set(MYSQL_PING OFF)
set(TOM_EXAMPLE ON)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(HelloWorld
main.cpp
)

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)

target_link_libraries(HelloWorld
PRIVATE
Qt${QT_VERSION_MAJOR}::Core
TinyOrm::TinyOrm
)

How FetchContent module works

The FetchContent_Declare command is like calling the git clone inside the build folder and then adding a cloned folder in a similar way as the add_subdirectory(<cloned_folder>) command does.

The FetchContent_MakeAvailable(<package>) internally calls the find_package(<package>) command or if you pass the OVERRIDE_FIND_PACKAGE argument, then you don't have to call the the FetchContent_MakeAvailable, but you must call the find_package(<package> x.y.z CONFIG REQUIRED) command manually.

info

An advantage of the OVERRIDE_FIND_PACKAGE argument is that you can call the find_package command much later, and you can insert additional configurations between.

Build Hello world

Now you are ready to configure HelloWorld CMake application.

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

And build.

cmake --build . --target all
tip

Enable the TINYORM_STRICT_MODE environment variable to produce better code and to follow good code practices.

Execute Hello world

Do not forget to add TinyOrm0d.dll on the path on Windows and on the LD_LIBRARY_PATH on Linux, so HelloWorld application can find it during execution, as is described here.

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

Execute HelloWorld example.

.\HelloWorld.exe

The output will look like this.

Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts
1 "First Post"
2 "Second Post"

Hello world with qmake

Create a folder for the qmake build.

cd /HelloWorld

mkdir HelloWorld-builds-qmake

The source code is the same as for the HelloWorld CMake example.

qmake project

Create HelloWorld.pro qmake file with the following content.

cd HelloWorld
vim HelloWorld.pro
tip

To paste a source code correctly in vim, press Shift + p.

HelloWorld.pro
QT -= gui

TEMPLATE = app

CONFIG *= cmdline

DEFINES *= PROJECT_TINYORM_HELLOWORLD

SOURCES += $$PWD/main.cpp

# Auto-configure TinyORM library 🔥
include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)
caution

The exact folders structure is crucial in this example because the paths to the TinyORM source and build folders are relative.

caution

Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

Auto-configure using .qmake.conf and .env

If you want to have properly configured DEFINES (C preprocessor macros) or have Qt headers marked as system headers, then you need to specify a path to the TinyORM qmake features (.prf files) which handle this correctly; this path is provided by the QMAKEFEATURES variable and can only be set in the .qmake.conf file.

tip

Read the Consume TinyOrm library (qmake) section, as everything that is described in that section applies here as well.

Create the .qmake.conf file in the HelloWorld project root folder with the following content.

.qmake.conf
# Path to the PARENT folder of the TinyORM source folder
TINY_MAIN_DIR = $$clean_path($$PWD/../../TinyORM/)
# To find .env and .env.$$QMAKE_PLATFORM files
TINY_DOTENV_ROOT = $$PWD
# Path to the current build tree (used to guess the TinyORM build tree)
#TINY_BUILD_TREE = $$shadowed($$PWD)

# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants
QMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)

Then, create a .env.(win32|unix|mingw) file in the HelloWorld project root folder with the following content.

# Names and values of these qmake variables are crucial, they are used in HelloWorld.pro
# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

# Path to the TinyORM build folder
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug/)

# Path to the vcpkg - range-v3
# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty
TINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)
TINY_VCPKG_TRIPLET = x64-windows

# Enable ccache wrapper
#CONFIG *= tiny_ccache_win32

Don't forget to update the TINYORM_BUILD_TREE and TINY_VCPKG_ROOT folder paths to your needs if you are not using the recommended Folders structure.

You can use the Partial guessing of the TINYORM_BUILD_TREE if you don't like to specify it manually. Just comment out the TINYORM_BUILD_TREE and uncomment the TINY_BUILD_TREE = $$shadowed($$PWD) in the .qmake.conf file.

tip

You can entirely avoid the .env files, just move the TINYORM_BUILD_TREE to the .qmake.conf or remove it by help of Partial guessing of the TINYORM_BUILD_TREE and set the VCPKG_ROOT environment variable at system level as is described in Set up vcpkg environment.

info

Configuring by the .qmake.conf and .env files has one big advantage, which is that you don't have to modify the project files.

Build Hello world

tip

I recommend creating a new Session in the QtCreator IDE as is described here.

Now you can open the HelloWorld.pro project in the QtCreator IDE.

This will open the Configure Project tab, select some kit and update build folder paths to meet our folders structure or like you want.

HelloWorld - QtCreator - Configure Project
tip

You can force the QtCreator to generate a build folders structure as is described here.

You are ready to configure build options, hit Ctrl+5 to open Project Settings tab and select Build in the left sidebar to open the Build Settings, it should look similar to the following picture.

HelloWorld - QtCreator - Build Settings

Disable QML debugging and profiling and Qt Quick Compiler, they are not used.

In the left sidebar open Dependencies and check TinyORM project and Synchronize configuration, this setting ensures that the current project will be rebuilt correctly when the TinyORM library source code changes.

Everything is ready to build, you can press Ctrl+b to build the project.

Execute Hello world

The 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 LD_LIBRARY_PATH on Linux.

The only thing you might want to change is to run the HelloWorld example in the new terminal window. To do so, hit Ctrl+5 to open the Project Settings tab and select Run in the left sidebar to open the Run Settings, then in the Run section select the Run in terminal checkbox.

To execute the HelloWorld example press Ctrl + r.

The output will look like this.

Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts
1 "First Post"
2 "Second Post"
- - +

Building: Hello world

+ +

Introduction

+

We will try to create the simplest working console application, in the terminal with the CMake and in the QtCreator IDE with the qmake build systems.

+

The HelloWorld example also expects the following folders structure, let's create them.

+
cd 
mkdir HelloWorld/HelloWorld
cd HelloWorld
+

Prepare SQLite 3 database

+

The easiest way to demonstrate the HelloWorld example will be with a SQLite 3 database.

+

Execute the following command in the terminal to create and insert two rows into the SQLite 3 database.

+
sqlite3 HelloWorld.sqlite3 "
create table posts(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name VARCHAR NOT NULL);
insert into posts values(1, 'First Post');
insert into posts values(2, 'Second Post');
select * from posts;"
+

Install dependencies

+

First, install the vcpkg package manager as is described here.

+

The range-v3 and tabulate libraries are required dependencies because TinyORM uses them in header files, you have to install them before you can use TinyORM. The tabulate library is only needed in the tom migrations it's used by the migrate:status command.

+

There are two ways how to install the range-v3 and tabulate libraries using vcpkg.

+

Using vcpkg.json (manifest mode)

+

Create a vcpkg.json file with the following content. CMake example below uses this method.

+
cd HelloWorld
vim vcpkg.json
+
vcpkg.json
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "tinyorm-helloworld",
"version-semver": "0.1.0",
"maintainers": "Silver Zachara <silver.zachara@gmail.com>",
"description": "Hello world console application for TinyORM C++ library",
"homepage": "https://github.com/silverqx/TinyORM",
"documentation": "https://www.tinyorm.org/building/hello-world",
"supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",
"dependencies": [
"range-v3",
"tabulate"
]
}
+
note

Only CMake via the toolchain file supports this method.

+

Using vcpkg install (manually)

+

This method can be used with both CMake and qmake.

+
cd ../../vcpkg

vcpkg search range-v3
vcpkg search tabulate
vcpkg install range-v3 tabulate
vcpkg list
+

Source code

+

Let's start in the HelloWorld project folder.

+
cd /HelloWorld/HelloWorld
+

Create main.cpp source file.

+
vim main.cpp
+
tip

To paste a source code correctly in vim, press Shift + p.

+

And paste the following code.

+
main.cpp
#include <QCoreApplication>
#include <QDebug>

#ifdef _WIN32
# include <qt_windows.h>
#endif

#include <orm/db.hpp>

using Orm::DB;

int main(int argc, char *argv[])
{
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
// SetConsoleOutputCP(1250);
#endif

/* Needed from Qt v6.5.3 to avoid:
qt.core.qobject.connect: QObject::connect(QObject, Unknown): invalid nullptr parameter */
QCoreApplication app(argc, argv);

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QSQLITE"},
{"database", qEnvironmentVariable("TINYORM_HELLOWORLD_DB_SQLITE_DATABASE",
"../../HelloWorld.sqlite3")},
{"check_database_exists", true},
});

auto posts = DB::select("select * from posts");

while(posts.next())
qDebug() << posts.value("id").toULongLong()
<< posts.value("name").toString();
}
+
warning

The QSqlDatabase depends on QCoreApplication from Qt v6.5.3 so you must create the QCoreApplication instance before you will call anything from the TinyORM library. 🫤 The change was made here.

+

Hello world with CMake

+

Create a folder for the CMake build.

+
cd ..
mkdir HelloWorld-builds-cmake/build-debug

cd HelloWorld
+

CMake project

+

Create CMakeLists.txt file with the following content.

+
cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)

project(HelloWorld LANGUAGES CXX)

# build tree
list(APPEND CMAKE_PREFIX_PATH "/TinyORM/TinyORM-builds-cmake/build-debug")

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(HelloWorld
main.cpp
)

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)

target_link_libraries(HelloWorld
PRIVATE
Qt${QT_VERSION_MAJOR}::Core
TinyOrm::TinyOrm
)
+

FetchContent

+

If you don't have cloned and built the TinyORM library, or you want to quickly try TinyORM without wasting time with cloning and building the TinyORM library, then you can use CMake's FetchContent module that will do all of this for you.

+

Instead of providing a path by the CMAKE_PREFIX_PATH (or using the User Package Registry) like in the example below:

+
# build tree
list(APPEND CMAKE_PREFIX_PATH "/TinyORM/TinyORM-builds-cmake/build-debug")
+

You can use the FetchContent module like in the following example.

+
cmake_minimum_required(VERSION VERSION 3.22...3.29 FATAL_ERROR)

project(HelloWorld LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# FetchContent method
include(FetchContent)
FetchContent_Declare(TinyOrm
GIT_REPOSITORY https://github.com/silverqx/TinyORM.git
GIT_TAG origin/main
OVERRIDE_FIND_PACKAGE
)
# Here you can configure TinyORM CMake options
set(MYSQL_PING OFF)
set(TOM_EXAMPLE ON)

add_executable(HelloWorld
main.cpp
)

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)

target_link_libraries(HelloWorld
PRIVATE
Qt${QT_VERSION_MAJOR}::Core
TinyOrm::TinyOrm
)
+

How FetchContent module works

+

The FetchContent_Declare command is like calling the git clone inside the build folder and then adding a cloned folder in a similar way as the add_subdirectory(<cloned_folder>) command does.

+

The FetchContent_MakeAvailable(<package>) internally calls the find_package(<package>) command or if you pass the OVERRIDE_FIND_PACKAGE argument, then you don't have to call the the FetchContent_MakeAvailable, but you must call the find_package(<package> x.y.z CONFIG REQUIRED) command manually.

+
info

An advantage of the OVERRIDE_FIND_PACKAGE argument is that you can call the find_package command much later, and you can insert additional configurations between.

+

Build Hello world

+

Now you are ready to configure HelloWorld CMake application.

+
cd ../HelloWorld-builds-cmake/build-debug
+
cmake.exe `
-S "/HelloWorld/HelloWorld" `
-B "/HelloWorld/HelloWorld-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/HelloWorld"
+

And build.

+
cmake --build . --target all
+
tip

Enable the TINYORM_STRICT_MODE environment variable to produce better code and to follow good code practices.

+

Execute Hello world

+

Do not forget to add TinyOrm0d.dll on the path on Windows and on the LD_LIBRARY_PATH on Linux, so HelloWorld application can find it during execution, as is described here.

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

Execute HelloWorld example.

+
.\HelloWorld.exe
+

The output will look like this.

+
Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts
1 "First Post"
2 "Second Post"
+

Hello world with qmake

+

Create a folder for the qmake build.

+
cd /HelloWorld

mkdir HelloWorld-builds-qmake
+

The source code is the same as for the HelloWorld CMake example.

+

qmake project

+

Create HelloWorld.pro qmake file with the following content.

+
cd HelloWorld
vim HelloWorld.pro
+
tip

To paste a source code correctly in vim, press Shift + p.

+
HelloWorld.pro
QT -= gui

TEMPLATE = app

CONFIG *= cmdline

DEFINES *= PROJECT_TINYORM_HELLOWORLD

SOURCES += $$PWD/main.cpp

# Auto-configure TinyORM library 🔥
include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)
+
warning

The exact folders structure is crucial in this example because the paths to the TinyORM source and build folders are relative.

+
warning

Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

+

Auto-configure using .qmake.conf and .env

+

If you want to have properly configured DEFINES (C preprocessor macros) or have Qt headers marked as system headers, then you need to specify a path to the TinyORM qmake features (.prf files) which handle this correctly; this path is provided by the QMAKEFEATURES variable and can only be set in the .qmake.conf file.

+
tip

Read the Consume TinyOrm library (qmake) section, as everything that is described in that section applies here as well.

+

Create the .qmake.conf file in the HelloWorld project root folder with the following content.

+
.qmake.conf
# Path to the PARENT folder of the TinyORM source folder
TINY_MAIN_DIR = $$clean_path($$PWD/../../TinyORM/)
# To find .env and .env.$$QMAKE_PLATFORM files
TINY_DOTENV_ROOT = $$PWD
# Path to the current build tree (used to guess the TinyORM build tree)
#TINY_BUILD_TREE = $$shadowed($$PWD)

# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants
QMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)
+

Then, create a .env.(win32|unix|mingw) file in the HelloWorld project root folder with the following content.

+
# Names and values of these qmake variables are crucial, they are used in HelloWorld.pro
# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

# Path to the TinyORM build folder
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug/)

# Path to the vcpkg - range-v3
# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty
TINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)
TINY_VCPKG_TRIPLET = x64-windows

# Enable ccache wrapper
#CONFIG *= tiny_ccache_win32
+

Don't forget to update the TINYORM_BUILD_TREE and TINY_VCPKG_ROOT folder paths to your needs if you are not using the recommended Folders structure.

+

You can use the Partial guessing of the TINYORM_BUILD_TREE if you don't like to specify it manually. Just comment out the TINYORM_BUILD_TREE and uncomment the TINY_BUILD_TREE = $$shadowed($$PWD) in the .qmake.conf file.

+
tip

You can entirely avoid the .env files, just move the TINYORM_BUILD_TREE to the .qmake.conf or remove it by help of Partial guessing of the TINYORM_BUILD_TREE and set the VCPKG_ROOT environment variable at system level as is described in Set up vcpkg environment.

+
info

Configuring by the .qmake.conf and .env files has one big advantage, which is that you don't have to modify the project files.

+

Build Hello world

+
tip

I recommend creating a new Session in the QtCreator IDE as is described here.

+

Now you can open the HelloWorld.pro project in the QtCreator IDE.

+

This will open the Configure Project tab, select some kit and update build folder paths to meet our folders structure or like you want.

+HelloWorld - QtCreator - Configure Project +
tip

You can force the QtCreator to generate a build folders structure as is described here.

+

You are ready to configure build options, hit Ctrl+5 to open Project Settings tab and select Build in the left sidebar to open the Build Settings, it should look similar to the following picture.

+HelloWorld - QtCreator - Build Settings +

Disable QML debugging and profiling and Qt Quick Compiler, they are not used.

+

In the left sidebar open Dependencies and check TinyORM project and Synchronize configuration, this setting ensures that the current project will be rebuilt correctly when the TinyORM library source code changes.

+

Everything is ready to build, you can press Ctrl+b to build the project.

+

Execute Hello world

+

The 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 LD_LIBRARY_PATH on Linux.

+

The only thing you might want to change is to run the HelloWorld example in the new terminal window. To do so, hit Ctrl+5 to open the Project Settings tab and select Run in the left sidebar to open the Run Settings, then in the Run section select the Run in terminal checkbox.

+

To execute the HelloWorld example press Ctrl + r.

+

The output will look like this.

+
Executed prepared query (6ms, -1 results, 0 affected, tinyorm_default) : select * from posts
1 "First Post"
2 "Second Post"
\ No newline at end of file diff --git a/building/migrations.html b/building/migrations.html index b5668f197..b86b1ead1 100644 --- a/building/migrations.html +++ b/building/migrations.html @@ -1,9 +1,9 @@ - + - -Building: Migrations - TinyORM + +Building: Migrations - TinyORM @@ -13,14 +13,168 @@ - - - + + + -
-

Building: Migrations

Introduction

We will try to create a working migrations console application called as tom in the terminal with the CMake and in the QtCreator IDE with the qmake build systems.

The tom console application also expects the following folders structure, let's create them.

cd 
mkdir tom/tom
cd tom

TinyORM source tree contains the tom example application, you can inspire or look at the source code. Also, TinyORM unit tests use a tom migrations internally to create the database structure, internally called as the tom migrations for unit tests.

All these three console applications the tom example, tom migrations for unit tests, and the application described in this tutorial have practically identical source code (the main.cpp file).

note

The tom is able to generate DDL queries for all the supported databases databases.

info

You can see the Tom showcase image of how the resulting tom console application will look like.

Install dependencies

First, install the vcpkg package manager as is described here.

The range-v3 and tabulate libraries are required dependencies because TinyORM uses them in header files, you have to install them before you can use TinyORM. The tabulate library is only needed in the tom migrations it's used by the migrate:status command.

There are two ways how to install the range-v3 and tabulate libraries using vcpkg.

Also, don't forget to build the TinyORM library with the tom source code enabled (it's enabled by default) as is described here.

Using vcpkg.json (manifest mode)

Create a vcpkg.json file with the following content. CMake example below uses this method.

cd tom
vim vcpkg.json
vcpkg.json
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "tom",
"version-semver": "0.1.0",
"description": "Tom console application for TinyORM C++ library",
"homepage": "https://github.com/silverqx/TinyORM",
"documentation": "https://www.tinyorm.org/building/migrations",
"maintainers": "Silver Zachara <silver.zachara@gmail.com>",
"supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",
"dependencies": [
"range-v3",
"tabulate"
]
}
note

Only CMake via the toolchain file supports this method.

Using vcpkg install (manually)

This method can be used with both CMake and qmake.

cd ../../vcpkg

vcpkg search range-v3
vcpkg search tabulate
vcpkg install range-v3 tabulate
vcpkg list

Source code

Let's start in the tom project folder.

cd /tom/tom

Main file

Create main.cpp source file.

vim main.cpp
tip

To paste a source code correctly in vim, press Shift + p.

And paste the following code.

main.cpp
#include <orm/db.hpp>

#include <tom/application.hpp>

#include "migrations/2014_10_12_000000_create_posts_table.hpp"

#include "seeders/databaseseeder.hpp"

using Orm::DatabaseManager;
using Orm::DB;

using TomApplication = Tom::Application;

using namespace Migrations; // NOLINT(google-build-using-namespace)
using namespace Seeders; // NOLINT(google-build-using-namespace)

/*! Create the database manager instance and add a database connection. */
std::shared_ptr<DatabaseManager> setupDatabaseManager();

/*! C++ main function. */
int main(int argc, char *argv[])
{
try {
// Ownership of the shared_ptr()
auto db = setupDatabaseManager();

return TomApplication(argc, argv, std::move(db), "TOM_EXAMPLE_ENV")
.migrations<CreatePostsTable>()
.seeders<DatabaseSeeder>()
// Fire it up 🔥🚀✨
.run();

} catch (const std::exception &e) {

TomApplication::logException(e);
}

return EXIT_FAILURE;
}

std::shared_ptr<DatabaseManager> setupDatabaseManager()
{
using namespace Orm::Constants; // NOLINT(google-build-using-namespace)

// Ownership of the shared_ptr()
return DB::create({
{driver_, QMYSQL},
{host_, qEnvironmentVariable("DB_MYSQL_HOST", H127001)},
{port_, qEnvironmentVariable("DB_MYSQL_PORT", P3306)},
{database_, qEnvironmentVariable("DB_MYSQL_DATABASE", EMPTY)},
{username_, qEnvironmentVariable("DB_MYSQL_USERNAME", EMPTY)},
{password_, qEnvironmentVariable("DB_MYSQL_PASSWORD", EMPTY)},
{charset_, qEnvironmentVariable("DB_MYSQL_CHARSET", UTF8MB4)},
{collation_, qEnvironmentVariable("DB_MYSQL_COLLATION", UTF8MB40900aici)},
{timezone_, TZ00},
/* Specifies what time zone all QDateTime-s will have, the overridden default is
the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use
the system local time. */
{qt_timezone, QVariant::fromValue(Qt::UTC)},
{strict_, true},
},
QStringLiteral("tinyorm_tom_mysql")); // shell:connection
}
tip

If you have defined more database connections then you can tag the lines with the database connection names with the // shell:connection comment and this connection names will be provided to the bash, zsh, pwsh completions for the --database= option 😎, example.

Migrations

If you have already built the tom application then you can generate a migrations using the make:migration command 😎.

tom make:migration create_posts_table

Below is the expected folders structure for the migrations. The migrations.pri file is used only by the qmake build system and is not needed with CMake builds.

tom/
└── database/
├── migrations/
├── seeders/
├── migrations.pri
└── seeders.pri

Let's create the first migration manually.

mkdir database/migrations

vim database/migrations/2014_10_12_000000_create_posts_table.hpp

And paste the following code.

database/migrations/2014_10_12_000000_create_posts_table.hpp
#pragma once

#include <tom/migration.hpp>

namespace Migrations
{

struct CreatePostsTable : Migration
{
/*! Filename of the migration file. */
T_MIGRATION

/*! Run the migrations. */
void up() const override
{
Schema::create("posts", [](Blueprint &table)
{
table.id();

table.string(NAME);
table.timestamps();
});
}

/*! Reverse the migrations. */
void down() const override
{
Schema::dropIfExists("posts");
}
};

} // namespace Migrations
tip

The TinyORM source tree contains the 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.

info

If you want, you can also build the tom application without the migrations, simply comment out the migrations method and the corresponding #include "migrations/xyz.hpp" files.

Seeders

If you have already built the tom application then you can generate a seeder using the make:seeder command 😎.

tom make:seeder PostSeeder

The expected folders structure is described a few paragraphs above. The seeders.pri file is used only by the qmake build system and is not needed with CMake builds.

Let's create the root seeder class manually.

mkdir database/seeders

vim database/seeders/databaseseeder.hpp

And paste the following code.

database/seeders/databaseseeder.hpp
#pragma once

#include <tom/seeder.hpp>

namespace Seeders
{

/*! Main database seeder. */
struct DatabaseSeeder : Seeder
{
/*! Run the database seeders. */
void run() override
{
DB::table("posts")->insert({
{{"name", "1. post"}},
{{"name", "2. post"}},
});
}
};

} // namespace Seeders
tip

The TinyORM source tree contains the 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.

tip

You can create more seeder classes like this and use the call<>() method to invoke them as is described in the Calling Additional Seeders section.

Migrations with CMake

Create a folder for the CMake build.

cd ..
mkdir tom-builds-cmake/build-debug

cd tom

CMake project

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.

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_INSTALL_PREFIX:PATH="/tmp/tom"

And build.

cmake --build . --target all

Execute migrations

Do not forget to add TinyOrm0d.dll on the path on Windows and on the LD_LIBRARY_PATH on Linux, so tom application can find it during execution, as is described here.

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

Execute tom application.

.\tom.exe migrate:status

The output will look something like this.

Tom migrations - migrate:status command output

See also the final thoughts on how to verify the tom executable file properties.

Happy migrating 🎉👌

Migrations with qmake

Create a folder for the qmake build.

cd /tom

mkdir tom-builds-qmake

The source code is the same as for the Migrations with CMake console application.

qmake project

Create tom.pro qmake file with the following content.

cd tom
vim tom.pro
tip

To paste a source code correctly in vim, press Shift + p.

tom.pro
QT -= gui

TEMPLATE = app
TARGET = tom

CONFIG *= cmdline

DEFINES *= PROJECT_TOM

SOURCES += $$PWD/main.cpp

# Database migrations
include($$PWD/database/migrations.pri)
# Database seeders
include($$PWD/database/seeders.pri)

# Auto-configure TinyORM library for the migrations purposes 🔥
include($$TINY_MAIN_DIR/TinyORM/qmake/tom.pri)
caution

The exact folders structure is crucial in this example because the paths to the TinyORM source and build folders are relative.

caution

Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

Auto-configure using .qmake.conf and .env

If you want to have properly configured 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 TinyORM qmake features (.prf files) which handle this correctly; this path is provided by the QMAKEFEATURES variable and can only be set in the .qmake.conf file.

tip

Read the Consume TinyOrm library (qmake) section, as everything that is described in that section applies here as well.

Create the .qmake.conf file in the tom application root folder with the following content.

.qmake.conf
# Path to the PARENT folder of the TinyORM source folder
TINY_MAIN_DIR = $$clean_path($$PWD/../../TinyORM/)
# To find .env and .env.$$QMAKE_PLATFORM files
TINY_DOTENV_ROOT = $$PWD
# Path to the current build tree (used to guess the TinyORM build tree)
#TINY_BUILD_TREE = $$shadowed($$PWD)

# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants
QMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)

Then, create a .env.(win32|unix|mingw) file in the tom application root folder with the following content.

# Names and values of these qmake variables are crucial, they are used in the tom.pro
# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

# Path to the TinyORM build folder
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug/)

# Path to the vcpkg - range-v3 and tabulate
# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty
TINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)
TINY_VCPKG_TRIPLET = x64-windows

# Enable ccache wrapper
#CONFIG *= tiny_ccache_win32

Don't forget to update the TINYORM_BUILD_TREE and TINY_VCPKG_ROOT folder paths to your needs if you are not using the recommended Folders structure.

You can use the Partial guessing of the TINYORM_BUILD_TREE if you don't like to specify it manually. Just comment out the TINYORM_BUILD_TREE and uncomment the TINY_BUILD_TREE = $$shadowed($$PWD) in the .qmake.conf file.

tip

You can entirely avoid the .env files, just move the TINYORM_BUILD_TREE to the .qmake.conf or remove it by help of Partial guessing of the TINYORM_BUILD_TREE and set the VCPKG_ROOT environment variable at system level as is described in Set up vcpkg environment.

info

Configuring by the .qmake.conf and .env files has one big advantage, which is that you don't have to modify the project files.

Migrations source files

Create database/migrations.pri file and paste the following code.

database/migrations.pri
INCLUDEPATH *= $$PWD

HEADERS += \
$$PWD/migrations/2014_10_12_000000_create_posts_table.hpp \

Seeders source files

Create database/seeders.pri file and paste the following code.

database/seeders.pri
INCLUDEPATH *= $$PWD

HEADERS += \
$$PWD/seeders/databaseseeder.hpp \

Build migrations

tip

I recommend creating a new Session in the QtCreator IDE as is described here.

Now you can open the tom.pro project in the QtCreator IDE.

This will open the Configure Project tab, select some kit and update build folder paths to meet our folders structure or like you want.

tom - QtCreator - Configure Project
tip

You can force the QtCreator to generate a build folders structure as is described here.

You are ready to configure build options, hit Ctrl+5 to open Project Settings tab and select Build in the left sidebar to open the Build Settings, it should look similar to the following picture.

tom - QtCreator - Build Settings

Disable QML debugging and profiling and Qt Quick Compiler, they are not used.

In the left sidebar open Dependencies and check TinyORM project and Synchronize configuration, this setting ensures that the current project will be rebuilt correctly when the TinyORM library source code changes.

Everything is ready to build, you can press Ctrl+b to build the project.

Execute migrations

The 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 LD_LIBRARY_PATH on Linux.

The only thing you might want to change is to run the tom application in the new terminal window. To do so, hit Ctrl+5 to open the Project Settings tab and select Run in the left sidebar to open the Run Settings, then in the Run section select the Run in terminal checkbox.

You can also set the Command line arguments in this Run section, eg. the migrate:status.

To execute the tom application press Ctrl + r.

The output will look very similar to this if you add more migrations.

Tom migrations - migrate:status command output

Happy migrating 🎉👌

Finish

As the last thing, you can check that all the file properties were correctly set by the rc compiler.

Find the tom.exe file and press Alt + Enter to open the file properties. To check the executable manifest you can use eg. the Resource Hacker.

tom.exe file properties detail
- - +

Building: Migrations

+ +

Introduction

+

We will try to create a working migrations console application called as tom in the terminal with the CMake and in the QtCreator IDE with the qmake build systems.

+

The tom console application also expects the following folders structure, let's create them.

+
cd 
mkdir tom/tom
cd tom
+

TinyORM source tree contains the tom example application, you can inspire or look at the source code. Also, TinyORM unit tests use a tom migrations internally to create the database structure, internally called as the tom migrations for unit tests.

+

All these three console applications the tom example, tom migrations for unit tests, and the application described in this tutorial have practically identical source code (the main.cpp file).

+
note

The tom is able to generate DDL queries for all the supported databases databases.

+
info

You can see the Tom showcase image of how the resulting tom console application will look like.

+

Install dependencies

+

First, install the vcpkg package manager as is described here.

+

The range-v3 and tabulate libraries are required dependencies because TinyORM uses them in header files, you have to install them before you can use TinyORM. The tabulate library is only needed in the tom migrations it's used by the migrate:status command.

+

There are two ways how to install the range-v3 and tabulate libraries using vcpkg.

+

Also, don't forget to build the TinyORM library with the tom source code enabled (it's enabled by default) as is described here.

+

Using vcpkg.json (manifest mode)

+

Create a vcpkg.json file with the following content. CMake example below uses this method.

+
cd tom
vim vcpkg.json
+
vcpkg.json
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "tom",
"version-semver": "0.1.0",
"maintainers": "Silver Zachara <silver.zachara@gmail.com>",
"description": "Tom console application for TinyORM C++ library",
"homepage": "https://github.com/silverqx/TinyORM",
"documentation": "https://www.tinyorm.org/building/migrations",
"supports": "!(uwp | arm | android | emscripten | osx | ios | xbox | freebsd | openbsd | wasm32)",
"dependencies": [
"range-v3",
"tabulate"
]
}
+
note

Only CMake via the toolchain file supports this method.

+

Using vcpkg install (manually)

+

This method can be used with both CMake and qmake.

+
cd ../../vcpkg

vcpkg search range-v3
vcpkg search tabulate
vcpkg install range-v3 tabulate
vcpkg list
+

Source code

+

Let's start in the tom project folder.

+
cd /tom/tom
+

Main file

+

Create main.cpp source file.

+
vim main.cpp
+
tip

To paste a source code correctly in vim, press Shift + p.

+

And paste the following code.

+ +
main.cpp
#include <orm/db.hpp>

#include <tom/application.hpp>

#include "migrations/2014_10_12_000000_create_posts_table.hpp"

#include "seeders/databaseseeder.hpp"

using Orm::DatabaseManager;
using Orm::DB;

using TomApplication = Tom::Application;

using namespace Migrations; // NOLINT(google-build-using-namespace)
using namespace Seeders; // NOLINT(google-build-using-namespace)

/*! Create the database manager instance and add a database connection. */
std::shared_ptr<DatabaseManager> setupDatabaseManager();

/*! C++ main function. */
int main(int argc, char *argv[])
{
try {
// Ownership of the shared_ptr()
auto db = setupDatabaseManager();

return TomApplication(argc, argv, std::move(db), "TOM_EXAMPLE_ENV")
.migrations<CreatePostsTable>()
.seeders<DatabaseSeeder>()
// Fire it up 🔥🚀✨
.run();

} catch (const std::exception &e) {

TomApplication::logException(e);
}

return EXIT_FAILURE;
}

std::shared_ptr<DatabaseManager> setupDatabaseManager()
{
using namespace Orm::Constants; // NOLINT(google-build-using-namespace)

// Ownership of the shared_ptr()
return DB::create({
{driver_, QMYSQL},
{host_, qEnvironmentVariable("DB_MYSQL_HOST", H127001)},
{port_, qEnvironmentVariable("DB_MYSQL_PORT", P3306)},
{database_, qEnvironmentVariable("DB_MYSQL_DATABASE", EMPTY)},
{username_, qEnvironmentVariable("DB_MYSQL_USERNAME", EMPTY)},
{password_, qEnvironmentVariable("DB_MYSQL_PASSWORD", EMPTY)},
{charset_, qEnvironmentVariable("DB_MYSQL_CHARSET", UTF8MB4)},
{collation_, qEnvironmentVariable("DB_MYSQL_COLLATION", UTF8MB40900aici)},
{timezone_, TZ00},
/* Specifies what time zone all QDateTime-s will have, the overridden default is
the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use
the system local time. */
{qt_timezone, QVariant::fromValue(Qt::UTC)},
{strict_, true},
},
QStringLiteral("tinyorm_tom_mysql")); // shell:connection
}
+
tip

If you have defined more database connections then you can tag the lines with the database connection names with the // shell:connection comment and this connection names will be provided to the bash, zsh, pwsh completions for the --database= option 😎, example.

+

Migrations

+

If you have already built the tom application then you can generate a migrations using the make:migration command 😎.

+
tom make:migration create_posts_table
+

Below is the expected folders structure for the migrations. The migrations.pri file is used only by the qmake build system and is not needed with CMake builds.

+ +
tom/
└── database/
├── migrations/
├── seeders/
├── migrations.pri
└── seeders.pri
+

Let's create the first migration manually.

+
mkdir database/migrations

vim database/migrations/2014_10_12_000000_create_posts_table.hpp
+

And paste the following code.

+
database/migrations/2014_10_12_000000_create_posts_table.hpp
#pragma once

#include <tom/migration.hpp>

namespace Migrations
{

struct CreatePostsTable : Migration
{
/*! Filename of the migration file. */
T_MIGRATION

/*! Run the migrations. */
void up() const override
{
Schema::create("posts", [](Blueprint &table)
{
table.id();

table.string(NAME);
table.timestamps();
});
}

/*! Reverse the migrations. */
void down() const override
{
Schema::dropIfExists("posts");
}
};

} // namespace Migrations
+
tip

The TinyORM source tree contains the 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.

+
info

If you want, you can also build the tom application without the migrations, simply comment out the migrations method and the corresponding #include "migrations/xyz.hpp" files.

+

Seeders

+

If you have already built the tom application then you can generate a seeder using the make:seeder command 😎.

+
tom make:seeder PostSeeder
+

The expected folders structure is described a few paragraphs above. The seeders.pri file is used only by the qmake build system and is not needed with CMake builds.

+

Let's create the root seeder class manually.

+
mkdir database/seeders

vim database/seeders/databaseseeder.hpp
+

And paste the following code.

+
database/seeders/databaseseeder.hpp
#pragma once

#include <tom/seeder.hpp>

namespace Seeders
{

/*! Main database seeder. */
struct DatabaseSeeder : Seeder
{
/*! Run the database seeders. */
void run() override
{
DB::table("posts")->insert({
{{"name", "1. post"}},
{{"name", "2. post"}},
});
}
};

} // namespace Seeders
+
tip

The TinyORM source tree contains the 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.

+
tip

You can create more seeder classes like this and use the call<>() method to invoke them as is described in the Calling Additional Seeders section.

+

Migrations with CMake

+

Create a folder for the CMake build.

+
cd ..
mkdir tom-builds-cmake/build-debug

cd tom
+

CMake project

+

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.

+
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.

+
cmake --build . --target all
+

Execute migrations

+

Do not forget to add TinyOrm0d.dll on the path on Windows and on the LD_LIBRARY_PATH on Linux, so tom application can find it during execution, as is described here.

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

Execute tom application.

+
.\tom.exe migrate:status
+

The output will look something like this.

+Tom migrations - migrate:status command output +

See also the final thoughts on how to verify the tom executable file properties.

+

Happy migrating 🎉👌

+

Migrations with qmake

+

Create a folder for the qmake build.

+
cd /tom

mkdir tom-builds-qmake
+

The source code is the same as for the Migrations with CMake console application.

+

qmake project

+

Create tom.pro qmake file with the following content.

+
cd tom
vim tom.pro
+
tip

To paste a source code correctly in vim, press Shift + p.

+
tom.pro
QT -= gui

TEMPLATE = app
TARGET = tom

CONFIG *= cmdline

DEFINES *= PROJECT_TOM

SOURCES += $$PWD/main.cpp

# Database migrations
include($$PWD/database/migrations.pri)
# Database seeders
include($$PWD/database/seeders.pri)

# Auto-configure TinyORM library for the migrations purposes 🔥
include($$TINY_MAIN_DIR/TinyORM/qmake/tom.pri)
+
warning

The exact folders structure is crucial in this example because the paths to the TinyORM source and build folders are relative.

+
warning

Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

+

Auto-configure using .qmake.conf and .env

+

If you want to have properly configured 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 TinyORM qmake features (.prf files) which handle this correctly; this path is provided by the QMAKEFEATURES variable and can only be set in the .qmake.conf file.

+
tip

Read the Consume TinyOrm library (qmake) section, as everything that is described in that section applies here as well.

+

Create the .qmake.conf file in the tom application root folder with the following content.

+
.qmake.conf
# Path to the PARENT folder of the TinyORM source folder
TINY_MAIN_DIR = $$clean_path($$PWD/../../TinyORM/)
# To find .env and .env.$$QMAKE_PLATFORM files
TINY_DOTENV_ROOT = $$PWD
# Path to the current build tree (used to guess the TinyORM build tree)
#TINY_BUILD_TREE = $$shadowed($$PWD)

# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants
QMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)
+

Then, create a .env.(win32|unix|mingw) file in the tom application root folder with the following content.

+
# Names and values of these qmake variables are crucial, they are used in the tom.pro
# Please pay special attention to letter casing in paths, especially TinyOrm vs TinyORM!

# Path to the TinyORM build folder
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug/)

# Path to the vcpkg - range-v3 and tabulate
# Will use the TINY_VCPKG_ROOT or VCPKG_ROOT environment variable if is empty
TINY_VCPKG_ROOT = $$clean_path($$PWD/../../../vcpkg/)
TINY_VCPKG_TRIPLET = x64-windows

# Enable ccache wrapper
#CONFIG *= tiny_ccache_win32
+

Don't forget to update the TINYORM_BUILD_TREE and TINY_VCPKG_ROOT folder paths to your needs if you are not using the recommended Folders structure.

+

You can use the Partial guessing of the TINYORM_BUILD_TREE if you don't like to specify it manually. Just comment out the TINYORM_BUILD_TREE and uncomment the TINY_BUILD_TREE = $$shadowed($$PWD) in the .qmake.conf file.

+
tip

You can entirely avoid the .env files, just move the TINYORM_BUILD_TREE to the .qmake.conf or remove it by help of Partial guessing of the TINYORM_BUILD_TREE and set the VCPKG_ROOT environment variable at system level as is described in Set up vcpkg environment.

+
info

Configuring by the .qmake.conf and .env files has one big advantage, which is that you don't have to modify the project files.

+

Migrations source files

+

Create database/migrations.pri file and paste the following code.

+
database/migrations.pri
INCLUDEPATH *= $$PWD

HEADERS += \
$$PWD/migrations/2014_10_12_000000_create_posts_table.hpp \
+

Seeders source files

+

Create database/seeders.pri file and paste the following code.

+
database/seeders.pri
INCLUDEPATH *= $$PWD

HEADERS += \
$$PWD/seeders/databaseseeder.hpp \
+

Build migrations

+
tip

I recommend creating a new Session in the QtCreator IDE as is described here.

+

Now you can open the tom.pro project in the QtCreator IDE.

+

This will open the Configure Project tab, select some kit and update build folder paths to meet our folders structure or like you want.

+tom - QtCreator - Configure Project +
tip

You can force the QtCreator to generate a build folders structure as is described here.

+

You are ready to configure build options, hit Ctrl+5 to open Project Settings tab and select Build in the left sidebar to open the Build Settings, it should look similar to the following picture.

+tom - QtCreator - Build Settings +

Disable QML debugging and profiling and Qt Quick Compiler, they are not used.

+

In the left sidebar open Dependencies and check TinyORM project and Synchronize configuration, this setting ensures that the current project will be rebuilt correctly when the TinyORM library source code changes.

+

Everything is ready to build, you can press Ctrl+b to build the project.

+

Execute migrations

+

The 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 LD_LIBRARY_PATH on Linux.

+

The only thing you might want to change is to run the tom application in the new terminal window. To do so, hit Ctrl+5 to open the Project Settings tab and select Run in the left sidebar to open the Run Settings, then in the Run section select the Run in terminal checkbox.

+

You can also set the Command line arguments in this Run section, eg. the migrate:status.

+

To execute the tom application press Ctrl + r.

+

The output will look very similar to this if you add more migrations.

+Tom migrations - migrate:status command output +

Happy migrating 🎉👌

+

Finish

+

As the last thing, you can check that all the file properties were correctly set by the rc compiler.

+

Find the tom.exe file and press Alt + Enter to open the file properties. To check the executable manifest you can use eg. the Resource Hacker.

+tom.exe file properties detail
\ No newline at end of file diff --git a/building/tinyorm.html b/building/tinyorm.html index ee754def8..acb66d059 100644 --- a/building/tinyorm.html +++ b/building/tinyorm.html @@ -1,9 +1,9 @@ - + - -Building: TinyORM - TinyORM + +Building: TinyORM - TinyORM @@ -13,17 +13,259 @@ - - - + + + -
-

Building: TinyORM

Introduction

The build systems supported out of the box are CMake and qmake.

info

All examples below assume that pwsh runs on Windows and bash runs on Linux.

Common Prerequisites

Install the required dependencies before starting.

caution

The QSqlDatabase depends on QCoreApplication from Qt v6.5.3 so you must create the QCoreApplication instance before you will call anything from the TinyORM library. 🫤 The change was made here.

Windows Prerequisites

Build environment scripts

The Visual Studio does not provide vcvars scripts for pwsh, you can use vcvars64.ps1 provided by TinyORM in the tools/ folder. Place them on the $env:Path user/system path and they will be available system-wide.

The same is true for the Qt Framework, it doesn't provide qtenv scripts for pwsh too. You can create your own script, place it on the $env:Path user/system path and it will be available system-wide.

Here is one simple example for pwsh.

Write-Host 'Setting up environment for Qt 6.7.0 usage...' -ForegroundColor Magenta
$env:Path = 'C:\Qt\6.7.0\msvc2019_64\bin;' + $env:Path
. E:\dotfiles\bin\vcvars64.ps1

And here for Linux.

echo 'Setting up environment for Qt 6.7.0 usage...'

export PATH=/opt/Qt/6.7.0/gcc_64/bin${PATH:+:}$PATH
export LD_LIBRARY_PATH=/opt/Qt/6.7.0/gcc_64/lib${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH

Open Local Security Policy, go to Local Policies - User Rights Assignment, open Create symbolic links and add your user account or user group, restart when it doesn't apply immediately.

Folders structure

All tinyorm.org examples are based on the following folders structure. The tom folder will contain a migrations console application.

tip

You can set the root and application folder paths in the form below and they will be used across the whole www.tinyorm.org website. 🥳 The pwsh shell is supposed to use on Windows and the bash shell on Linux, but it is not a requirement.

Current pwsh path 



├──
│ ├── HelloWorld/
│ | ├── HelloWorld/
│ | ├── HelloWorld-builds-cmake/
│ | | └── build-debug/
│ | └── HelloWorld-builds-qmake/
│ | └── build-debug/
│ ├── TinyORM/
│ | ├── TinyORM/
│ | ├── TinyORM-builds-cmake/
│ | │ ├── build-gcc-debug/
│ | │ ├── build-gcc-release/
│ | │ └── build-clang-debug/
│ | └── TinyORM-builds-qmake/
│ | ├── build-debug/
│ | ├── build-TinyORM-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/
│ | └── build-TinyORM-Desktop_Qt_5_15_2_MSYS2_UCRT64_64bit-Release/
│ └── tom/
│ ├── tom/
│ │ └── database/
│ │ ├── migrations/
│ │ ├── seeders/
│ │ ├── migrations.pri
│ │ └── seeders.pri
│ ├── tom-builds-cmake/
│ │ └── build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/
│ └── tom-builds-qmake/
│ ├── build-TinyORM-Desktop_Qt_5_15_3_MSYS2_UCRT64_64bit-Release/
│ └── build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/
├── tmp/
└── vcpkg/
danger

Avoid paths with spaces with the qmake build system, it will not compile.

tip

You can force the QtCreator to generate a build folders structure as is described above.

To generate the required folders structure set the Settings - Build & Run - Default Build Properties - Default build directory to:
-../%{Project:Name}-builds-%{BuildSystem:Name}/%{JS: Util.asciify("build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}")}

Getting started

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 PATH and LD_LIBRARY_PATH for Qt Framework, or use our qtenvX scripts described above.

mkdir 
cd
$env:Path = 'C:\Qt\6.7.0\msvc2019_64\bin;' + $env:Path
vcvars64.ps1
tip

You can also use the tools/Add-FolderOnPath.ps1 pwsh script to fastly prepend a path or pwd on the system PATH.

vcpkg

Installing the vcpkg is highly recommended, it simplifies installation of the range-v3 and tabulate dependencies.

git clone git@github.com:microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat

Add vcpkg on the system path, add the following to the .bashrc or .zshrc on Linux.

export PATH=/vcpkg${PATH:+:}$PATH

On Windows, open the Environment variables dialog and add vcpkg on the user PATH.

Or you can export it for the current session only.

$env:Path = "\vcpkg;" + $env:Path

Set up vcpkg environment

To export vcpkg environment variables globally, add it to the .bashrc or .zshrc on Linux, and you can use the Environment variables dialog on Windows.

Linux
export VCPKG_DEFAULT_TRIPLET=x64-linux
#export VCPKG_DEFAULT_HOST_TRIPLET=x64-linux
export VCPKG_MAX_CONCURRENCY=11
export VCPKG_OVERLAY_PORTS="$HOME/.local/share/vcpkg/ports"
export VCPKG_OVERLAY_TRIPLETS="$HOME/.local/share/vcpkg/triplets"
export VCPKG_ROOT="$HOME/Code/c/vcpkg"
info

It is recommended to define these variables globally because the CMake and qmake build system are able to detect the vcpkg installation from them so you don't have to configure them manually to detect the vcpkg installation.

tip

On Windows, it's always better to create these types of variables as user variables instead of system variables in the Environment variables dialog.

C preprocessor macros

The following table summarizes all the C preprocessor macros defined in the TinyORM library. These C macros are configured by CMake or qmake build systems. They are not sorted alphabetically, but they are sorted by how significant they are.

In the CMake build system, all the C macros are auto-detected / auto-configured or controlled by CMake build options, so you don't have to care too much about them.

In the qmake build is important whether you are building TinyORM library or you are building your application and linking against TinyORM library. When you are building the TinyORM library, all the C macros are auto-detected / auto-configured or controlled by qmake build options, so you don't have to care too much about them.

But a special situation is when you are building your application / library and you are linking against TinyORM library. In this particular case, you must configure all these C macros manually! For this reason, the TinyOrm.pri has been created, so that's not a big deal either. Little more info here.

C Macro NameDescription
TINYORM_LINKING_SHAREDMust be defined when you are linking against TinyORM shared build (dll library), exported classes and functions will be tagged with __declspec(dllimport) on msvc and visibility("default") on GCC >= 4.
TINYORM_BUILDING_SHAREDDefined when TinyORM is built as a dll library (shared build).
TINYORM_DEBUGDefined in the debug build.
TINYORM_NO_DEBUGDefined in the release build.
TINYORM_DEBUG_SQLDefined in the debug build.
TINYORM_NO_DEBUG_SQLDefined in the release build.
TINYORM_MYSQL_PINGEnable Orm::MySqlConnection::pingDatabase() method.
Defined when mysql_ping (qmake) / MYSQL_PING (cmake) configuration build option is enabled.
TINYORM_DISABLE_ORMControls the compilation of all ORM-related source code, when this macro is defined, then only the query builder without ORM is compiled. Also excludes ORM-related unit tests.
Defined when disable_orm (qmake) / ORM (cmake) configuration build option is enabled (qmake) / disabled (cmake).
TINYORM_EXTERN_CONSTANTSDefined when extern constants are used. Extern constants are enabled by default for shared builds and disabled for static builds.
Described at qmake / CMake how it works.
TINYORM_INLINE_CONSTANTSDefined when global inline constants are used.
Defined when inline_constants (qmake) / INLINE_CONSTANTS (cmake) configuration build option is enabled.
TINYORM_TESTS_CODEEnable code needed by unit tests, eg. connection overriding in the Orm::Tiny::Model.
Defined when build_tests (qmake) / BUILD_TESTS (cmake) configuration build option is enabled.
TINYORM_DISABLE_THREAD_LOCALRemove all thread_local storage duration specifiers, it disables multi-threading support.
Defined when disable_thread_local (qmake) / DISABLE_THREAD_LOCAL (cmake) configuration build option is enabled.
TINYTOM_MIGRATIONS_DIRDefault migrations path for the make:migration command, can be an absolute or relative path (to the pwd).
Default value: database/migrations (relative to the pwd)
Defined by TOM_MIGRATIONS_DIR (cmake) configuration build option.
(qmake note) You can use DEFINES += TINYTOM_MIGRATIONS_DIR="\"database/migrations\"" on the command-line or set it in the main conf.pri file.
TINYTOM_MODELS_DIRDefault models path for the make:model command, can be an absolute or relative path (to the pwd).
Default value: database/models (relative to the pwd)
Defined by TOM_MODELS_DIR (cmake) configuration build option.
(qmake note) You can use DEFINES += TINYTOM_MODELS_DIR="\"database/models\"" on the command-line or set it in the main conf.pri file.
TINYTOM_SEEDERS_DIRDefault seeders path for the make:seeder command, can be an absolute or relative path (to the pwd).
Default value: database/seeders (relative to the pwd)
Defined by TOM_SEEDERS_DIR (cmake) configuration build option.
(qmake note) You can use DEFINES += TINYTOM_SEEDERS_DIR="\"database/seeders\"" on the command-line or set it in the main conf.pri file.
TINYORM_USING_PCHDefined if building with precompiled headers.
Controlled by qmake / CMake.

Building with CMake

tip

If something is not clear, you can still look at GitHub Action workflows how a building is done.

First, create a basic folder structure and then clone the TinyORM project.

cd 
mkdir /TinyORM/TinyORM-builds-cmake/build-debug

cd /TinyORM
git clone git@github.com:silverqx/TinyORM.git

Configure & Build (cmake)

Now you are ready to configure the TinyORM library.

cd TinyORM-builds-cmake/build-debug
cmake.exe `
-S "/TinyORM/TinyORM" `
-B "/TinyORM/TinyORM-builds-cmake/build-debug" `
-G 'Ninja' `
-D CMAKE_BUILD_TYPE:STRING='Debug' `
-D CMAKE_TOOLCHAIN_FILE:FILEPATH="/vcpkg/scripts/buildsystems/vcpkg.cmake" `
-D CMAKE_INSTALL_PREFIX:PATH="/tmp/TinyORM" `
-D BUILD_TESTS:BOOL=OFF `
-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=ON `
-D MYSQL_PING:BOOL=OFF `
-D TOM:BOOL=ON `
-D TOM_EXAMPLE:BOOL=OFF `
-D VERBOSE_CONFIGURE:BOOL=ON
CMake STRICT_MODE option

The STRICT_MODE CMake configuration option was added in TinyORM v0.37.3. This option was added to avoid the propagation of aggressive strict warning compiler/linker options and Qt definitions from the TinyORM library to user code through the TinyOrm::CommonConfig interface library.

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 ISOCPP C++ Core Guidelines standards.

If you want to enable these strict warning options in your code, you can enable the STRICT_MODE CMake configuration option and they will be propagated to your code. You can also enabled it globally using the 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 STRICT_MODE CMake configuration option.

You can achieve the same result by manually linking against the TinyOrm::CommonConfig interface library when the STRICT_MODE is set to OFF.

target_link_libraries(<target> PRIVATE TinyOrm::CommonConfig)
info

The recommended way is to set the TINYORM_STRICT_MODE environment variable to 1 or ON.

Build TinyORM

And build. You don't have to install it, you can use the build tree directly if you want.

cmake --build . --target all
cmake --install .

Or build and install in one step.

cmake --build . --target install
info

CMake multi-config generators like Ninja Multi-Config or Visual Studio 16 2019 are also supported.

CMake build options

Option NameDefaultDescription
BUILD_DRIVERSOFFBuild TinyDrivers SQL database drivers (core/common code; replaces QtSql module).
BUILD_MYSQL_DRIVEROFFBuild TinyDrivers MySQL database driver.
Available when: BUILD_DRIVERS
BUILD_SHARED_LIBSONBuild as a shared/static library.
BUILD_TESTSOFFBuild TinyORM unit tests.
BUILD_TREE_DEPLOYONCopy TinyDrivers and TinyMySql libraries to the root of the build tree.
DRIVERS_TYPESharedHow to build and link against TinyDrivers SQL database drivers.
The Static value will be select by default when the BUILD_SHARED_LIBS is OFF.
Supported values: Shared, Loadable, and Static
Available when: BUILD_DRIVERS AND BUILD_SHARED_LIBS
INLINE_CONSTANTSOFFUse inline constants instead of extern constants in the shared build.
OFF is highly recommended for the shared build;
is always ON for the static build.
Available when: BUILD_SHARED_LIBS
MSVC_RUNTIME_DYNAMICONUse MSVC dynamic runtime library (-MD) instead of static (-MT), also considers a Debug configuration (-MTd, -MDd).
Available when: MSVC AND NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY
MYSQL_PINGOFFEnable Orm::MySqlConnection::pingDatabase() method.
ORMONControls the compilation of all ORM-related source code, when this option is disabled, then only the query builder without ORM is compiled. Also excludes ORM-related unit tests.
STRICT_MODEOFFControls propagation of strict compiler/linker options and Qt definitions using the TinyOrm::CommonConfig interface library to the user code.
(highly recommended; can also be set with the TINYORM_STRICT_MODE environment variable; described here).
TOMONControls the compilation of all Tom-related source code, when this option is disabled, then it also excludes Tom-related unit tests.
TOM_EXAMPLEOFFBuild the tom console application example.
TOM_MIGRATIONS_DIR-Default migrations path for the make:migration command, can be an absolute or relative path (to the pwd).
Default value: database/migrations (relative to the pwd)
TOM_MODELS_DIR-Default models path for the make:model command, can be an absolute or relative path (to the pwd).
Default value: database/models (relative to the pwd)
TOM_SEEDERS_DIR-Default seeders path for the make:seeder command, can be an absolute or relative path (to the pwd).
Default value: database/seeders (relative to the pwd)
VERBOSE_CONFIGUREOFFShow information about PACKAGES_FOUND / PACKAGES_NOT_FOUND in the CMake configure output.

Advanced TinyORM options.

Option NameDefaultDescription
DISABLE_THREAD_LOCALOFFRemove all thread_local storage duration specifiers, it disables multi-threading support.
MATCH_EQUAL_EXPORTED_BUILDTREEOFFExported package configuration from the build tree is considered to match only when the build type of application/library that is linking against the TinyORM library is equal.
Available when:
CMAKE_EXPORT_PACKAGE_REGISTRY AND NOT TINY_IS_MULTI_CONFIG

Important CMake options.

Option NameDefaultDescription
CMAKE_DISABLE_PRECOMPILE_HEADERSOFFDisable precompiled headers.
CMAKE_CXX_COMPILERautoThe full path to the C++ compiler.
CMAKE_CXX_COMPILER_LAUNCHER-Default compiler launcher to use for the C++ compiler.
Can be used to enable ccache, eg. ccache.exe on MinGW or /usr/bin/ccache on Linux.
CMAKE_EXPORT_PACKAGE_REGISTRYOFFEnable the export(TinyOrm) command.
TinyORM doesn't set this variable by default. Its initial value is taken from the TINYORM_EXPORT_PACKAGE_REGISTRY environment variable if not already defined.
CMAKE_VERBOSE_MAKEFILEOFFEnable verbose output from Makefile builds.

Consume TinyOrm library (cmake)

In your application or library CMakeLists.txt file add following find_package() call.

CMakeLists.txt
find_package(TinyOrm 0.37.3 CONFIG REQUIRED)

If the TinyORM build tree is not exported to the CMake's User Package Registry then also add the TinyORM build tree or CMAKE_INSTALL_PREFIX folder to the CMAKE_PREFIX_PATH, so CMake can find TinyORM's package configuration file during find_package(TinyOrm) call.

# build tree
list(APPEND CMAKE_PREFIX_PATH "/TinyORM/TinyORM-builds-cmake/build-debug")

# installation folder - CMAKE_INSTALL_PREFIX
list(APPEND CMAKE_PREFIX_PATH "/tmp/TinyORM")

Or as an alternative, you can set CMAKE_PREFIX_PATH environment variable.

As the last thing, do not forget to add TinyOrm0d.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-cmake\build-debug;" + $env:Path

Now you can try the HelloWorld CMake example.

info

You can also try the FetchContent method to fastly link against the TinyORM library.

Building with qmake

First, create a basic folder structure and then clone the TinyORM project.

cd 
mkdir /TinyORM/TinyORM-builds-qmake

cd /TinyORM
git clone git@github.com:silverqx/TinyORM.git

Install dependencies

With the qmake build system, you have to install TinyORM dependencies manually. We will use the vcpkg package manager.

cd ../../vcpkg

vcpkg search range-v3
vcpkg search tabulate
vcpkg install range-v3 tabulate
vcpkg list

On Linux, you can install the range-v3 library and some other dependencies with the package manager.

Configure & Build (qmake)

Open QtCreator IDE

tip

I recommend creating a new Session in the 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 QtCreator IDE. You can name it tinyorm.org or TinyORM examples, it is up to you.

tip

If you are using sessions, you can use a single clangd instance for all projects in this session in the QtCreator IDE. One significant advantage of this method is that the .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 Settings - C++ - Clangd - Sessions with a single clangd instance.

Configure TinyORM

Now you are ready to configure the TinyORM library. There are two ways how to configure the TinyORM library and it's the new Auto-configure feature added in TinyORM v0.34.0 using the .env files and the old way using the conf.pri files.

Auto-configuration and tiny_dotenv

This is the new recommended method to auto-configure TinyORM's qmake build system and also the dependencies, it was added in TinyORM v0.34.0. You need to copy the prepared .env.(win32|unix|mingw).example file to the .env.(win32|unix|mingw). One .env example file is prepared for each supported platform.

All prepared .env.(win32|unix|mingw).example files are simple and clear. You can also create a common .env file that is included before the platform-specific .env.(win32|unix|mingw) files.

cd /TinyORM/TinyORM

cp .env.win32.example .env.win32

And that is all, if you have correctly set all qmake variables in this .env.(win32|unix|mingw) file or you have correctly set environment variables, then the qmake build system should be able to auto-detect all dependencies . 🔥

info

The Auto-configuration and Environment files internals are described at the end to make this section more clear.

tip

The Auto-configuration feature can be turned off using the disable_autoconf qmake configuration option (eg. CONFIG*=disable_autoconf).

tip

The tiny_dotenv feature can be turned off using the disable_dotenv qmake configuration option (eg. CONFIG*=disable_dotenv).

Manual configuration (conf.pri)

This is the old method used before TinyORM v0.34.0. You need to copy the conf.pri.example files to conf.pri (there are four, one for every project or sub-project) and manually update the INCLUDEPATH and LIBS to configure TinyORM's qmake build dependencies. This way you can override any qmake build options or variables.

To disable the Auto-configuration feature you must define the disable_autoconf qmake configuration option (eg. CONFIG*=disable_autoconf) because from TinyORM v0.34.0 is the Auto-configuration feature enabled by default.

You can also remove all .env files or turn off the tiny_dotenv feature using CONFIG*=disable_dotenv. You can use them all at once if you want, .env and also conf.pri files.

conf.pri files are nicely commented on, so you can see what needs to be modified.

cd /TinyORM/TinyORM

cp conf.pri.example conf.pri
cp tests/conf.pri.example tests/conf.pri
cp tests/testdata_tom/conf.pri.example tests/testdata_tom/conf.pri
cp examples/tom/conf.pri.example examples/tom/conf.pri
info

The Manual configuration internals are described at the end to make this section more clear.

note

The Manual configuration is still relevant if you have any non-standard installation of the vcpkg or MySQL and the Auto-configuration feature fails.

Opening TinyORM.pro (main project file)

Now you can open the TinyORM.pro project in the QtCreator IDE.

This will open the Configure Project tab, select some kit and update build folder paths to meet our folders structure or like you want.

TinyORM - QtCreator - Configure Project
tip

You can force the QtCreator to generate a build folders structure as is described above.

You are ready to configure build options, hit Ctrl+5 to open Project Settings tab and select Build in the left sidebar to open the Build Settings, it should look similar to the following picture.

Disable QML debugging and profiling and Qt Quick Compiler, they are not used.

TinyORM - QtCreator - Build Settings

If you want to change some TinyORM build options, you can pass them to the Build Steps - qmake TinyORM.pro - Additional arguments input field. It can look like this.

TinyORM - QtCreator - Build Settings - Additional arguments

Build TinyORM

Everything is ready for build, you can press Ctrl+b to build the project.

qmake build options

CONFIG Option NameDefaultDescription
build_loadable_driversOFFBuild TinyDrivers as a shared library and SQL database drivers (eg. TinyMySql) as shared libraries (Loadable modules) that are loaded at runtime using LoadLibrary() on Windows or dlopen() on Linux.
build_mysql_driverOFFBuild TinyDrivers MySQL database driver.
It's enabled by default when build_shared_drivers, build_loadable_drivers, or build_static_drivers is enabled.
Available when: build_shared_drivers OR build_loadable_drivers OR build_static_drivers
build_shared_driversOFFBuild TinyDrivers as a Shared library.
build_static_driversOFFBuild TinyDrivers as a Static library archive.
The build_static_drivers qmake configuration option will be select by default when the CONFIG*=static is enabled.
build_testsOFFBuild TinyORM unit tests.
disable_autoconfOFFDisable the Auto-configuration feature (auto-configuration is enabled by default from TinyORM v0.34.0).
disable_dotenvOFFDisable the tiny_dotenv feature (environment files are enabled by default from TinyORM v0.34.0).
disable_thread_localOFFRemove all thread_local storage duration specifiers, it disables multi-threading support.
disable_ormOFFControls the compilation of all ORM-related source code, when this option is enabled, then only the query builder without ORM is compiled. Also excludes ORM-related unit tests.
disable_tomOFFControls the compilation of all Tom-related source code, when this option is disabled, then it also excludes Tom-related unit tests.
extern_constantsONUse extern constants instead of inline constants in the shared build.
ON is highly recommended for the shared build (by default);
is always OFF for the static build.
Available when: CONFIG(shared|dll):!inline_constants
inline_constantsOFFUse inline constants instead of extern constants in the shared build.
OFF is highly recommended for the shared build;
is always ON for the static build.
mysql_pingOFFEnable Orm::MySqlConnection::pingDatabase() method.
tiny_ccache_win32ONEnable compiler cache. Homepage
It works only on Windows systems. It works well with the MSYS2 g++, clang++, msvc, and clang-cl with msvc. It disables precompile_header as they are not supported on Windows and changes the -Zi compiler option to the -Z7 for debug builds as the -Zi compiler option is not supported (link to the issue).
tom_exampleOFFBuild the tom console application example.

Advanced TinyORM options.

Option NameDefaultDescription
ubsanOFFAllows to enable UBSan sanitizer (Clang only).

Important qmake options.

CONFIG Option NameDefaultDescription
ccacheOFFEnable compiler cache. Homepage
It works only on the Unix systems. It works well with the g++ and clang++ and also supports precompiled headers.
precompile_header-Enable precompiled headers, you can disable them with:
CONFIG-=precompile_header.
The precompile_header is enabled by default on msvc, g++, clang++, clang-cl on Windows and disabled by default on linux.
static
staticlib
OFFBuild as a static library (lib only).
If you want to build all libraries in the TinyORM project as static library archives and link against static libraries use the CONFIG += static. Don't use the CONFIG += staticlib.
See NOTES.txt for more information (search static vs staticlib).
static_runtimeOFFLink against the shared (dynamic) or static run-time library.
The -MD becomes -MT and -MDd becomes -MTd. It works only on MSVC and MinGW or MSYS2.
Please don't use this option.
Available when: msvc or mingw

Consume TinyOrm library (qmake)

The TinyOrm.pri file is available to simplify the integration of the TinyORM library into your application. It sets up and configures the CONFIG and DEFINES qmake variables, adds the TinyORM, tom, and vcpkg header files on the system INCLUDEPATH (cross-platform using the -isystem or -imsvc), links against the TinyORM shared or static library using the LIBS.

You can use it to configure the TinyORM library when you are linking against it. It does a very similar thing like the CMake's Find Modules feature.

Requirements

It has a few requirements, you need to:

  • specify path to the TinyORM qmake features (.prf files) using the QMAKEFEATURES variable that can only be set in the .qmake.conf file
  • specify qmake or environment variables to find the vcpkg installation (TINY_VCPKG_ROOT and TINY_VCPKG_TRIPLET)
  • specify path to the TinyORM build folder (TINYORM_BUILD_TREE)
  • build your application with the same CONFIG qmake variables that were used when building the TinyORM library

Let's explain one by one.

QMAKEFEATURES

Create the .qmake.conf file in your application root folder with the following content.

.qmake.conf
# Path to the PARENT folder of the TinyORM source folder
TINY_MAIN_DIR = $$clean_path(<your_path>)
# To find .env and .env.$$QMAKE_PLATFORM files in YOUR project
TINY_DOTENV_ROOT = $$PWD

# Path to the TinyORM build folder (specified manually)
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/)
# vcpkg - range-v3 and tabulate
TINY_VCPKG_ROOT = $$quote(<your_path>/vcpkg/)
#TINY_VCPKG_TRIPLET = x64-windows

# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants
QMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)

You can move all qmake variables that are part of the qmake configuration process to the .env file if you want (recommended), this is possible because the TinyOrm.pri enables the Environment files feature by default.

You can look at the Auto-configure using .qmake.conf and .env example for Hello world project of what must stay in the qmake.conf file and what can be moved to the .env files.

tip

You can use the Partial guessing of the TINYORM_BUILD_TREE if you don't like to specify it manually.

Variables affecting TinyOrm.pri

You must define the following variables before the TinyOrm.pri is included:

Variable NameDescription
TINYORM_BUILD_TREEPath to the TinyORM build folder.
TINY_VCPKG_ROOTPath to the vcpkg installation folder.
If not defined, then it tries to use the VCPKG_ROOT environment variable.
TINY_VCPKG_TRIPLETThe vcpkg triplet to use (vcpkg/installed/$$TINY_VCPKG_TRIPLET/).
If not defined, then it tries to guess the vcpkg triplet based on the current compiler and OS (based on the QMAKESPEC), and as the last thing, it tries to use the VCPKG_DEFAULT_TRIPLET environment variable.

These variables will be set after the configuration is done:

Variable NameDescription
TINY_BUILD_SUBFOLDERFolder by release type if CONFIG+=debug_and_release is defined (/debug, /release, or an empty string).
TINY_CCACHE_BUILDTo correctly link ccache build against a ccache build (_ccache or an empty string).
TINY_MSVC_VERSIONThe msvc compiler string (MSVC2022 or MSVC2019).
TINY_QT_VERSION_UNDERSCOREDUnderscored Qt version (eg. 6_7_0).
TINY_RELEASE_TYPE_CAMELBuild type string (Debug, Profile, or Release).
TINY_VCPKG_INCLUDEPath to the vcpkg include folder (vcpkg/installed/<triplet>/include/).

Then you simply include the TinyOrm.pri in your project file.

AnyProject.pro
include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)

And that is all, now you should be able to link against the TinyORM library. 👌

Manual configuration examples

Frankly, there is no reason to use the Manual configuration (define the variables described below before the 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.

You will have to link against the TinyORM library manually if you don't set the TINYORM_BUILD_TREE qmake variable before the inclusion of the TinyOrm.pri file. The INCLUDEPATH is auto-detected every time.

# Link against TinyORM library
# ---
TINY_MAIN_DIR = $$clean_path(<your_path>)

# Configure TinyORM library
include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)

# TinyORM library path
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake)
LIBS += $$quote(-L$$TINYORM_BUILD_TREE/build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)
LIBS += -lTinyOrm

The same is true for the vcpkg include path. If you don't set the TINY_VCPKG_ROOT or have not defined the VCPKG_ROOT environment variable, then you need to set up the INCLUDEPATH for the vcpkg that provides the range-v3 and tabulate header files.

# vcpkg - range-v3 and tabulate
# ---
INCLUDEPATH += $$quote(<your_path>/vcpkg/installed/x64-windows/include/)

You can also use TinyORM's qmake function tiny_add_system_includepath() which handles INCLUDEPATH in a cross-platform way.

# 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.

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.

The Auto-configuration feature is designed to find the vcpkg and MySQL installations, and tiny_dotenv to include the .env and .env.(win32|unix|mingw) files in the project's root folder. These new features can be configured using qmake and environment variables, and they also contain some guessing logic if these variables are not defined.

The Auto-configuration feature can be turned off using the disable_autoconf qmake configuration option (eg. CONFIG*=disable_autoconf).

These are qmake and environment variables that affect the Auto-configuration feature:

Variable NameDescription
TINY_VCPKG_ROOTPath to the vcpkg installation folder.
If not defined, then it tries to use the VCPKG_ROOT environment variable.
TINY_VCPKG_TRIPLETThe vcpkg triplet to use (vcpkg/installed/$$TINY_VCPKG_TRIPLET/).
If not defined, then it tries to guess the vcpkg triplet based on the current compiler and OS (based on the QMAKESPEC), and as the last thing, it tries to use the VCPKG_DEFAULT_TRIPLET environment variable.
TINY_MYSQL_ROOTPath to the MySQL installation folder.
If not defined, then it tries to guess the MySQL installation folder (win32 only): $$(ProgramFiles)/MySQL/MySQL Server (8.3|8.2|8.1|8.0|5.7)/

You can set these variables in the .env (recommended) or conf.pri files, in the .qmake.conf file (or wherever you want), or as environment variables.

These variables will be set after auto-configuration is done:

Variable NameDescription
TINY_VCPKG_INCLUDEPath to the vcpkg include folder (vcpkg/installed/<triplet>/include/).
TINY_MYSQL_INCLUDEPath to the MySQL include folder (MySQL Server 8.3/include/).
TINY_MYSQL_LIBPath to the MySQL lib folder (MySQL Server 8.3/lib/).

The TINY_MYSQL_INCLUDE and TINY_MYSQL_LIB are only set on win32 platform except mingw.

Environment files

The tiny_dotenv feature allows us to define the .env and .env.$$TINY_DOTENV_PLATFORM files in the project's root folder. These files are loaded as early as possible so you can affect the qmake configuration process. On the other hand, the conf.pri files are loaded as late as possible, and they can be used to override the qmake configuration.

The .env file is included first and is included on all platforms.

There is only one requirement for this feature to work correctly, and that is to set the TINY_DOTENV_ROOT qmake variable to the project's root folder. This variable is already set in the .qmake.conf file for the TinyORM project.

Then the following names are taken into account: .env, .env.win32, .env.unix, .env.mingw

.qmake.conf
# To find .env and .env.$$QMAKE_PLATFORM files
TINY_DOTENV_ROOT = $$PWD

The tiny_dotenv feature can be turned off using the disable_dotenv qmake configuration option (eg. CONFIG*=disable_dotenv).

caution

Environment files don't work in the CMake builds.

Partial guessing of the TINYORM_BUILD_TREE

You don't have to manually define the TINYORM_BUILD_TREE in .env or .qmake.conf files. The TINYORM_BUILD_TREE absolute path can be put together for you (this is happening inside the variables.pri file) and TinyORM build folder name can be guessed for you too.

You must define the following variables before the TinyOrm.pri will be included to make this real (set them in the .qmake.conf):

Variable NameDescription
TINY_MAIN_DIRPath to the PARENT folder of the TinyORM source folder.
TINY_BUILD_TREEPath to the current build tree - TINY_BUILD_TREE = $$shadowed($$PWD).

The TINY_MAIN_DIR is required for another features anyway (so it should already be set) and all that's left is to set the TINY_BUILD_TREE.

.qmake.conf
# Path to the current build tree (used to guess the TinyORM build tree)
TINY_BUILD_TREE = $$shadowed($$PWD)

If you will follow this pattern or logic then you can switch QtCreator Kits and the TINYORM_BUILD_TREE will be auto-generated correctly and will always point to the correct TinyORM build tree.

It works this way, all is happening inside the variables.pri, it takes a build folder name for the current project eg. build-HelloWorld-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug, replaces the HelloWorld with the TinyORM and as we already know the TinyORM build folder location we can simply concatenate these paths like $$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug.

caution

This will only work if you follow the recommended Folders structure.

Manual configuration internals

There is not much to say about the Manual configuration feature. It uses conf.pri files (there are four, one for every project or sub-project), and every project has prepared its own conf.pri.example file for faster initial configuration.

These conf.pri.example files are nicely commented on, so you can see what needs to be modified. The conf.pri files are loaded as late as possible, and they can be used to override the qmake configuration.

If the Auto-configuration feature is disabled and there are no conf.pri files, then the TinyORM qmake configuration or build will fail at 100%.

These conf.pri files are intended for configuring qmake's INCLUDEPATH and LIBS, CONFIG or eg. QMAKE_LFLAGS, or any other qmake options or variables.

Ccache support

The TinyORM supports the ccache out of the box for all supported compilers. For qmake you can enable it using the CONFIG+=ccache on Linux or CONFIG+=tiny_ccache_win32 on Windows. For CMake you can set the CMAKE_CXX_COMPILER_LAUNCHER=ccache.

On Linux it's clear, the ccache is fully supported and works also with the precompiled headers. But was necessary to add some workarounds to the qmake/CMake build systems to make out of the box support on Windows. When you enable the ccache on Windows then the build system disables precompiled headers and replaces the -Zi compiler option with the -Z7 (link to the issue).

tip

You can install the ccache using the scoop install ccache command on Windows.

- - +

Building: TinyORM

+ +

Introduction

+

The build systems supported out of the box are CMake and qmake.

+
info

All examples below assume that pwsh runs on Windows and bash runs on Linux.

+

Common Prerequisites

+

Install the required dependencies before starting.

+
warning

The QSqlDatabase depends on QCoreApplication from Qt v6.5.3 so you must create the QCoreApplication instance before you will call anything from the TinyORM library. 🫤 The change was made here.

+

Windows Prerequisites

+
Build environment scripts
+

The Visual Studio does not provide vcvars scripts for pwsh, you can use vcvars64.ps1 provided by TinyORM in the tools/ folder. Place them on the $env:Path user/system path and they will be available system-wide.

+

The same is true for the Qt Framework, it doesn't provide qtenv scripts for pwsh too. You can create your own script, place it on the $env:Path user/system path and it will be available system-wide.

+

Here is one simple example for pwsh.

+
#!/usr/bin/env pwsh

Set-StrictMode -Version 3.0

Write-Host 'Setting up environment for Qt 6.7.0 usage...' -ForegroundColor Magenta
Write-Host

$Script:QtRoot = $env:TINY_QT_ROOT ?? 'C:\Qt'

$env:Path = "$Script:QtRoot\6.7.0\msvc2019_64\bin;" + $env:Path

. vcvars64.ps1
+

And here for Linux.

+
echo 'Setting up environment for Qt 6.7.0 usage...'

QtRoot="${TINY_QT_ROOT:-/opt/Qt}"

export PATH="$QtRoot/6.7.0/gcc_64/bin"${PATH:+:}$PATH
export LD_LIBRARY_PATH="$QtRoot/6.7.0/gcc_64/lib"${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH
+
info

These scripts consider the TINY_QT_ROOT environment variable that should point to the Qt installation folder, you can define this environment variable globally in your OS.

+ +

Open Local Security Policy, go to Local Policies - User Rights Assignment, open Create symbolic links and add your user account or user group, restart when it doesn't apply immediately.

+

Folders structure

+

All tinyorm.org examples are based on the following folders structure. The tom folder will contain a migrations console application.

+
tip

You can set the root and application folder paths in the form below and they will be used across the whole www.tinyorm.org website. 🥳 The pwsh shell is supposed to use on Windows and the bash shell on Linux, but it is not a requirement.

+

Current pwsh path 




├──
│ ├── HelloWorld/
│ | ├── HelloWorld/
│ | ├── HelloWorld-builds-cmake/
│ | | └── build-debug/
│ | └── HelloWorld-builds-qmake/
│ | └── build-debug/
│ ├── TinyORM/
│ | ├── TinyORM/
│ | ├── TinyORM-builds-cmake/
│ | │ ├── build-gcc-debug/
│ | │ ├── build-gcc-release/
│ | │ └── build-clang-debug/
│ | └── TinyORM-builds-qmake/
│ | ├── build-debug/
│ | ├── build-TinyORM-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/
│ | └── build-TinyORM-Desktop_Qt_5_15_2_MSYS2_UCRT64_64bit-Release/
│ └── tom/
│ ├── tom/
│ │ └── database/
│ │ ├── migrations/
│ │ ├── seeders/
│ │ ├── migrations.pri
│ │ └── seeders.pri
│ ├── tom-builds-cmake/
│ │ └── build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/
│ └── tom-builds-qmake/
│ ├── build-TinyORM-Desktop_Qt_5_15_3_MSYS2_UCRT64_64bit-Release/
│ └── build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/
├── tmp/
└── vcpkg/
+
danger

Avoid paths with spaces with the qmake build system, it will not compile.

+ +
tip

You can force the QtCreator to generate a build folders structure as is described above.

To generate the required folders structure set the Settings - Build & Run - Default Build Properties - Default build directory to:
+../%{Project:Name}-builds-%{BuildSystem:Name}/%{JS: Util.asciify("build-%{Project:Name}-%{Kit:FileSystemName}-%{BuildConfig:Name}")}

+

Getting started

+

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 PATH and LD_LIBRARY_PATH for Qt Framework, or use our qtenvX scripts described above.

+
mkdir 
cd
$env:Path = 'C:\Qt\6.7.0\msvc2019_64\bin;' + $env:Path
vcvars64.ps1
+
tip

You can also use the tools/Add-FolderOnPath.ps1 pwsh script to fastly prepend a path or pwd on the system PATH.

+

vcpkg

+

Installing the vcpkg is highly recommended, it simplifies installation of the range-v3 and tabulate dependencies.

+
git clone git@github.com:microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
+

Add vcpkg on the system path, add the following to the .bashrc or .zshrc on Linux.

+
export PATH=/vcpkg${PATH:+:}$PATH
+

On Windows, open the Environment variables dialog and add vcpkg on the user PATH.

+

Or you can export it for the current session only.

+
$env:Path = "\vcpkg;" + $env:Path
+

Set up vcpkg environment

+

To export vcpkg environment variables globally, add it to the .bashrc or .zshrc on Linux, and you can use the Environment variables dialog on Windows.

+
Linux
export VCPKG_DEFAULT_TRIPLET=x64-linux
#export VCPKG_DEFAULT_HOST_TRIPLET=x64-linux
export VCPKG_MAX_CONCURRENCY=11
export VCPKG_OVERLAY_PORTS="$HOME/.local/share/vcpkg/ports"
export VCPKG_OVERLAY_TRIPLETS="$HOME/.local/share/vcpkg/triplets"
export VCPKG_ROOT="$HOME/Code/c/vcpkg"
+
info

It is recommended to define these variables globally because the CMake and qmake build system are able to detect the vcpkg installation from them so you don't have to configure them manually to detect the vcpkg installation.

+
tip

On Windows, it's always better to create these types of variables as user variables instead of system variables in the Environment variables dialog.

+

C preprocessor macros

+

The following table summarizes all the C preprocessor macros defined in the TinyORM library. These C macros are configured by CMake or qmake build systems. They are not sorted alphabetically, but they are sorted by how significant they are.

+

In the CMake build system, all the C macros are auto-detected / auto-configured or controlled by CMake build options, so you don't have to care too much about them.

+

In the qmake build is important whether you are building TinyORM library or you are building your application and linking against TinyORM library. When you are building the TinyORM library, all the C macros are auto-detected / auto-configured or controlled by qmake build options, so you don't have to care too much about them.

+

But a special situation is when you are building your application / library and you are linking against TinyORM library. In this particular case, you must configure all these C macros manually! For this reason, the TinyOrm.pri has been created, so that's not a big deal either. Little more info here.

+
C Macro NameDescription
TINYORM_LINKING_SHAREDMust be defined when you are linking against TinyORM shared build (dll library), exported classes and functions will be tagged with __declspec(dllimport) on msvc and visibility("default") on GCC >= 4.
TINYORM_BUILDING_SHAREDDefined when TinyORM is built as a dll library (shared build).
TINYORM_DEBUGDefined in the debug build.
TINYORM_NO_DEBUGDefined in the release build.
TINYORM_DEBUG_SQLDefined in the debug build.
TINYORM_NO_DEBUG_SQLDefined in the release build.
TINYORM_MYSQL_PINGEnable Orm::MySqlConnection::pingDatabase() method.
Defined when mysql_ping (qmake) / MYSQL_PING (cmake) configuration build option is enabled.
TINYORM_DISABLE_ORMControls the compilation of all ORM-related source code, when this macro is defined, then only the query builder without ORM is compiled. Also excludes ORM-related unit tests.
Defined when disable_orm (qmake) / ORM (cmake) configuration build option is enabled (qmake) / disabled (cmake).
TINYORM_EXTERN_CONSTANTSDefined when extern constants are used. Extern constants are enabled by default for shared builds and disabled for static builds.
Described at qmake / CMake how it works.
TINYORM_INLINE_CONSTANTSDefined when global inline constants are used.
Defined when inline_constants (qmake) / INLINE_CONSTANTS (cmake) configuration build option is enabled.
TINYORM_TESTS_CODEEnable code needed by unit tests, eg. connection overriding in the Orm::Tiny::Model.
Defined when build_tests (qmake) / BUILD_TESTS (cmake) configuration build option is enabled.
TINYORM_DISABLE_THREAD_LOCALRemove all thread_local storage duration specifiers, it disables multi-threading support.
Defined when disable_thread_local (qmake) / DISABLE_THREAD_LOCAL (cmake) configuration build option is enabled.
TINYTOM_MIGRATIONS_DIRDefault migrations path for the make:migration command, can be an absolute or relative path (to the pwd).
Default value: database/migrations (relative to the pwd)
Defined by TOM_MIGRATIONS_DIR (cmake) configuration build option.
(qmake note) You can use DEFINES += TINYTOM_MIGRATIONS_DIR="\"database/migrations\"" on the command-line or set it in the main conf.pri file.
TINYTOM_MODELS_DIRDefault models path for the make:model command, can be an absolute or relative path (to the pwd).
Default value: database/models (relative to the pwd)
Defined by TOM_MODELS_DIR (cmake) configuration build option.
(qmake note) You can use DEFINES += TINYTOM_MODELS_DIR="\"database/models\"" on the command-line or set it in the main conf.pri file.
TINYTOM_SEEDERS_DIRDefault seeders path for the make:seeder command, can be an absolute or relative path (to the pwd).
Default value: database/seeders (relative to the pwd)
Defined by TOM_SEEDERS_DIR (cmake) configuration build option.
(qmake note) You can use DEFINES += TINYTOM_SEEDERS_DIR="\"database/seeders\"" on the command-line or set it in the main conf.pri file.
TINYORM_USING_PCHDefined if building with precompiled headers.
Controlled by qmake / CMake.
+

Building with CMake

+
tip

If something is not clear, you can still look at GitHub Action workflows how a building is done.

+

First, create a basic folder structure and then clone the TinyORM project.

+
cd 
mkdir /TinyORM/TinyORM-builds-cmake/build-debug

cd /TinyORM
git clone git@github.com:silverqx/TinyORM.git
+

Configure & Build (cmake)

+

Now you are ready to configure the TinyORM library.

+
cd TinyORM-builds-cmake/build-debug
+
cmake.exe `
-S "/TinyORM/TinyORM" `
-B "/TinyORM/TinyORM-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/TinyORM" `
-D BUILD_TESTS:BOOL=OFF `
-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=ON `
-D MYSQL_PING:BOOL=OFF `
-D TOM:BOOL=ON `
-D TOM_EXAMPLE:BOOL=OFF `
-D VERBOSE_CONFIGURE:BOOL=ON
+
CMake STRICT_MODE option
+

The STRICT_MODE CMake configuration option was added in TinyORM v0.37.3. This option was added to avoid the propagation of aggressive strict warning compiler/linker options and Qt definitions from the TinyORM library to user code through the TinyOrm::CommonConfig interface library.

+

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 ISOCPP C++ Core Guidelines standards.

+

If you want to enable these strict warning options in your code, you can enable the STRICT_MODE CMake configuration option and they will be propagated to your code. You can also enabled it globally using the 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 STRICT_MODE CMake configuration option.

+

You can achieve the same result by manually linking against the TinyOrm::CommonConfig interface library when the STRICT_MODE is set to OFF.

+
target_link_libraries(<target> PRIVATE TinyOrm::CommonConfig)
+
info

The recommended way is to set the TINYORM_STRICT_MODE environment variable to 1 or ON.

+

Build TinyORM

+

And build. You don't have to install it, you can use the build tree directly if you want.

+
cmake --build . --target all
cmake --install .
+

Or build and install in one step.

+
cmake --build . --target install
+
info

CMake multi-config generators like Ninja Multi-Config or Visual Studio 16 2019 are also supported.

+

CMake build options

+
Option NameDefaultDescription
BUILD_DRIVERSOFFBuild TinyDrivers SQL database drivers (core/common code; replaces QtSql module).
BUILD_MYSQL_DRIVEROFFBuild TinyDrivers MySQL database driver.
Available when: BUILD_DRIVERS
BUILD_SHARED_LIBSONBuild as a shared/static library.
BUILD_TESTSOFFBuild TinyORM unit tests.
BUILD_TREE_DEPLOYONCopy TinyDrivers and TinyMySql libraries to the root of the build tree.
DRIVERS_TYPESharedHow to build and link against TinyDrivers SQL database drivers.
The Static value will be select by default when the BUILD_SHARED_LIBS is OFF.
Supported values: Shared, Loadable, and Static
Available when: BUILD_DRIVERS AND BUILD_SHARED_LIBS
INLINE_CONSTANTSOFFUse inline constants instead of extern constants in the shared build.
OFF is highly recommended for the shared build;
is always ON for the static build.
Available when: BUILD_SHARED_LIBS
MSVC_RUNTIME_DYNAMICONUse MSVC dynamic runtime library (-MD) instead of static (-MT), also considers a Debug configuration (-MTd, -MDd).
Available when: MSVC AND NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY
MYSQL_PINGOFFEnable Orm::MySqlConnection::pingDatabase() method.
ORMONControls the compilation of all ORM-related source code, when this option is disabled, then only the query builder without ORM is compiled. Also excludes ORM-related unit tests.
STRICT_MODEOFFControls propagation of strict compiler/linker options and Qt definitions using the TinyOrm::CommonConfig interface library to the user code.
(highly recommended; can also be set with the TINYORM_STRICT_MODE environment variable; described here).
TOMONControls the compilation of all Tom-related source code, when this option is disabled, then it also excludes Tom-related unit tests.
TOM_EXAMPLEOFFBuild the tom console application example.
TOM_MIGRATIONS_DIR-Default migrations path for the make:migration command, can be an absolute or relative path (to the pwd).
Default value: database/migrations (relative to the pwd)
TOM_MODELS_DIR-Default models path for the make:model command, can be an absolute or relative path (to the pwd).
Default value: database/models (relative to the pwd)
TOM_SEEDERS_DIR-Default seeders path for the make:seeder command, can be an absolute or relative path (to the pwd).
Default value: database/seeders (relative to the pwd)
VERBOSE_CONFIGUREOFFShow information about PACKAGES_FOUND / PACKAGES_NOT_FOUND in the CMake configure output.
+

Advanced TinyORM options.

+
Option NameDefaultDescription
DISABLE_THREAD_LOCALOFFRemove all thread_local storage duration specifiers, it disables multi-threading support.
MATCH_EQUAL_EXPORTED_BUILDTREEOFFExported package configuration from the build tree is considered to match only when the build type of application/library that is linking against the TinyORM library is equal.
Available when:
CMAKE_EXPORT_PACKAGE_REGISTRY AND NOT TINY_IS_MULTI_CONFIG
+

Important CMake options.

+
Option NameDefaultDescription
CMAKE_DISABLE_PRECOMPILE_HEADERSOFFDisable precompiled headers.
CMAKE_CXX_COMPILERautoThe full path to the C++ compiler.
CMAKE_CXX_COMPILER_LAUNCHER-Default compiler launcher to use for the C++ compiler.
Can be used to enable ccache, eg. ccache.exe on MinGW or /usr/bin/ccache on Linux.
CMAKE_EXPORT_PACKAGE_REGISTRYOFFEnable the export(TinyOrm) command.
TinyORM doesn't set this variable by default. Its initial value is taken from the TINYORM_EXPORT_PACKAGE_REGISTRY environment variable if not already defined.
CMAKE_VERBOSE_MAKEFILEOFFEnable verbose output from Makefile builds.
+

Consume TinyOrm library (cmake)

+

In your application or library CMakeLists.txt file add following find_package() call.

+
CMakeLists.txt
find_package(TinyOrm 0.37.3 CONFIG REQUIRED)
+

If the TinyORM build tree is not exported to the CMake's User Package Registry then also add the TinyORM build tree or CMAKE_INSTALL_PREFIX folder to the CMAKE_PREFIX_PATH, so CMake can find TinyORM's package configuration file during find_package(TinyOrm) call.

+
# build tree
list(APPEND CMAKE_PREFIX_PATH "/TinyORM/TinyORM-builds-cmake/build-debug")

# installation folder - CMAKE_INSTALL_PREFIX
list(APPEND CMAKE_PREFIX_PATH "/tmp/TinyORM")
+

Or as an alternative, you can set CMAKE_PREFIX_PATH environment variable.

+ +

As the last thing, do not forget to add TinyOrm0d.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-cmake\build-debug;" + $env:Path
+

Now you can try the HelloWorld CMake example.

+
info

You can also try the FetchContent method to fastly link against the TinyORM library.

+

Building with qmake

+

First, create a basic folder structure and then clone the TinyORM project.

+
cd 
mkdir /TinyORM/TinyORM-builds-qmake

cd /TinyORM
git clone git@github.com:silverqx/TinyORM.git
+

Install dependencies

+

With the qmake build system, you have to install TinyORM dependencies manually. We will use the vcpkg package manager.

+
cd ../../vcpkg

vcpkg search range-v3
vcpkg search tabulate
vcpkg install range-v3 tabulate
vcpkg list
+

On Linux, you can install the range-v3 library and some other dependencies with the package manager.

+

Configure & Build (qmake)

+

Open QtCreator IDE

+
tip

I recommend creating a new Session in the 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 QtCreator IDE. You can name it tinyorm.org or TinyORM examples, it is up to you.

+
tip

If you are using sessions, you can use a single clangd instance for all projects in this session in the QtCreator IDE. One significant advantage of this method is that the .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 Settings - C++ - Clangd - Sessions with a single clangd instance.

+

Configure TinyORM

+

Now you are ready to configure the TinyORM library. There are two ways how to configure the TinyORM library and it's the new Auto-configure feature added in TinyORM v0.34.0 using the .env files and the old way using the conf.pri files.

+
Auto-configuration and tiny_dotenv
+

This is the new recommended method to auto-configure TinyORM's qmake build system and also the dependencies, it was added in TinyORM v0.34.0. You need to copy the prepared .env.(win32|unix|mingw).example file to the .env.(win32|unix|mingw). One .env example file is prepared for each supported platform.

+

All prepared .env.(win32|unix|mingw).example files are simple and clear. You can also create a common .env file that is included before the platform-specific .env.(win32|unix|mingw) files.

+
cd /TinyORM/TinyORM

cp .env.win32.example .env.win32
+

And that is all, if you have correctly set all qmake variables in this .env.(win32|unix|mingw) file or you have correctly set environment variables, then the qmake build system should be able to auto-detect all dependencies . 🔥

+
info

The Auto-configuration and Environment files internals are described at the end to make this section more clear.

+
tip

The Auto-configuration feature can be turned off using the disable_autoconf qmake configuration option (eg. CONFIG*=disable_autoconf).

+
tip

The tiny_dotenv feature can be turned off using the disable_dotenv qmake configuration option (eg. CONFIG*=disable_dotenv).

+
Manual configuration (conf.pri)
+

This is the old method used before TinyORM v0.34.0. You need to copy the conf.pri.example files to conf.pri (there are four, one for every project or sub-project) and manually update the INCLUDEPATH and LIBS to configure TinyORM's qmake build dependencies. This way you can override any qmake build options or variables.

+

To disable the Auto-configuration feature you must define the disable_autoconf qmake configuration option (eg. CONFIG*=disable_autoconf) because from TinyORM v0.34.0 is the Auto-configuration feature enabled by default.

+

You can also remove all .env files or turn off the tiny_dotenv feature using CONFIG*=disable_dotenv. You can use them all at once if you want, .env and also conf.pri files.

+

conf.pri files are nicely commented on, so you can see what needs to be modified.

+
cd /TinyORM/TinyORM

cp conf.pri.example conf.pri
cp tests/conf.pri.example tests/conf.pri
cp tests/testdata_tom/conf.pri.example tests/testdata_tom/conf.pri
cp examples/tom/conf.pri.example examples/tom/conf.pri
+
info

The Manual configuration internals are described at the end to make this section more clear.

+
note

The Manual configuration is still relevant if you have any non-standard installation of the vcpkg or MySQL and the Auto-configuration feature fails.

+
Opening TinyORM.pro (main project file)
+

Now you can open the TinyORM.pro project in the QtCreator IDE.

+

This will open the Configure Project tab, select some kit and update build folder paths to meet our folders structure or like you want.

+TinyORM - QtCreator - Configure Project +
tip

You can force the QtCreator to generate a build folders structure as is described above.

+

You are ready to configure build options, hit Ctrl+5 to open Project Settings tab and select Build in the left sidebar to open the Build Settings, it should look similar to the following picture.

+

Disable QML debugging and profiling and Qt Quick Compiler, they are not used.

+TinyORM - QtCreator - Build Settings +

If you want to change some TinyORM build options, you can pass them to the Build Steps - qmake TinyORM.pro - Additional arguments input field. It can look like this.

+TinyORM - QtCreator - Build Settings - Additional arguments +

Build TinyORM

+

Everything is ready for build, you can press Ctrl+b to build the project.

+

qmake build options

+
CONFIG Option NameDefaultDescription
build_loadable_driversOFFBuild TinyDrivers as a shared library and SQL database drivers (eg. TinyMySql) as shared libraries (Loadable modules) that are loaded at runtime using LoadLibrary() on Windows or dlopen() on Linux.
build_mysql_driverOFFBuild TinyDrivers MySQL database driver.
It's enabled by default when build_shared_drivers, build_loadable_drivers, or build_static_drivers is enabled.
Available when: build_shared_drivers OR build_loadable_drivers OR build_static_drivers
build_shared_driversOFFBuild TinyDrivers as a Shared library.
build_static_driversOFFBuild TinyDrivers as a Static library archive.
The build_static_drivers qmake configuration option will be select by default when the CONFIG*=static is enabled.
build_testsOFFBuild TinyORM unit tests.
disable_autoconfOFFDisable the Auto-configuration feature (auto-configuration is enabled by default from TinyORM v0.34.0).
disable_dotenvOFFDisable the tiny_dotenv feature (environment files are enabled by default from TinyORM v0.34.0).
disable_thread_localOFFRemove all thread_local storage duration specifiers, it disables multi-threading support.
disable_ormOFFControls the compilation of all ORM-related source code, when this option is enabled, then only the query builder without ORM is compiled. Also excludes ORM-related unit tests.
disable_tomOFFControls the compilation of all Tom-related source code, when this option is disabled, then it also excludes Tom-related unit tests.
extern_constantsONUse extern constants instead of inline constants in the shared build.
ON is highly recommended for the shared build (by default);
is always OFF for the static build.
Available when: CONFIG(shared|dll):!inline_constants
inline_constantsOFFUse inline constants instead of extern constants in the shared build.
OFF is highly recommended for the shared build;
is always ON for the static build.
mysql_pingOFFEnable Orm::MySqlConnection::pingDatabase() method.
tiny_ccache_win32ONEnable compiler cache. Homepage
It works only on Windows systems. It works well with the MSYS2 g++, clang++, msvc, and clang-cl with msvc. It disables precompile_header as they are not supported on Windows and changes the -Zi compiler option to the -Z7 for debug builds as the -Zi compiler option is not supported (link to the issue).
tom_exampleOFFBuild the tom console application example.
+

Advanced TinyORM options.

+
Option NameDefaultDescription
ubsanOFFAllows to enable UBSan sanitizer (Clang only).
+

Important qmake options.

+
CONFIG Option NameDefaultDescription
ccacheOFFEnable compiler cache. Homepage
It works only on the Unix systems. It works well with the g++ and clang++ and also supports precompiled headers.
precompile_header-Enable precompiled headers, you can disable them with:
CONFIG-=precompile_header.
The precompile_header is enabled by default on msvc, g++, clang++, clang-cl on Windows and disabled by default on linux.
static
staticlib
OFFBuild as a static library (lib only).
If you want to build all libraries in the TinyORM project as static library archives and link against static libraries use the CONFIG += static. Don't use the CONFIG += staticlib.
See NOTES.txt for more information (search static vs staticlib).
static_runtimeOFFLink against the shared (dynamic) or static run-time library.
The -MD becomes -MT and -MDd becomes -MTd. It works only on MSVC and MinGW or MSYS2.
Please don't use this option.
Available when: msvc or mingw
+

Consume TinyOrm library (qmake)

+

The TinyOrm.pri file is available to simplify the integration of the TinyORM library into your application. It sets up and configures the CONFIG and DEFINES qmake variables, adds the TinyORM, tom, and vcpkg header files on the system INCLUDEPATH (cross-platform using the -isystem or -imsvc), links against the TinyORM shared or static library using the LIBS.

+

You can use it to configure the TinyORM library when you are linking against it. It does a very similar thing like the CMake's Find Modules feature.

+

Requirements

+

It has a few requirements, you need to:

+
    +
  • specify path to the TinyORM qmake features (.prf files) using the QMAKEFEATURES variable that can only be set in the .qmake.conf file
  • +
  • specify qmake or environment variables to find the vcpkg installation (TINY_VCPKG_ROOT and TINY_VCPKG_TRIPLET)
  • +
  • specify path to the TinyORM build folder (TINYORM_BUILD_TREE) + +
  • +
  • build your application with the same CONFIG qmake variables that were used when building the TinyORM library
  • +
+

Let's explain one by one.

+
QMAKEFEATURES
+

Create the .qmake.conf file in your application root folder with the following content.

+
.qmake.conf
# Path to the PARENT folder of the TinyORM source folder
TINY_MAIN_DIR = $$clean_path(<your_path>)
# To find .env and .env.$$QMAKE_PLATFORM files in YOUR project
TINY_DOTENV_ROOT = $$PWD

# Path to the TinyORM build folder (specified manually)
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/)
# vcpkg - range-v3 and tabulate
TINY_VCPKG_ROOT = $$quote(<your_path>/vcpkg/)
#TINY_VCPKG_TRIPLET = x64-windows

# To find .prf files, needed by eg. CONFIG += tiny_system_headers inline/extern_constants
QMAKEFEATURES *= $$quote($$TINY_MAIN_DIR/TinyORM/qmake/features)
+

You can move all qmake variables that are part of the qmake configuration process to the .env file if you want (recommended), this is possible because the TinyOrm.pri enables the Environment files feature by default.

+

You can look at the Auto-configure using .qmake.conf and .env example for Hello world project of what must stay in the qmake.conf file and what can be moved to the .env files.

+
tip

You can use the Partial guessing of the TINYORM_BUILD_TREE if you don't like to specify it manually.

+
Variables affecting TinyOrm.pri
+

You must define the following variables before the TinyOrm.pri is included:

+
Variable NameDescription
TINYORM_BUILD_TREEPath to the TinyORM build folder.
TINY_VCPKG_ROOTPath to the vcpkg installation folder.
If not defined, then it tries to use the VCPKG_ROOT environment variable.
TINY_VCPKG_TRIPLETThe vcpkg triplet to use (vcpkg/installed/$$TINY_VCPKG_TRIPLET/).
If not defined, then it tries to guess the vcpkg triplet based on the current compiler and OS (based on the QMAKESPEC), and as the last thing, it tries to use the VCPKG_DEFAULT_TRIPLET environment variable.
+

These variables will be set after the configuration is done:

+
Variable NameDescription
TINY_BUILD_SUBFOLDERFolder by release type if CONFIG+=debug_and_release is defined (/debug, /release, or an empty string).
TINY_CCACHE_BUILDTo correctly link ccache build against a ccache build (_ccache or an empty string).
TINY_MSVC_VERSIONThe msvc compiler string (MSVC2022 or MSVC2019).
TINY_QT_VERSION_UNDERSCOREDUnderscored Qt version (eg. 6_7_0).
TINY_RELEASE_TYPE_CAMELBuild type string (Debug, Profile, or Release).
TINY_VCPKG_INCLUDEPath to the vcpkg include folder (vcpkg/installed/<triplet>/include/).
+

Then you simply include the TinyOrm.pri in your project file.

+
AnyProject.pro
include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)
+

And that is all, now you should be able to link against the TinyORM library. 👌

+
Manual configuration examples
+

Frankly, there is no reason to use the Manual configuration (define the variables described below before the 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.

+

You will have to link against the TinyORM library manually if you don't set the TINYORM_BUILD_TREE qmake variable before the inclusion of the TinyOrm.pri file. The INCLUDEPATH is auto-detected every time.

+
# Link against TinyORM library
# ---
TINY_MAIN_DIR = $$clean_path(<your_path>)

# Configure TinyORM library
include($$TINY_MAIN_DIR/TinyORM/qmake/TinyOrm.pri)

# TinyORM library path
TINYORM_BUILD_TREE = $$quote($$TINY_MAIN_DIR/TinyORM-builds-qmake)
LIBS += $$quote(-L$$TINYORM_BUILD_TREE/build-TinyORM-Desktop_Qt_6_7_0_MSVC2019_64bit-Debug/src$${TINY_BUILD_SUBFOLDER}/)
LIBS += -lTinyOrm
+

The same is true for the vcpkg include path. If you don't set the TINY_VCPKG_ROOT or have not defined the VCPKG_ROOT environment variable, then you need to set up the INCLUDEPATH for the vcpkg that provides the range-v3 and tabulate header files.

+
# vcpkg - range-v3 and tabulate
# ---
INCLUDEPATH += $$quote(<your_path>/vcpkg/installed/x64-windows/include/)
+

You can also use TinyORM's qmake function tiny_add_system_includepath() which handles INCLUDEPATH in a cross-platform way.

+
# 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.

+

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.

+

The Auto-configuration feature is designed to find the vcpkg and MySQL installations, and tiny_dotenv to include the .env and .env.(win32|unix|mingw) files in the project's root folder. These new features can be configured using qmake and environment variables, and they also contain some guessing logic if these variables are not defined.

+

The Auto-configuration feature can be turned off using the disable_autoconf qmake configuration option (eg. CONFIG*=disable_autoconf).

+

These are qmake and environment variables that affect the Auto-configuration feature:

+
Variable NameDescription
TINY_VCPKG_ROOTPath to the vcpkg installation folder.
If not defined, then it tries to use the VCPKG_ROOT environment variable.
TINY_VCPKG_TRIPLETThe vcpkg triplet to use (vcpkg/installed/$$TINY_VCPKG_TRIPLET/).
If not defined, then it tries to guess the vcpkg triplet based on the current compiler and OS (based on the QMAKESPEC), and as the last thing, it tries to use the VCPKG_DEFAULT_TRIPLET environment variable.
TINY_MYSQL_ROOTPath to the MySQL installation folder.
If not defined, then it tries to guess the MySQL installation folder (win32 only): $$(ProgramFiles)/MySQL/MySQL Server (8.3|8.2|8.1|8.0|5.7)/
+

You can set these variables in the .env (recommended) or conf.pri files, in the .qmake.conf file (or wherever you want), or as environment variables.

+

These variables will be set after auto-configuration is done:

+
Variable NameDescription
TINY_VCPKG_INCLUDEPath to the vcpkg include folder (vcpkg/installed/<triplet>/include/).
TINY_MYSQL_INCLUDEPath to the MySQL include folder (MySQL Server 8.3/include/).
TINY_MYSQL_LIBPath to the MySQL lib folder (MySQL Server 8.3/lib/).
+

The TINY_MYSQL_INCLUDE and TINY_MYSQL_LIB are only set on win32 platform except mingw.

+

Environment files

+

The tiny_dotenv feature allows us to define the .env and .env.$$TINY_DOTENV_PLATFORM files in the project's root folder. These files are loaded as early as possible so you can affect the qmake configuration process. On the other hand, the conf.pri files are loaded as late as possible, and they can be used to override the qmake configuration.

+

The .env file is included first and is included on all platforms.

+

There is only one requirement for this feature to work correctly, and that is to set the TINY_DOTENV_ROOT qmake variable to the project's root folder. This variable is already set in the .qmake.conf file for the TinyORM project.

+

Then the following names are taken into account: .env, .env.win32, .env.unix, .env.mingw

+
.qmake.conf
# To find .env and .env.$$QMAKE_PLATFORM files
TINY_DOTENV_ROOT = $$PWD
+

The tiny_dotenv feature can be turned off using the disable_dotenv qmake configuration option (eg. CONFIG*=disable_dotenv).

+
warning

Environment files don't work in the CMake builds.

+

Partial guessing of the TINYORM_BUILD_TREE

+

You don't have to manually define the TINYORM_BUILD_TREE in .env or .qmake.conf files. The TINYORM_BUILD_TREE absolute path can be put together for you (this is happening inside the variables.pri file) and TinyORM build folder name can be guessed for you too.

+

You must define the following variables before the TinyOrm.pri will be included to make this real (set them in the .qmake.conf):

+
Variable NameDescription
TINY_MAIN_DIRPath to the PARENT folder of the TinyORM source folder.
TINY_BUILD_TREEPath to the current build tree - TINY_BUILD_TREE = $$shadowed($$PWD).
+

The TINY_MAIN_DIR is required for another features anyway (so it should already be set) and all that's left is to set the TINY_BUILD_TREE.

+
.qmake.conf
# Path to the current build tree (used to guess the TinyORM build tree)
TINY_BUILD_TREE = $$shadowed($$PWD)
+

If you will follow this pattern or logic then you can switch QtCreator Kits and the TINYORM_BUILD_TREE will be auto-generated correctly and will always point to the correct TinyORM build tree.

+

It works this way, all is happening inside the variables.pri, it takes a build folder name for the current project eg. build-HelloWorld-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug, replaces the HelloWorld with the TinyORM and as we already know the TinyORM build folder location we can simply concatenate these paths like $$TINY_MAIN_DIR/TinyORM-builds-qmake/build-TinyORM-Desktop_Qt_6_7_0_MSVC2022_64bit-Debug.

+
warning

This will only work if you follow the recommended Folders structure.

+

Manual configuration internals

+

There is not much to say about the Manual configuration feature. It uses conf.pri files (there are four, one for every project or sub-project), and every project has prepared its own conf.pri.example file for faster initial configuration.

+

These conf.pri.example files are nicely commented on, so you can see what needs to be modified. The conf.pri files are loaded as late as possible, and they can be used to override the qmake configuration.

+

If the Auto-configuration feature is disabled and there are no conf.pri files, then the TinyORM qmake configuration or build will fail at 100%.

+

These conf.pri files are intended for configuring qmake's INCLUDEPATH and LIBS, CONFIG or eg. QMAKE_LFLAGS, or any other qmake options or variables.

+

Ccache support

+

The TinyORM supports the ccache out of the box for all supported compilers. For qmake you can enable it using the CONFIG+=ccache on Linux or CONFIG+=tiny_ccache_win32 on Windows. For CMake you can set the CMAKE_CXX_COMPILER_LAUNCHER=ccache.

+

On Linux it's clear, the ccache is fully supported and works also with the precompiled headers. But was necessary to add some workarounds to the qmake/CMake build systems to make out of the box support on Windows. When you enable the ccache on Windows then the build system disables precompiled headers and replaces the -Zi compiler option with the -Z7 (link to the issue).

+
tip

You can install the ccache using the scoop install ccache command on Windows.

\ No newline at end of file diff --git a/database/getting-started.html b/database/getting-started.html index ce3156086..0d2b7d3fe 100644 --- a/database/getting-started.html +++ b/database/getting-started.html @@ -1,9 +1,9 @@ - + - -Database: Getting Started - TinyORM + +Database: Getting Started - TinyORM @@ -13,14 +13,141 @@ - - - + + + -
-

Database: Getting Started

Introduction

Almost every modern application interacts with a database. TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. Currently, TinyORM provides first-party support for four databases:

TinyORM internally uses QtSql module, you can look for supported databases.

note

TinyORM's code is ready and designed to simply add support for the SQL Server.

Configuration

You can create and configure a new database connection using the create method provided by the DB facade:

#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},
{"port", qEnvironmentVariable("DB_PORT", "3306")},
{"database", qEnvironmentVariable("DB_DATABASE", "")},
{"username", qEnvironmentVariable("DB_USERNAME", "root")},
{"password", qEnvironmentVariable("DB_PASSWORD", "")},
{"charset", qEnvironmentVariable("DB_CHARSET", "utf8mb4")},
{"collation", qEnvironmentVariable("DB_COLLATION", "utf8mb4_0900_ai_ci")},
{"timezone", "+00:00"},
/* Specifies what time zone all QDateTime-s will have, the overridden default is
the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use
the system local time. */
{"qt_timezone", QVariant::fromValue(Qt::UTC)},
{"prefix", ""},
{"prefix_indexes", false},
{"strict", true},
{"engine", "InnoDB"},
{"options", QVariantHash()},
});
#include <orm/db.hpp>
#include <orm/utils/configuration.hpp>

using Orm::DB;

using ConfigUtils = Orm::Utils::Configuration;

using namespace Orm::Constants; // NOLINT(google-build-using-namespace)

// Ownership of a shared_ptr()
auto manager = DB::create({
{driver_, QMYSQL},
{host_, qEnvironmentVariable("DB_HOST", H127001)},
{port_, qEnvironmentVariable("DB_PORT", P3306)},
{database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},
{username_, qEnvironmentVariable("DB_USERNAME", ROOT)},
{password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},
{charset_, qEnvironmentVariable("DB_CHARSET", UTF8MB4)},
{collation_, qEnvironmentVariable("DB_COLLATION", UTF8MB40900aici)},
// SSL-related
{ssl_ca, QStringLiteral("C:/mysql/data/ca.pem")},
{ssl_cert, QStringLiteral("C:/mysql/data/client-cert.pem")},
{ssl_key, QStringLiteral("C:/mysql/data/client-key.pem")},
{ssl_mode, VerifyCA},
// Or
// {options, ConfigUtils::mysqlSslOptions()},
{timezone_, TZ00},
/* Specifies what time zone all QDateTime-s will have, the overridden default is
the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use
the system local time. */
{qt_timezone, QVariant::fromValue(Qt::UTC)},
{prefix_, EMPTY},
{prefix_indexes, false},
{strict_, true},
// {isolation_level, QStringLiteral("REPEATABLE READ")}, // MySQL default is REPEATABLE READ for InnoDB
{engine_, InnoDB},
{Version, {}}, // Autodetect
{options_, QVariantHash()},
// Examples
// {options_, QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT = 1 ; MYSQL_OPT_READ_TIMEOUT=1")},
// {options_, QVariantHash {{QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT"), 1},
// {QStringLiteral("MYSQL_OPT_READ_TIMEOUT"), 1}}},
});

The first argument is configuration hash which is of type QVariantHash and the second argument specifies the name of the connection, this connection will also be a default connection. You can configure multiple database connections at once and choose the needed one before executing SQL query, section Using Multiple Database Connections describes how to create and use multiple database connections.

You may also configure connection options by options key as QVariantHash or QString, you can pass any connection options supported by QSqlDatabase.

You can also configure Transaction Isolation Levels for MySQL connection with the isolation_level configuration option.

The version option is relevant only for the MySQL connections and you can save/avoid one database query (select version()) if you provide it manually. On the base of this version will be decided which session variables will be set if strict mode is enabled and whether to use an alias during the upsert method call.

Breaking values are as follows; use an upsert alias on the MySQL >=8.0.19 and remove the NO_AUTO_CREATE_USER sql mode on the MySQL >=8.0.11 if the strict mode is enabled.

info

A database connection is resolved lazily, which means that the connection configuration is only saved after the DB::create method call. The connection will be resolved after you run some query or you can create it using the DB::connection method.

tip

You can also use predefined string constants to avoid unnecessary QString instantiations, as used in the tom migrations example.

SQLite Configuration

SQLite databases are contained within a single file on your filesystem. You can create a new SQLite database using the touch command in your terminal: touch database.sqlite3. After the database has been created, you may configure SQLite database connection:

#include <orm/db.hpp>

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QSQLITE"},
{"database", qEnvironmentVariable("DB_DATABASE", "/absolute/path/to/database.sqlite3")},
{"foreign_key_constraints", qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},
{"check_database_exists", true},
{"prefix", ""},
});

The database configuration value is the absolute path to the database. To enable foreign key constraints for SQLite connections, you should set the foreign_key_constraints configuration value to true, if this configuration value is not set, then the default of the SQLite driver will be used (currently the default is disabled).

If the check_database_exists configuration value is set to the true value, then the database connection throws an Orm::InvalidArgumentError exception, when the SQLite database file doesn't exist. If it is set to the false value and the SQLite database file doesn't exist, then it will be created for you by SQLite driver. The default value is true.

SSL Connections

SSL connections are supported for the MySQL and PostgreSQL databases. They can be set using the options configuration option.

info

This feature is heavily dependent on the underlying QSqlDatabase module. What means that you can pass the same connection options to the TinyORM that the QSqlDatabase accepts.

MySQL

You have to pass the SSL_CA, SSL_CERT, SSL_KEY, and MYSQL_OPT_SSL_MODE options.

#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
...
{"options", QVariantHash({{"SSL_CA", "C:/mysql/data/ca.pem"},
{"SSL_CERT", "C:/mysql/data/client-cert.pem"},
{"SSL_KEY", "C:/mysql/data/client-key.pem"},
{"MYSQL_OPT_SSL_MODE", "VERIFY_CA"}})},
});

You may also use the ConfigUtils::mysqlSslOptions() or the ConfigUtils::insertMySqlSslOptions() methods to insert these options for you and define them using the DB_MYSQL_SSL_CA, DB_MYSQL_SSL_CERT, DB_MYSQL_SSL_KEY, and DB_MYSQL_SSL_MODE environment variables.

#include <orm/db.hpp>
#include <orm/utils/configuration.hpp>

using Orm::DB;

using ConfigUtils = Orm::Utils::Configuration;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
...
{"options", ConfigUtils::mysqlSslOptions()},
});

You can define these SSL-related options in the top-level configuration, they will be copied to the options option hash during configuration parsing. The top-level configuration takes precedence and overwrites the options in the options hash.

#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
...
{"SSL_CA", "C:/mysql/data/ca.pem"},
{"SSL_CERT", "C:/mysql/data/client-cert.pem"},
{"SSL_KEY", "C:/mysql/data/client-key.pem"},
{"MYSQL_OPT_SSL_MODE", "VERIFY_CA"},
});
tip

You can take a look at the GitHub actions how the MySQL certificates are generated in the CI pipeline for Windows and Linux.

tip

You can also pass the QString to the options configuration separated by the ; semicolon character and use the = to assign values.

PostgreSQL

You have to pass the sslmode or the deprecated requiressl options.

#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"options", QVariantHash({{"sslmode", "verify-full"}})},
});

And place your client certificates to the ~/.postgres/ on Linux and $env:APPDATA/postgres/ on Windows. Everything is described in the PostgreSQL's libpq client and server documentation.

If you want to keep your client certificates in your own location, you can set the sslcert, sslkey, and sslrootcert options.

#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"options", QVariantHash({{"sslmode", "verify-full"},
{"sslcert", "C:/example/postgres.crt"},
{"sslkey", "C:/example/postgres.key"},
{"sslrootcert", "C:/example/root.crt"}})},
});

You can define these SSL-related options in the top-level configuration, they will be copied to the options option hash during a configuration parsing. The top-level configuration takes precedence and overwrites the options in the options hash.

#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"sslmode", "verify-full"},
{"sslcert", "C:/example/postgres.crt"},
{"sslkey", "C:/example/postgres.key"},
{"sslrootcert", "C:/example/root.crt"},
});

You may also use the ConfigUtils::postgresSslOptions() or the ConfigUtils::insertPostgresSslOptions() methods to insert the sslmode, sslcert, sslkey, and sslrootcert options for you and define them using the DB_PGSQL_SSLMODE, DB_PGSQL_SSLCERT, DB_PGSQL_SSLKEY, and DB_PGSQL_SSLROOTCERT environment variable.

#include <orm/db.hpp>
#include <orm/utils/configuration.hpp>

using Orm::DB;

using ConfigUtils = Orm::Utils::Configuration;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"options", ConfigUtils::postgresSslOptions()},
});
info

The PostgreSQL's libpq client library provides the PGSSLMODE, PGSSLCERT, PGSSLKEY, and PGSSLROOTCERT environment variables, so you don't have to use TinyORM's options configuration and may use these environment variables instead.

tip

You can take a look at the GitHub actions how the PostgreSQL certificates are generated in the CI pipeline for Windows and Linux.

Running SQL Queries

Once you have configured your database connection, you may run queries using the DB facade. The DB facade provides methods for each type of query: select, update, insert, delete, and statement.

Running A Select Query

To run a basic SELECT query, you may use the select method on the DB facade:

auto users = DB::select("select * from users where active = ?", {1});

The first argument passed to the select method is the SQL query, while the second argument is any parameter bindings that need to be bound to the query. Typically, these are the values of the where clause constraints. Parameter binding provides protection against SQL injection.

The select method returns a QSqlQuery containing the results of the query, where each result can be accessed by QSqlQuery::next method. Look into the QSqlQuery documentation on how to obtain results from the "query". You may access each column's value by QSqlQuery::value method. The first bool return value is the value returned from QSqlQuery::exec method:

#include <QDebug>

#include <orm/db.hpp>

auto users = DB::select("select * from users");

while(users.next())
qDebug() << users.value("name").toString();

Selecting Scalar Values

Sometimes your database query may result in a single, scalar value. Instead of being required to retrieve the query's scalar result from a record instance, TinyORM allows you to retrieve this value directly using the scalar shortcut method:

#include <orm/db.hpp>

auto states = DB::scalar(
"select count(case when state = 'pending' then 1 end) as states "
"from comments"
);

// With binding
auto states = DB::scalar(
"select count(case when state = ? then 1 end) as states from comments",
{"pending"}
);

Running An Insert Statement

To execute an insert statement, you may use the insert method on the DB facade. Like select, this method accepts the SQL query as its first argument and bindings as its second argument and returns QSqlQuery:

#include <orm/db.hpp>

DB::insert("insert into users (id, name) values (?, ?)", {1, "Marc"});

Running An Update Statement

The update method should be used to update existing records in the database. The number of rows affected by the statement and QSqlQuery is returned by the method as std::tuple<int, QSqlQuery>:

#include <QDateTime>

#include <orm/db.hpp>

auto [affected, query] = DB::update(
"update users set updated_at = ? where name = ?",
{QDateTime::currentDateTimeUtc(), "Anita"}
);

if (!affected)
qDebug() << "Any record was updated.";

Running A Delete Statement

The remove method should be used to delete records from the database. Like update, the number of affected rows and QSqlQuery will be returned by the method as std::tuple<int, QSqlQuery>:

#include <orm/db.hpp>

auto [affected, query] = DB::remove("delete from users");
note

delete can not be used as the method name because it is the reserved word.

Running A General Statement

Some database statements do not return any value. For these types of operations, you may use the statement method on the DB facade:

DB::statement("drop table users");
tip

DB::statement method should be used for DDL queries, don't use it for "select" queries because it internally calls recordsHaveBeenModified method.

Running An Unprepared Statement

Sometimes you may want to execute an SQL statement without binding any values. You may use the DB facade's unprepared method to accomplish this:

DB::unprepared("update users set votes = 100 where name = 'Dries'");
caution

Since unprepared statements do not bind parameters, they may be vulnerable to SQL injection. You should never allow user controlled values within an unprepared statement.

Implicit Commits

When using the DB facade's statement methods within transactions, you must be careful to avoid statements that cause implicit commits. These statements will cause the database engine to indirectly commit the entire transaction, leaving TinyORM unaware of the database's transaction level. An example of such a statement is creating a database table:

DB::statement("create table users (name varchar(255) null)");

Please refer to the MySQL manual for a list of all statements that trigger implicit commits.

Using Multiple Database Connections

You can configure multiple database connections at once during DatabaseManager instantiation using the DB::create overload, where the first argument is a hash of multiple connections and is of type QHash<QString, QVariantHash> and the second argument is the name of the default connection:

#include <orm/db.hpp>

// Ownership of a shared_ptr()
auto manager = DB::create({
{"mysql", {
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
{"port", qEnvironmentVariable("DB_MYSQL_PORT", "3306")},
{"database", qEnvironmentVariable("DB_MYSQL_DATABASE", "")},
{"username", qEnvironmentVariable("DB_MYSQL_USERNAME", "root")},
{"password", qEnvironmentVariable("DB_MYSQL_PASSWORD", "")},
{"charset", qEnvironmentVariable("DB_MYSQL_CHARSET", "utf8mb4")},
{"collation", qEnvironmentVariable("DB_MYSQL_COLLATION", "utf8mb4_0900_ai_ci")},
{"strict", true},
{"options", QVariantHash()},
}},
{"sqlite", {
{"driver", "QSQLITE"},
{"database", qEnvironmentVariable("DB_SQLITE_DATABASE", "")},
{"foreign_key_constraints", qEnvironmentVariable("DB_SQLITE_FOREIGN_KEYS", "true")},
{"check_database_exists", true},
{"prefix", ""},
}},
}, "mysql");

If your application needs to use multiple connections, you may access each connection via the connection method provided by the DB facade. The connection name passed to the connection method should correspond to one of the connections key listed in your configuration:

#include <orm/db.hpp>

auto query = DB::connection("mysql_test").select(...);

You may access the raw underlying QSqlQuery instance of a connection using the getQtQuery method on a connection instance:

auto query = DB::connection().getQtQuery();

Or you can use the shortcut method qtQuery provided by the DB facade:

auto query = DB::qtQuery();

Database Transactions

Manually Using Transactions

If you would like to begin a transaction manually and have complete control over rollbacks and commits, you may use the beginTransaction method provided by the DB facade:

#include <orm/db.hpp>

DB::beginTransaction();

You can rollback the transaction via the rollBack method:

DB::rollBack();

Lastly, you can commit a transaction via the commit method:

DB::commit();

All transaction methods accept a connection name as the optional argument:

DB::beginTransaction("mysql_test");
tip

The DB facade's transaction methods control the transactions for both the query builder and TinyORM.

Multi-threading support

The TinyORM supports multi-threading for the MSVC and GCC on Linux compilers. Multi-threading is disabled for the Clang <14.0.3 compiler on MSYS2, Clang <14.0.4 on Linux and for the GCC compiler on MSYS2. The reason are bugs in the TLS wrapper that is generated by the thread_local keyword.

A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread where the connection was created is not supported.

In addition, the third party libraries used by the QSqlDrivers can impose further restrictions on using the SQL Module in a multithreaded program.

In short, if you create a DB::connection in some thread then you have to use this connection only from this particular thread and of course all queries that will be executed on this connection.

If you want to execute some query from another thread for the same connection then you have to create a new connection first and if you have a new connection you can send a query from this new thread to the database.

caution

The schema builder and migrations don't support multi-threading.

- - +

Database: Getting Started

+ +

Introduction

+

Almost every modern application interacts with a database. TinyORM makes interacting with a database extremely simple using raw SQL, a fluent query builder, and the TinyORM. Currently, TinyORM provides first-party support for four databases:

+
+

TinyORM internally uses QtSql module, you can look for supported databases.

+
note

TinyORM's code is ready and designed to simply add support for the SQL Server.

+

Configuration

+

You can create and configure a new database connection using the create method provided by the DB facade:

+
#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_HOST", "127.0.0.1")},
{"port", qEnvironmentVariable("DB_PORT", "3306")},
{"database", qEnvironmentVariable("DB_DATABASE", "")},
{"username", qEnvironmentVariable("DB_USERNAME", "root")},
{"password", qEnvironmentVariable("DB_PASSWORD", "")},
{"charset", qEnvironmentVariable("DB_CHARSET", "utf8mb4")},
{"collation", qEnvironmentVariable("DB_COLLATION", "utf8mb4_0900_ai_ci")},
{"timezone", "+00:00"},
/* Specifies what time zone all QDateTime-s will have, the overridden default is
the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use
the system local time. */
{"qt_timezone", QVariant::fromValue(Qt::UTC)},
{"prefix", ""},
{"prefix_indexes", false},
{"strict", true},
{"engine", "InnoDB"},
{"options", QVariantHash()},
});
#include <orm/db.hpp>
#include <orm/utils/configuration.hpp>

using Orm::DB;

using ConfigUtils = Orm::Utils::Configuration;

using namespace Orm::Constants; // NOLINT(google-build-using-namespace)

// Ownership of a shared_ptr()
auto manager = DB::create({
{driver_, QMYSQL},
{host_, qEnvironmentVariable("DB_HOST", H127001)},
{port_, qEnvironmentVariable("DB_PORT", P3306)},
{database_, qEnvironmentVariable("DB_DATABASE", EMPTY)},
{username_, qEnvironmentVariable("DB_USERNAME", ROOT)},
{password_, qEnvironmentVariable("DB_PASSWORD", EMPTY)},
{charset_, qEnvironmentVariable("DB_CHARSET", UTF8MB4)},
{collation_, qEnvironmentVariable("DB_COLLATION", UTF8MB40900aici)},
// SSL-related
{ssl_ca, QStringLiteral("C:/mysql/data/ca.pem")},
{ssl_cert, QStringLiteral("C:/mysql/data/client-cert.pem")},
{ssl_key, QStringLiteral("C:/mysql/data/client-key.pem")},
{ssl_mode, VerifyCA},
// Or
// {options, ConfigUtils::mysqlSslOptions()},
{timezone_, TZ00},
/* Specifies what time zone all QDateTime-s will have, the overridden default is
the Qt::UTC, set to the Qt::LocalTime or QtTimeZoneType::DontConvert to use
the system local time. */
{qt_timezone, QVariant::fromValue(Qt::UTC)},
{prefix_, EMPTY},
{prefix_indexes, false},
{strict_, true},
// {isolation_level, QStringLiteral("REPEATABLE READ")}, // MySQL default is REPEATABLE READ for InnoDB
{engine_, InnoDB},
{Version, {}}, // Autodetect
{options_, QVariantHash()},
// Examples
// {options_, QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT = 1 ; MYSQL_OPT_READ_TIMEOUT=1")},
// {options_, QVariantHash {{QStringLiteral("MYSQL_OPT_CONNECT_TIMEOUT"), 1},
// {QStringLiteral("MYSQL_OPT_READ_TIMEOUT"), 1}}},
});
+

The first argument is configuration hash which is of type QVariantHash and the second argument specifies the name of the connection, this connection will also be a default connection. You can configure multiple database connections at once and choose the needed one before executing SQL query, section Using Multiple Database Connections describes how to create and use multiple database connections.

+

You may also configure connection options by options key as QVariantHash or QString, you can pass any connection options supported by QSqlDatabase.

+

You can also configure Transaction Isolation Levels for MySQL connection with the isolation_level configuration option.

+

The version option is relevant only for the MySQL connections and you can save/avoid one database query (select version()) if you provide it manually. On the base of this version will be decided which session variables will be set if strict mode is enabled and whether to use an alias during the upsert method call.

+

Breaking values are as follows; use an upsert alias on the MySQL >=8.0.19 and remove the NO_AUTO_CREATE_USER sql mode on the MySQL >=8.0.11 if the strict mode is enabled.

+
info

A database connection is resolved lazily, which means that the connection configuration is only saved after the DB::create method call. The connection will be resolved after you run some query or you can create it using the DB::connection method.

+
tip

You can also use predefined string constants to avoid unnecessary QString instantiations, as used in the tom migrations example.

+

SQLite Configuration

+

SQLite databases are contained within a single file on your filesystem. You can create a new SQLite database using the touch command in your terminal: touch database.sqlite3. After the database has been created, you may configure SQLite database connection:

+
#include <orm/db.hpp>

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QSQLITE"},
{"database", qEnvironmentVariable("DB_DATABASE", "/absolute/path/to/database.sqlite3")},
{"foreign_key_constraints", qEnvironmentVariable("DB_FOREIGN_KEYS", "true")},
{"check_database_exists", true},
{"prefix", ""},
});
+

The database configuration value is the absolute path to the database. To enable foreign key constraints for SQLite connections, you should set the foreign_key_constraints configuration value to true, if this configuration value is not set, then the default of the SQLite driver will be used (currently the default is disabled).

+

If the check_database_exists configuration value is set to the true value, then the database connection throws an Orm::InvalidArgumentError exception, when the SQLite database file doesn't exist. If it is set to the false value and the SQLite database file doesn't exist, then it will be created for you by SQLite driver. The default value is true.

+

SSL Connections

+

SSL connections are supported for the MySQL and PostgreSQL databases. They can be set using the options configuration option.

+
info

This feature is heavily dependent on the underlying QSqlDatabase module. What means that you can pass the same connection options to the TinyORM that the QSqlDatabase accepts.

+
MySQL
+

You have to pass the SSL_CA, SSL_CERT, SSL_KEY, and MYSQL_OPT_SSL_MODE options.

+
#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
...
{"options", QVariantHash({{"SSL_CA", "C:/mysql/data/ca.pem"},
{"SSL_CERT", "C:/mysql/data/client-cert.pem"},
{"SSL_KEY", "C:/mysql/data/client-key.pem"},
{"MYSQL_OPT_SSL_MODE", "VERIFY_CA"}})},
});
+

You may also use the ConfigUtils::mysqlSslOptions() or the ConfigUtils::insertMySqlSslOptions() methods to insert these options for you and define them using the DB_MYSQL_SSL_CA, DB_MYSQL_SSL_CERT, DB_MYSQL_SSL_KEY, and DB_MYSQL_SSL_MODE environment variables.

+
#include <orm/db.hpp>
#include <orm/utils/configuration.hpp>

using Orm::DB;

using ConfigUtils = Orm::Utils::Configuration;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
...
{"options", ConfigUtils::mysqlSslOptions()},
});
+

You can define these SSL-related options in the top-level configuration, they will be copied to the options option hash during configuration parsing. The top-level configuration takes precedence and overwrites the options in the options hash.

+
#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
...
{"SSL_CA", "C:/mysql/data/ca.pem"},
{"SSL_CERT", "C:/mysql/data/client-cert.pem"},
{"SSL_KEY", "C:/mysql/data/client-key.pem"},
{"MYSQL_OPT_SSL_MODE", "VERIFY_CA"},
});
+
tip

You can take a look at the GitHub actions how the MySQL certificates are generated in the CI pipeline for Windows and Linux.

+
tip

You can also pass the QString to the options configuration separated by the ; semicolon character and use the = to assign values.

+
PostgreSQL
+

You have to pass the sslmode or the deprecated requiressl options.

+
#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"options", QVariantHash({{"sslmode", "verify-full"}})},
});
+

And place your client certificates to the ~/.postgres/ on Linux and $env:APPDATA/postgres/ on Windows. Everything is described in the PostgreSQL's libpq client and server documentation.

+

If you want to keep your client certificates in your own location, you can set the sslcert, sslkey, and sslrootcert options.

+
#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"options", QVariantHash({{"sslmode", "verify-full"},
{"sslcert", "C:/example/postgres.crt"},
{"sslkey", "C:/example/postgres.key"},
{"sslrootcert", "C:/example/root.crt"}})},
});
+

You can define these SSL-related options in the top-level configuration, they will be copied to the options option hash during a configuration parsing. The top-level configuration takes precedence and overwrites the options in the options hash.

+
#include <orm/db.hpp>

using Orm::DB;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"sslmode", "verify-full"},
{"sslcert", "C:/example/postgres.crt"},
{"sslkey", "C:/example/postgres.key"},
{"sslrootcert", "C:/example/root.crt"},
});
+

You may also use the ConfigUtils::postgresSslOptions() or the ConfigUtils::insertPostgresSslOptions() methods to insert the sslmode, sslcert, sslkey, and sslrootcert options for you and define them using the DB_PGSQL_SSLMODE, DB_PGSQL_SSLCERT, DB_PGSQL_SSLKEY, and DB_PGSQL_SSLROOTCERT environment variable.

+
#include <orm/db.hpp>
#include <orm/utils/configuration.hpp>

using Orm::DB;

using ConfigUtils = Orm::Utils::Configuration;

// Ownership of a shared_ptr()
auto manager = DB::create({
{"driver", "QPSQL"},
{"host", qEnvironmentVariable("DB_PGSQL_HOST", "127.0.0.1")},
...
{"options", ConfigUtils::postgresSslOptions()},
});
+
info

The PostgreSQL's libpq client library provides the PGSSLMODE, PGSSLCERT, PGSSLKEY, and PGSSLROOTCERT environment variables, so you don't have to use TinyORM's options configuration and may use these environment variables instead.

+
tip

You can take a look at the GitHub actions how the PostgreSQL certificates are generated in the CI pipeline for Windows and Linux.

+

Running SQL Queries

+

Once you have configured your database connection, you may run queries using the DB facade. The DB facade provides methods for each type of query: select, update, insert, delete, and statement.

+

Running A Select Query

+

To run a basic SELECT query, you may use the select method on the DB facade:

+

auto users = DB::select("select * from users where active = ?", 1);

+

The first argument passed to the select method is the SQL query, while the second argument is any parameter bindings that need to be bound to the query. Typically, these are the values of the where clause constraints. Parameter binding provides protection against SQL injection.

+

The select method returns a QSqlQuery containing the results of the query, where each result can be accessed by QSqlQuery::next method. Look into the QSqlQuery documentation on how to obtain results from the "query". You may access each column's value by QSqlQuery::value method. The first bool return value is the value returned from QSqlQuery::exec method:

+
#include <QDebug>

#include <orm/db.hpp>

auto users = DB::select("select * from users");

while(users.next())
qDebug() << users.value("name").toString();
+

Selecting Scalar Values

+

Sometimes your database query may result in a single, scalar value. Instead of being required to retrieve the query's scalar result from a record instance, TinyORM allows you to retrieve this value directly using the scalar shortcut method:

+
#include <orm/db.hpp>

auto states = DB::scalar(
"select count(case when state = 'pending' then 1 end) as states "
"from comments"
);

// With binding
auto states = DB::scalar(
"select count(case when state = ? then 1 end) as states from comments",
{"pending"}
);
+

Running An Insert Statement

+

To execute an insert statement, you may use the insert method on the DB facade. Like select, this method accepts the SQL query as its first argument and bindings as its second argument and returns QSqlQuery:

+
#include <orm/db.hpp>

DB::insert("insert into users (id, name) values (?, ?)", {1, "Marc"});
+

Running An Update Statement

+

The update method should be used to update existing records in the database. The number of rows affected by the statement and QSqlQuery is returned by the method as std::tuple<int, QSqlQuery>:

+
#include <QDateTime>

#include <orm/db.hpp>

auto [affected, query] = DB::update(
"update users set updated_at = ? where name = ?",
{QDateTime::currentDateTimeUtc(), "Anita"}
);

if (!affected)
qDebug() << "Any record was updated.";
+

Running A Delete Statement

+

The remove method should be used to delete records from the database. Like update, the number of affected rows and QSqlQuery will be returned by the method as std::tuple<int, QSqlQuery>:

+
#include <orm/db.hpp>

auto [affected, query] = DB::remove("delete from users");
+
note

delete can not be used as the method name because it is the reserved word.

+

Running A General Statement

+

Some database statements do not return any value. For these types of operations, you may use the statement method on the DB facade:

+
DB::statement("drop table users");
+
tip

DB::statement method should be used for DDL queries, don't use it for "select" queries because it internally calls recordsHaveBeenModified method.

+

Running An Unprepared Statement

+

Sometimes you may want to execute an SQL statement without binding any values. You may use the DB facade's unprepared method to accomplish this:

+
DB::unprepared("update users set votes = 100 where name = 'Dries'");
+
warning

Since unprepared statements do not bind parameters, they may be vulnerable to SQL injection. You should never allow user controlled values within an unprepared statement.

+

Implicit Commits

+

When using the DB facade's statement methods within transactions, you must be careful to avoid statements that cause implicit commits. These statements will cause the database engine to indirectly commit the entire transaction, leaving TinyORM unaware of the database's transaction level. An example of such a statement is creating a database table:

+
DB::statement("create table users (name varchar(255) null)");
+

Please refer to the MySQL manual for a list of all statements that trigger implicit commits.

+

Using Multiple Database Connections

+

You can configure multiple database connections at once during DatabaseManager instantiation using the DB::create overload, where the first argument is a hash of multiple connections and is of type QHash<QString, QVariantHash> and the second argument is the name of the default connection:

+
#include <orm/db.hpp>

// Ownership of a shared_ptr()
auto manager = DB::create({
{"mysql", {
{"driver", "QMYSQL"},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
{"port", qEnvironmentVariable("DB_MYSQL_PORT", "3306")},
{"database", qEnvironmentVariable("DB_MYSQL_DATABASE", "")},
{"username", qEnvironmentVariable("DB_MYSQL_USERNAME", "root")},
{"password", qEnvironmentVariable("DB_MYSQL_PASSWORD", "")},
{"charset", qEnvironmentVariable("DB_MYSQL_CHARSET", "utf8mb4")},
{"collation", qEnvironmentVariable("DB_MYSQL_COLLATION", "utf8mb4_0900_ai_ci")},
{"strict", true},
{"options", QVariantHash()},
}},
{"sqlite", {
{"driver", "QSQLITE"},
{"database", qEnvironmentVariable("DB_SQLITE_DATABASE", "")},
{"foreign_key_constraints", qEnvironmentVariable("DB_SQLITE_FOREIGN_KEYS", "true")},
{"check_database_exists", true},
{"prefix", ""},
}},
}, "mysql");
+

If your application needs to use multiple connections, you may access each connection via the connection method provided by the DB facade. The connection name passed to the connection method should correspond to one of the connections key listed in your configuration:

+
#include <orm/db.hpp>

auto query = DB::connection("mysql_test").select(...);
+

You may access the raw underlying QSqlQuery instance of a connection using the getQtQuery method on a connection instance:

+
auto query = DB::connection().getQtQuery();
+

Or you can use the shortcut method qtQuery provided by the DB facade:

+
auto query = DB::qtQuery();
+

Database Transactions

+

Manually Using Transactions

+

If you would like to begin a transaction manually and have complete control over rollbacks and commits, you may use the beginTransaction method provided by the DB facade:

+
#include <orm/db.hpp>

DB::beginTransaction();
+

You can rollback the transaction via the rollBack method:

+
DB::rollBack();
+

Lastly, you can commit a transaction via the commit method:

+
DB::commit();
+

All transaction methods accept a connection name as the optional argument:

+
DB::beginTransaction("mysql_test");
+
tip

The DB facade's transaction methods control the transactions for both the query builder and TinyORM.

+

Multi-threading support

+

The TinyORM supports multi-threading for the MSVC and GCC on Linux compilers. Multi-threading is disabled for the Clang <14.0.3 compiler on MSYS2, Clang <14.0.4 on Linux and for the GCC compiler on MSYS2. The reason are bugs in the TLS wrapper that is generated by the thread_local keyword.

+

A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread where the connection was created is not supported.

+

In addition, the third party libraries used by the QSqlDrivers can impose further restrictions on using the SQL Module in a multithreaded program.

+

In short, if you create a DB::connection in some thread then you have to use this connection only from this particular thread and of course all queries that will be executed on this connection.

+

If you want to execute some query from another thread for the same connection then you have to create a new connection first and if you have a new connection you can send a query from this new thread to the database.

+
warning

The schema builder and migrations don't support multi-threading.

\ No newline at end of file diff --git a/database/migrations.html b/database/migrations.html index 64d03e087..919ebbe85 100644 --- a/database/migrations.html +++ b/database/migrations.html @@ -1,9 +1,9 @@ - + - -Database: Migrations - TinyORM + +Database: Migrations - TinyORM @@ -13,13 +13,173 @@ - - - + + + -
-

Database: Migrations

Introduction

Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. If you have ever had to tell a teammate to manually add a column to their local database schema after pulling in your changes from source control, you've faced the problem that database migrations solve.

The TinyORM Schema facade provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems. Typically, migrations will use this facade to create and modify database tables and columns.

The tom migrations is a small console application that depends on the TinyORM library. All migrations logic is compiled so recompilation is needed after adding a new migration class.

caution
note

TinyORM's schema builder supports all supported databases out of the box.

The following image shows what the tom console application looks like. ✨ As you can see it offers everything that is needed to generate and manage migrations and seeders and all of this is backed up with the tab completion.

TinyORM - Tom console application - Showcase

Generating Migrations

You may use the make:migration tom command to generate a database migration. The new migration will be placed in your database/migrations directory. Each migration filename contains a timestamp that allows tom to determine the order of the migrations:

tom make:migration create_posts_table

tom will use the name of the migration to attempt to guess the name of the table and whether or not the migration will be creating a new table. If tom is able to determine the table name from the migration name, tom will pre-fill the generated migration file with the specified table. Otherwise, you may simply specify the table in the migration file manually.

If you would like to specify a custom path for the generated migration, you may use the --path option when executing the make:migration command. The given path should be relative to your pwd or you can use the --realpath option and pass the absolute path to the --path option.

Migrations naming rules

If the migration name starts with the create_ string then the stub for table creation will be used and if the migration name contains _(from|to|in)_ then the stub for table update will be used. You can override these rules using the --create and --table options and specify the table name manually.

tip

You can also pass the full migration filename with the datetime prefix and extension to the make:migration. This command is able to detect almost any combination of the passed value, with or without datetime prefix or extension if it is the filename; or StudlyCase, snake_case, or kebab-case if it is the classname or any combination described above. 👀

Tab completion

Tab completion is available for the pwsh (on Linux too), bash, and zsh shells. For pwsh the tom.exe and TinyOrm0.dll library must be on the system path to work properly. With bash if the tom executable and libTinyOrm.so library is not on the system path then it will provide less accurate completions.

You can enable it using the following commands.

tom integrate pwsh

Or you can enable it manually. Following actions are the same as the tom integrate command does.

For the pwsh paste the following code to the pwsh profile (works on Linux or Windows).

~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1
Register-ArgumentCompleter -Native -CommandName tom,tom_testdata -ScriptBlock {
Param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding =
[Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
$Local:word = $wordToComplete.Replace('"', '\"')
$Local:ast = $commandAst.ToString().Replace('"', '\"')
tom complete --word="$Local:word" --commandline="$Local:ast" --position=$cursorPosition
| ForEach-Object {
$completionText, $listText, $toolTip = $_ -split ';', 3
$listText ??= $completionText
$toolTip ??= $completionText
[System.Management.Automation.CompletionResult]::new(
$completionText, $listText, 'ParameterValue', $toolTip)
}
}

For bash you can copy or create symlink of the /tools/completions/tom.bash file to the /usr/share/bash-completion/completions folder.

sudo ln -s /TinyORM/tools/completions/tom.bash /usr/share/bash-completion/completions/tom

And for zsh you can copy or create symlink of the /tools/completions/tom.zsh file to the _tom file to /usr/local/share/zsh/site-functions folder.

sudo ln -s /TinyORM/tools/completions/tom.zsh /usr/local/share/zsh/site-functions/_tom

It will provide completions for the tom commands, long and short parameters, and also for some positional arguments like namespaces for the list command or commands for the help command.

tip

The tom integrate zsh command also accepts the --path= option with which you can set the location, where the zsh completion file should be created.

tip

You can also output the completion script using the --stdout option eg. tom integrate bash --stdout.

Alternative installation methods

This section describes alternative installation methods for bash and zsh tab completions.

Static installation

Idea is to output the tab completion to the file and then source it.

mkdir -p ~/.local/share/tom
tom integrate bash --stdout > ~/.local/share/tom/tom.bash

# Then source this file in the ~/.bashrc
source $HOME/.local/share/tom/tom.bash

Dynamic installation

Idea is to avoid outputting the tab completion to the file, so you eval the tab completion source code right away.

# Add this eval to the ~/.bashrc
eval "$(tom integrate bash --stdout)"

Migration Structure

A migration class contains two methods: up and down. The up method is used to add new tables, columns, or indexes to your database, while the down method should reverse the operations performed by the up method.

Within both of these methods, you may use the TinyORM schema builder to expressively create and modify tables. To learn about all of the methods available on the Schema builder, check out its documentation. For example, the following migration creates a posts table:

#pragma once

#include <tom/migration.hpp>

namespace Migrations
{

struct CreatePostsTable : Migration
{
/*! Filename of the migration file. */
T_MIGRATION

/*! Run the migrations. */
void up() const override
{
Schema::create("posts", [](Blueprint &table)
{
table.id();

table.string(NAME);
table.timestamps();
});
}

/*! Reverse the migrations. */
void down() const override
{
Schema::dropIfExists("posts");
}
};

} // namespace Migrations

Migration classes can be named in two formats, StudlyCase without the datetime prefix and "snake_case" with the datetime prefix. If the StudlyCase name is used then the T_MIGRATION macro must also be used in the migration class.

Naming with the datetime prefix should look like this.

struct _2014_10_12_000000_create_posts_table : Migration
{

/*! Run the migrations. */
void up() const override
{
//
}

/*! Reverse the migrations. */
void down() const override
{
//
}
};
tip

The StudlyCase naming is preferred. Also the make:migration command generates migrations in this format.

Setting The Migration Connection

If your migration will be interacting with a database connection other than your application's default database connection, you should set the connection data member of your migration:

/*! The name of the database connection to use. */
QString connection = QStringLiteral("tinyorm_example");

/*! Run the migrations. */
void up() const override
{
//
}

Running Migrations

To run all of your outstanding migrations, execute the migrate Tom command:

tom migrate

If you would like to see which migrations have run thus far, you may use the migrate:status tom command:

tom migrate:status

If you would like to see the SQL statements that will be executed by the migrations without actually running them, you may provide the --pretend flag to the migrate command:

tom migrate --pretend
tip

Many tom commands offer variety of options, you can explore them using the tom list and tom help commands. In most cases, these commands and options are self-explanatory.

tip

The tom command is able to guess the command name and command namespace, eg. tom mig:st or tom m:rol, ...

tip

You can pass the -vvv command-line argument to any command to see all executed SQL queries. 👌

note

The migrate Tom command internally calls the migrate:install command which installs the migration repository table. To uninstall this repository table you can call the migrate:uninstall.

Forcing Migrations To Run In Production

Some migration operations are destructive, which means they may cause you to lose data. In order to protect you from running these commands against your production database, you will be prompted for confirmation before the commands are executed. To force the commands to run without a prompt, use the --force flag:

tom migrate --force

Rolling Back Migrations

To roll back the latest migration operation, you may use the rollback Tom command. This command rolls back the last "batch" of migrations, which may include multiple migration files:

tom migrate:rollback

You may roll back a limited number of migrations by providing the step option to the rollback command. For example, the following command will roll back the last five migrations:

tom migrate:rollback --step=5

The migrate:reset command will roll back all of your application's migrations:

tom migrate:reset

You may roll back a specific "batch" of migrations by providing the batch option to the rollback command, where the batch option corresponds to a batch value within your application's migrations database table. For example, the following command will roll back all migrations in batch three:

tom migrate:rollback --batch=3

The migrate:reset command will roll back all of your application's migrations:

tom migrate:reset

The migrate:uninstall command will uninstall the migration repository table, it optionally accepts the --reset option to roll back all of your application's migrations:

tom migrate:uninstall --reset

Roll Back & Migrate Using A Single Command

The migrate:refresh command will roll back all of your migrations and then execute the migrate command. This command effectively re-creates your entire database:

tom migrate:refresh

You may roll back and re-migrate a limited number of migrations by providing the step option to the refresh command. For example, the following command will roll back and re-migrate the last five migrations:

tom migrate:refresh --step=5

Drop All Tables & Migrate

The migrate:fresh command will drop all tables from the database and then execute the migrate command:

tom migrate:fresh
caution

The migrate:fresh command will drop all database tables regardless of their prefix. This command should be used with caution when developing on a database that is shared with other applications.

Tables

Creating Tables

To create a new database table, use the create method on the Schema facade. The create method accepts two arguments: the first is the name of the table, while the second is a lambda expression which receives a Orm::SchemaNs::Blueprint object that may be used to define the new table:

#include <orm/schema.hpp>

using Orm::Schema;

Schema::create("users", [](Blueprint &table)
{
table.id();
table.string("name");
table.string("email");
table.timestamps();
});

When creating the table, you may use any of the schema builder's column methods to define the table's columns.

Checking For Table / Column Existence

You may check for the existence of a table or column using the hasTable and hasColumn methods:

if (Schema::hasTable("users")) {
// The "users" table exists...
}

if (Schema::hasColumn("users", "email")) {
// The "users" table exists and has an "email" column...
}

Database Connection & Table Options

If you want to perform a schema operation on a database connection that is not your application's default connection, use the connection method or on alias:

Schema::connection("postgres").create("users", [](Blueprint &table)
{
table.id();
});

In addition, a few other data members and methods may be used to define other aspects of the table's creation. The engine data member may be used to specify the table's storage engine when using MySQL:

#include <orm/constants.hpp>

using Orm::Constants::InnoDB;

Schema::create("users", [](Blueprint &table)
{
table.engine = InnoDB;

// ...
});

The charset and collation data members may be used to specify the character set and collation for the created table when using MySQL:

#include <orm/constants.hpp>

using Orm::Constants::UTF8MB4;

Schema::create("users", [](Blueprint &table)
{
table.charset = UTF8MB4;
table.collation = "utf8mb4_unicode_ci";

// ...
});

The temporary method may be used to indicate that the table should be "temporary". Temporary tables are only visible to the current connection's database session and are dropped automatically when the connection is closed:

Schema::create("calculations", [](Blueprint &table)
{
table.temporary();

// ...
});

If you would like to add a "comment" to a database table, you may invoke the comment method on the table instance. Table comments are currently only supported by MySQL and PostgreSQL:

Schema::create("calculations", [](Blueprint &table)
{
table.comment("Business calculations");

// ...
});

Updating Tables

The table method on the Schema facade may be used to update existing tables. Like the create method, the table method accepts two arguments: the name of the table and a lambda expression that receives a Blueprint instance you may use to add columns or indexes to the table:

#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.integer("votes");
});

Renaming / Dropping Tables

To rename an existing database table, use the rename method:

#include <orm/schema.hpp>

Schema::rename("from", "to");

To drop an existing table, you may use the drop or dropIfExists methods:

Schema::drop("users");

Schema::dropIfExists("users");

Renaming Tables With Foreign Keys

Before renaming a table, you should verify that any foreign key constraints on the table have an explicit name in your migration files instead of letting TinyORM assign a convention based name. Otherwise, the foreign key constraint index name will refer to the old table name.

tip

After renaming a table, you can re-create (drop and create again) the foreign key constraints to fix an index name, so it refers to a renamed table.

Columns

Creating Columns

The table method on the Schema facade may be used to update existing tables. Like the create method, the table method accepts two arguments: the name of the table and a lambda expression that receives a Blueprint instance you may use to add columns to the table:

#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.integer("votes");
});

Available Column Types

The schema builder blueprint offers a variety of methods that correspond to the different types of columns you can add to your database tables. Each of the available methods are listed in the table below:

bigIncrements +

Database: Migrations

+ +

Introduction

+

Migrations are like version control for your database, allowing your team to define and share the application's database schema definition. If you have ever had to tell a teammate to manually add a column to their local database schema after pulling in your changes from source control, you've faced the problem that database migrations solve.

+

The TinyORM Schema facade provides database agnostic support for creating and manipulating tables across all of TinyORM's supported database systems. Typically, migrations will use this facade to create and modify database tables and columns.

+

The tom migrations is a small console application that depends on the TinyORM library. All migrations logic is compiled so recompilation is needed after adding a new migration class.

+
warning
+
note

TinyORM's schema builder supports all supported databases out of the box.

+

The following image shows what the tom console application looks like. ✨ As you can see it offers everything that is needed to generate and manage migrations and seeders and all of this is backed up with the tab completion.

+TinyORM - Tom console application - Showcase +

Generating Migrations

+

You may use the make:migration tom command to generate a database migration. The new migration will be placed in your database/migrations directory. Each migration filename contains a timestamp that allows tom to determine the order of the migrations:

+
tom make:migration create_posts_table
+

tom will use the name of the migration to attempt to guess the name of the table and whether or not the migration will be creating a new table. If tom is able to determine the table name from the migration name, tom will pre-fill the generated migration file with the specified table. Otherwise, you may simply specify the table in the migration file manually.

+

If you would like to specify a custom path for the generated migration, you may use the --path option when executing the make:migration command. The given path should be relative to your pwd or you can use the --realpath option and pass the absolute path to the --path option.

+

Migrations naming rules

+

If the migration name starts with the create_ string then the stub for table creation will be used and if the migration name contains _(from|to|in)_ then the stub for table update will be used. You can override these rules using the --create and --table options and specify the table name manually.

+
tip

You can also pass the full migration filename with the datetime prefix and extension to the make:migration. This command is able to detect almost any combination of the passed value, with or without datetime prefix or extension if it is the filename; or StudlyCase, snake_case, or kebab-case if it is the classname or any combination described above. 👀

+

Tab completion

+

Tab completion is available for the pwsh (on Linux too), bash, and zsh shells. For pwsh the tom.exe and TinyOrm0.dll library must be on the system path to work properly. With bash if the tom executable and libTinyOrm.so library is not on the system path then it will provide less accurate completions.

+

You can enable it using the following commands.

+
tom integrate pwsh
+

Or you can enable it manually. Following actions are the same as the tom integrate command does.

+

For the pwsh paste the following code to the pwsh profile (works on Linux or Windows).

+
~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1
Register-ArgumentCompleter -Native -CommandName tom,tom_testdata -ScriptBlock {
Param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding =
[Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
$Local:word = $wordToComplete.Replace('"', '\"')
$Local:ast = $commandAst.ToString().Replace('"', '\"')
tom complete --word="$Local:word" --commandline="$Local:ast" --position=$cursorPosition
| ForEach-Object {
$completionText, $listText, $toolTip = $_ -split ';', 3
$listText ??= $completionText
$toolTip ??= $completionText
[System.Management.Automation.CompletionResult]::new(
$completionText, $listText, 'ParameterValue', $toolTip)
}
}
+

For bash you can copy or create symlink of the /tools/completions/tom.bash file to the /usr/share/bash-completion/completions folder.

+
sudo ln -s /TinyORM/tools/completions/tom.bash /usr/share/bash-completion/completions/tom
+

And for zsh you can copy or create symlink of the /tools/completions/tom.zsh file to the _tom file to /usr/local/share/zsh/site-functions folder.

+
sudo ln -s /TinyORM/tools/completions/tom.zsh /usr/local/share/zsh/site-functions/_tom
+

It will provide completions for the tom commands, long and short parameters, and also for some positional arguments like namespaces for the list command or commands for the help command.

+
tip

The tom integrate zsh command also accepts the --path= option with which you can set the location, where the zsh completion file should be created.

+
tip

You can also output the completion script using the --stdout option eg. tom integrate bash --stdout.

+

Alternative installation methods

+

This section describes alternative installation methods for bash and zsh tab completions.

+

Static installation

+

Idea is to output the tab completion to the file and then source it.

+
mkdir -p ~/.local/share/tom
tom integrate bash --stdout > ~/.local/share/tom/tom.bash

# Then source this file in the ~/.bashrc
source $HOME/.local/share/tom/tom.bash
+

Dynamic installation

+

Idea is to avoid outputting the tab completion to the file, so you eval the tab completion source code right away.

+
# Add this eval to the ~/.bashrc
eval "$(tom integrate bash --stdout)"
+

Migration Structure

+

A migration class contains two methods: up and down. The up method is used to add new tables, columns, or indexes to your database, while the down method should reverse the operations performed by the up method.

+

Within both of these methods, you may use the TinyORM schema builder to expressively create and modify tables. To learn about all of the methods available on the Schema builder, check out its documentation. For example, the following migration creates a posts table:

+
#pragma once

#include <tom/migration.hpp>

namespace Migrations
{

struct CreatePostsTable : Migration
{
/*! Filename of the migration file. */
T_MIGRATION

/*! Run the migrations. */
void up() const override
{
Schema::create("posts", [](Blueprint &table)
{
table.id();

table.string(NAME);
table.timestamps();
});
}

/*! Reverse the migrations. */
void down() const override
{
Schema::dropIfExists("posts");
}
};

} // namespace Migrations
+

Migration classes can be named in two formats, StudlyCase without the datetime prefix and "snake_case" with the datetime prefix. If the StudlyCase name is used then the T_MIGRATION macro must also be used in the migration class.

+

Naming with the datetime prefix should look like this.

+
struct _2014_10_12_000000_create_posts_table : Migration
{

/*! Run the migrations. */
void up() const override
{
//
}

/*! Reverse the migrations. */
void down() const override
{
//
}
};
+
tip

The StudlyCase naming is preferred. Also the make:migration command generates migrations in this format.

+

Setting The Migration Connection

+

If your migration will be interacting with a database connection other than your application's default database connection, you should set the connection data member of your migration:

+
/*! The name of the database connection to use. */
QString connection = QStringLiteral("tinyorm_example");

/*! Run the migrations. */
void up() const override
{
//
}
+

Running Migrations

+

To run all of your outstanding migrations, execute the migrate Tom command:

+
tom migrate
+

If you would like to see which migrations have run thus far, you may use the migrate:status tom command:

+
tom migrate:status
+

If you would like to see the SQL statements that will be executed by the migrations without actually running them, you may provide the --pretend flag to the migrate command:

+
tom migrate --pretend
+
tip

Many tom commands offer variety of options, you can explore them using the tom list and tom help commands. In most cases, these commands and options are self-explanatory.

+
tip

The tom command is able to guess the command name and command namespace, eg. tom mig:st or tom m:rol, ...

+
tip

You can pass the -vvv command-line argument to any command to see all executed SQL queries. 👌

+
note

The migrate Tom command internally calls the migrate:install command which installs the migration repository table. To uninstall this repository table you can call the migrate:uninstall.

+

Forcing Migrations To Run In Production

+

Some migration operations are destructive, which means they may cause you to lose data. In order to protect you from running these commands against your production database, you will be prompted for confirmation before the commands are executed. To force the commands to run without a prompt, use the --force flag:

+
tom migrate --force
+

Rolling Back Migrations

+

To roll back the latest migration operation, you may use the rollback Tom command. This command rolls back the last "batch" of migrations, which may include multiple migration files:

+
tom migrate:rollback
+

You may roll back a limited number of migrations by providing the step option to the rollback command. For example, the following command will roll back the last five migrations:

+
tom migrate:rollback --step=5
+

The migrate:reset command will roll back all of your application's migrations:

+
tom migrate:reset
+

You may roll back a specific "batch" of migrations by providing the batch option to the rollback command, where the batch option corresponds to a batch value within your application's migrations database table. For example, the following command will roll back all migrations in batch three:

+
tom migrate:rollback --batch=3
+

The migrate:reset command will roll back all of your application's migrations:

+
tom migrate:reset
+

The migrate:uninstall command will uninstall the migration repository table, it optionally accepts the --reset option to roll back all of your application's migrations:

+
tom migrate:uninstall --reset
+

Roll Back & Migrate Using A Single Command

+

The migrate:refresh command will roll back all of your migrations and then execute the migrate command. This command effectively re-creates your entire database:

+
tom migrate:refresh
+

You may roll back and re-migrate a limited number of migrations by providing the step option to the refresh command. For example, the following command will roll back and re-migrate the last five migrations:

+
tom migrate:refresh --step=5
+

Drop All Tables & Migrate

+

The migrate:fresh command will drop all tables from the database and then execute the migrate command:

+
tom migrate:fresh
+
warning

The migrate:fresh command will drop all database tables regardless of their prefix. This command should be used with caution when developing on a database that is shared with other applications.

+

Tables

+

Creating Tables

+

To create a new database table, use the create method on the Schema facade. The create method accepts two arguments: the first is the name of the table, while the second is a lambda expression which receives a Orm::SchemaNs::Blueprint object that may be used to define the new table:

+
#include <orm/schema.hpp>

using Orm::Schema;

Schema::create("users", [](Blueprint &table)
{
table.id();
table.string("name");
table.string("email");
table.timestamps();
});
+

When creating the table, you may use any of the schema builder's column methods to define the table's columns.

+

Checking For Table / Column Existence

+

You may check for the existence of a table or column using the hasTable and hasColumn methods:

+
if (Schema::hasTable("users")) {
// The "users" table exists...
}

if (Schema::hasColumn("users", "email")) {
// The "users" table exists and has an "email" column...
}
+

Database Connection & Table Options

+

If you want to perform a schema operation on a database connection that is not your application's default connection, use the connection method or on alias:

+
Schema::connection("postgres").create("users", [](Blueprint &table)
{
table.id();
});
+

In addition, a few other data members and methods may be used to define other aspects of the table's creation. The engine data member may be used to specify the table's storage engine when using MySQL:

+
#include <orm/constants.hpp>

using Orm::Constants::InnoDB;

Schema::create("users", [](Blueprint &table)
{
table.engine = InnoDB;

// ...
});
+

The charset and collation data members may be used to specify the character set and collation for the created table when using MySQL:

+
#include <orm/constants.hpp>

using Orm::Constants::UTF8MB4;

Schema::create("users", [](Blueprint &table)
{
table.charset = UTF8MB4;
table.collation = "utf8mb4_unicode_ci";

// ...
});
+

The temporary method may be used to indicate that the table should be "temporary". Temporary tables are only visible to the current connection's database session and are dropped automatically when the connection is closed:

+
Schema::create("calculations", [](Blueprint &table)
{
table.temporary();

// ...
});
+

If you would like to add a "comment" to a database table, you may invoke the comment method on the table instance. Table comments are currently only supported by MySQL and PostgreSQL:

+
Schema::create("calculations", [](Blueprint &table)
{
table.comment("Business calculations");

// ...
});
+

Updating Tables

+

The table method on the Schema facade may be used to update existing tables. Like the create method, the table method accepts two arguments: the name of the table and a lambda expression that receives a Blueprint instance you may use to add columns or indexes to the table:

+
#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.integer("votes");
});
+

Renaming / Dropping Tables

+

To rename an existing database table, use the rename method:

+
#include <orm/schema.hpp>

Schema::rename("from", "to");
+

To drop an existing table, you may use the drop or dropIfExists methods:

+
Schema::drop("users");

Schema::dropIfExists("users");
+

Renaming Tables With Foreign Keys

+

Before renaming a table, you should verify that any foreign key constraints on the table have an explicit name in your migration files instead of letting TinyORM assign a convention based name. Otherwise, the foreign key constraint index name will refer to the old table name.

+
tip

After renaming a table, you can re-create (drop and create again) the foreign key constraints to fix an index name, so it refers to a renamed table.

+

Columns

+

Creating Columns

+

The table method on the Schema facade may be used to update existing tables. Like the create method, the table method accepts two arguments: the name of the table and a lambda expression that receives a Blueprint instance you may use to add columns to the table:

+
#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.integer("votes");
});
+

Available Column Types

+

The schema builder blueprint offers a variety of methods that correspond to the different types of columns you can add to your database tables. Each of the available methods are listed in the table below:

+
info

Names of Char, Double, Enum, and Float column methods are in the CamelCase format to avoid collisions with C++ keywords.

bigIncrements()

The bigIncrements method creates an auto-incrementing UNSIGNED BIGINT (primary key) equivalent column:

#include <orm/constants.hpp>

table.bigIncrements(Orm::ID);

bigInteger()

The bigInteger method creates a BIGINT equivalent column:

table.bigInteger("votes");

binary()

The binary method creates a BLOB equivalent column:

table.binary("photo");

boolean()

The boolean method creates a BOOLEAN equivalent column:

table.boolean("confirmed");

Char()

The Char method creates a CHAR equivalent column with of a given length:

#include <orm/constants.hpp>

table.Char(Orm::NAME, 100);

date()

The date method creates a DATE equivalent column:

table.date("created_at");

datetime()

The datetime method creates a DATETIME equivalent column with an optional precision (total digits):

table.datetime("created_at", precision = 0);

datetimes()

The datetimes method creates created_at and updated_at DATETIME equivalent columns with an optional precision (total digits):

table.datetimes(precision = 0);

datetimeTz()

The datetimeTz method creates a DATETIME (with timezone) equivalent column with an optional precision (total digits):

#include <orm/constants.hpp>

table.datetimeTz(Orm::CREATED_AT, precision = 0);

decimal()

The decimal method creates a DECIMAL equivalent column with the given precision (total digits) and scale (decimal digits):

table.decimal("amount", precision = 8, scale = 2);

Double()

The Double method creates a DOUBLE equivalent column with the given precision (total digits) and scale (decimal digits):

table.Double("amount", 8, 2);

Enum()

The Enum method creates a ENUM equivalent column with the given valid values:

table.Enum("difficulty", {"easy", "hard"});

Float()

The Float method creates a FLOAT equivalent column with the given precision (total digits) and scale (decimal digits):

table.Float("amount", 8, 2);

foreignId()

The foreignId method creates an UNSIGNED BIGINT equivalent column:

table.foreignId("user_id");

foreignIdFor()

The foreignIdFor method adds a {column}_id UNSIGNED BIGINT equivalent column for a given model class:

#include "models/user.hpp"

Models::User user;

table.foreignIdFor(User);

foreignUuid()

The foreignUuid method creates a UUID equivalent column:

table.foreignUuid("user_id");

geometry()

The geometry method creates a GEOMETRY equivalent column:

table.geometry("positions");

geometryCollection()

The geometryCollection method creates a GEOMETRYCOLLECTION equivalent column:

table.geometryCollection("positions");

id()

The id method is an alias of the bigIncrements method. By default, the method will create an id column; however, you may pass a column name if you would like to assign a different name to the column:

table.id();

increments()

The increments method creates an auto-incrementing UNSIGNED INTEGER equivalent column as a primary key:

table.increments("id");

integer()

The integer method creates an INTEGER equivalent column:

table.integer("votes");

ipAddress()

The ipAddress method creates a VARCHAR(45) equivalent column:

table.ipAddress("visitor");

json()

The json method creates a JSON equivalent column:

table.json("options");

jsonb()

The jsonb method creates a JSONB equivalent column:

table.jsonb("options");

lineString()

The lineString method creates a LINESTRING equivalent column:

table.lineString("positions");

longBinary()

The longBinary method creates a LONGBLOB equivalent column:

table.longBinary("photo");

longText()

The longText method creates a LONGTEXT equivalent column:

table.longText("description");

macAddress()

The macAddress method creates a column that is intended to hold a MAC address. Some database systems, such as PostgreSQL, have a dedicated column type for this type of data. Other database systems will use a string equivalent VARCHAR(17) column:

table.macAddress("device");

mediumBinary()

The mediumBinary method creates a MEDIUMBLOB equivalent column:

table.mediumBinary("photo");

mediumIncrements()

The mediumIncrements method creates an auto-incrementing UNSIGNED MEDIUMINT equivalent column as a primary key:

table.mediumIncrements("id");

mediumInteger()

The mediumInteger method creates a MEDIUMINT equivalent column:

table.mediumInteger("votes");

mediumText()

The mediumText method creates a MEDIUMTEXT equivalent column:

table.mediumText("description");

multiLineString()

The multiLineString method creates a MULTILINESTRING equivalent column:

table.multiLineString("positions");

multiPoint()

The multiPoint method creates a MULTIPOINT equivalent column:

table.multiPoint("positions");

multiPolygon()

The multiPolygon method creates a MULTIPOLYGON equivalent column:

table.multiPolygon("positions");

point()

The point method creates a POINT equivalent column:

table.point("position");

polygon()

The polygon method creates a POLYGON equivalent column:

table.polygon("position");

rememberToken()

The rememberToken method creates a nullable, VARCHAR(100) equivalent column that is intended to store the current "remember me" authentication token:

table.rememberToken();

set()

The set method creates a SET equivalent column with the given list of valid values:

table.set("flavors", {"strawberry", "vanilla"});

smallIncrements()

The smallIncrements method creates an auto-incrementing UNSIGNED SMALLINT equivalent column as a primary key:

table.smallIncrements("id");

smallInteger()

The smallInteger method creates a SMALLINT equivalent column:

table.smallInteger("votes");

softDeletes()

The softDeletes method adds a nullable deleted_at TIMESTAMP equivalent column with an optional precision (total digits). This column is intended to store the deleted_at timestamp needed for TinyORM's "soft delete" functionality:

table.softDeletes("deleted_at", precision = 0);

softDeletesDatetime()

The softDeletesDatetime method adds a nullable deleted_at DATETIME equivalent column with an optional precision (total digits). This column is intended to store the deleted_at timestamp needed for TinyORM's "soft delete" functionality:

table.softDeletesDatetime("deleted_at", precision = 0);

softDeletesTz()

The softDeletesTz method adds a nullable deleted_at TIMESTAMP (with timezone) equivalent column with an optional precision (total digits). This column is intended to store the deleted_at timestamp needed for TinyORM's "soft delete" functionality:

table.softDeletesTz("deleted_at", precision = 0);

string()

The string method creates a VARCHAR equivalent column of the given length:

#include <orm/constants.hpp>

table.string(Orm::NAME, 100);

text()

The text method creates a TEXT equivalent column:

table.text("description");

time()

The time method creates a TIME equivalent column with an optional precision (total digits):

table.time("sunrise", precision = 0);

timeTz()

The timeTz method creates a TIME (with timezone) equivalent column with an optional precision (total digits):

table.timeTz("sunrise", precision = 0);

timestamp()

The timestamp method creates a TIMESTAMP equivalent column with an optional precision (total digits):

table.timestamp("added_at", precision = 0);

timestampTz()

The timestampTz method creates a TIMESTAMP (with timezone) equivalent column with an optional precision (total digits):

table.timestampTz("added_at", precision = 0);

timestampsTz()

The timestampsTz method creates created_at and updated_at TIMESTAMP (with timezone) equivalent columns with an optional precision (total digits):

table.timestampsTz(precision = 0);

timestamps()

The timestamps method creates created_at and updated_at TIMESTAMP equivalent columns with an optional precision (total digits):

table.timestamps(precision = 0);

tinyBinary()

The tinyBinary method creates a TINYBLOB equivalent column:

table.tinyBinary("photo");

tinyIncrements()

The tinyIncrements method creates an auto-incrementing UNSIGNED TINYINT equivalent column as a primary key:

table.tinyIncrements("id");

tinyInteger()

The tinyInteger method creates a TINYINT equivalent column:

table.tinyInteger("votes");

tinyText()

The tinyText method creates a TINYTEXT equivalent column:

table.tinyText("notes");

unsignedBigInteger()

The unsignedBigInteger method creates an UNSIGNED BIGINT equivalent column:

table.unsignedBigInteger("votes");

unsignedDecimal()

The unsignedDecimal method creates an UNSIGNED DECIMAL equivalent column with an optional precision (total digits) and scale (decimal digits):

table.unsignedDecimal("amount", precision = 8, scale = 2);

unsignedInteger()

The unsignedInteger method creates an UNSIGNED INTEGER equivalent column:

table.unsignedInteger("votes");

unsignedMediumInteger()

The unsignedMediumInteger method creates an UNSIGNED MEDIUMINT equivalent column:

table.unsignedMediumInteger("votes");

unsignedSmallInteger()

The unsignedSmallInteger method creates an UNSIGNED SMALLINT equivalent column:

table.unsignedSmallInteger("votes");

unsignedTinyInteger()

The unsignedTinyInteger method creates an UNSIGNED TINYINT equivalent column:

table.unsignedTinyInteger("votes");

uuid()

The uuid method creates a UUID equivalent column:

table.uuid("id");

year()

The year method creates a YEAR equivalent column:

table.year("birth_year");

Column Modifiers

In addition to the column types listed above, there are several column "modifiers" you may use when adding a column to a database table. For example, to make the column "nullable", you may use the nullable method:

#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.string("email").nullable();
});

The following table contains all of the available column modifiers. This list does not include index modifiers:

ModifierDescription
.after("column")Place the column "after" another column (MySQL).
.autoIncrement()Set INTEGER columns as auto-incrementing (primary key).
.charset("utf8mb4")Specify a character set for the column (MySQL).
.collation("utf8mb4_unicode_ci")Specify a collation for the column (MySQL/PostgreSQL/SQL Server).
.comment("my comment")Add a comment to a column (MySQL / PostgreSQL).
Special characters are escaped.
.defaultValue(value)Specify a "default" value for the column.
Special characters are escaped.
.first()Place the column "first" in the table (MySQL).
.from(integer)Set the starting value of an auto-incrementing field, an alias for startingValue() (MySQL / PostgreSQL).
.invisible()Make the column "invisible" to SELECT * queries (MySQL).
.nullable(value = true)Allow NULL values to be inserted into the column.
.startingValue(integer)Set the starting value of an auto-incrementing field (MySQL / PostgreSQL).
.storedAs(expression)Create a stored generated column (MySQL / PostgreSQL).
.unsigned()Set INTEGER columns as UNSIGNED (MySQL).
.useCurrent()Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value.
.useCurrentOnUpdate()Set TIMESTAMP columns to use CURRENT_TIMESTAMP when a record is updated.
.virtualAs(expression)Create a virtual generated column (MySQL).
.generatedAs(expression)Create an identity column with specified sequence options (PostgreSQL).
.always()Defines the precedence of sequence values over input for an identity column (PostgreSQL).
.isGeometry()Set spatial column type to geometry - the default type is geography (PostgreSQL).

Default Expressions

The defaultValue modifier accepts a value or an Orm::Query::Expression instance. Using an Expression instance will prevent TinyORM from wrapping the value in quotes and allow you to use database-specific functions. One situation where this is particularly useful is when you need to assign default values to JSON columns:

#include <orm/schema.hpp>

using Orm::Query::Expression;

Schema::create("flights", [](Blueprint &table)
{
table.id();
table.json("detail").defaultValue(Expression("(JSON_ARRAY('none'))"));
table.timestamps();
});
note

Support for default expressions depends on your database driver, database version, and the field type. Please refer to your database's documentation.

tip

You can obtain an Orm::Query::Expression using the DB::raw method if you have access to the DB facade.

Column Order

When using the MySQL database, the after method may be used to add columns after an existing column in the schema:

table.after("password", [](Blueprint &table)
{
table.string("address_line1");
table.string("address_line2");
table.string("city");
});

Modifying Columns

The change method allows you to modify the type and attributes of existing columns. For example, you may wish to increase the size of a string column. To see the change method in action, let's increase the size of the name column from 25 to 50. To accomplish this, we simply define the new state of the column and then call the change method:

#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.string("name", 50).change();
});

When modifying a column, you must explicitly include all of the modifiers you want to keep on the column definition - any missing attribute will be dropped. For example, to retain the unsigned, default, and comment attributes, you must call each modifier explicitly when changing the column:

Schema::table("users", [](Blueprint &table)
{
table.integer("votes").isUnsigned().defaultValue(1).comment("my comment").change();
});
info

The change method and modifying columns is not implemented for the SQLite database because it doesn't support modifying columns out of the box.

Renaming Columns

To rename a column, you may use the renameColumn method provided by the schema builder blueprint:

Schema::table("users", [](Blueprint &table)
{
table.renameColumn("from", "to");
});

Renaming Columns On Legacy Databases

Renaming columns is not supported if you are running a database installation older than one of the following releases:

  • MySQL <8.0.3
  • MariaDB <10.5.2
  • SQLite <3.25.0

Dropping Columns

To drop a column, you may use the dropColumn method on the schema builder blueprint:

Schema::table("users", [](Blueprint &table)
{
table.dropColumn("votes");
});

You may drop multiple columns from a table by passing a QVector<QString> of column names to the dropColumns method, the dropColumns method also provides parameter pack overload:

Schema::table("users", [](Blueprint &table)
{
table.dropColumns({"votes", "avatar", "location"});
// Parameter pack overload
table.dropColumns("votes", "avatar", "location");
});
caution

The SQLite prior to v3.35.0 doesn't support dropping columns using the ALTER TABLE DROP COLUMN, dropping columns was added in the SQLite v3.35.0 as is described in the release notes.

Available Command Aliases

TinyORM provides several convenient methods related to dropping common types of columns. Each of these methods is described in the table below:

CommandDescription
table.dropRememberToken();Drop the remember_token column.
table.dropSoftDeletes();Drop the deleted_at column.
table.dropSoftDeletesDatetime();Alias of dropSoftDeletes() method.
table.dropSoftDeletesTz();Alias of dropSoftDeletes() method.
table.dropTimestamps();Drop the created_at and updated_at columns.
table.dropTimestampsTz();Alias of dropTimestamps() method.
table.dropDatetimes();Alias of dropTimestamps() method.

Indexes

Creating Indexes

The TinyORM schema builder supports several types of indexes. The following example creates a new email column and specifies that its values should be unique. To create the index, we can chain the unique method onto the column definition:

#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.string("email").unique();
});

Alternatively, you may create the index after defining the column. To do so, you should call the unique method on the schema builder blueprint. This method accepts the name of the column that should receive a unique index:

table.unique("email");

You may even pass a QVector<QString> of columns to an index method to create a compound (or composite) index:

table.index({"account_id", "created_at"});

When creating an index, TinyORM will automatically generate an index name based on the table, column names, and the index type (eg. users_email_unique), but you may pass a second argument to the method to specify the index name yourself:

table.unique("email", "unique_email");

Available Index Types

TinyORM's schema builder blueprint class provides methods for creating each type of index supported by TinyORM. Each index method accepts an optional second argument to specify the name of the index. If omitted, the name will be derived from the names of the table and column(s) used for the index, as well as the index type (eg. users_email_fulltext). Each of the available index methods is described in the table below:

CommandDescription
table.primary("id");Adds a primary key.
table.primary({"id", "parent_id"});Adds composite keys.
table.unique("email");Adds a unique index.
table.index("state");Adds an index.
table.fullText("body");Adds a full text index (MySQL/PostgreSQL).
table.fullText("body").language("english");Adds a full text index of the specified language (PostgreSQL).
table.spatialIndex("location");Adds a spatial index (except SQLite).

Index Lengths & MySQL / MariaDB

By default, TinyORM uses the utf8mb4 character set. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure the default string length by calling the Schema::defaultStringLength method:

#include <orm/schema.hpp>

Schema::defaultStringLength(191);
tip

Alternatively, you may enable the innodb_large_prefix option for your database (enabled by default in >=MySQL 5.7.7). Refer to your database's documentation for instructions on how to properly enable this option.

Renaming Indexes

To rename an index, you may use the renameIndex method provided by the schema builder blueprint. This method accepts the current index name as its first argument and the desired name as its second argument:

table.renameIndex("from", "to");

Dropping Indexes

To drop an index, you must specify the index's name. By default, TinyORM automatically assigns an index name based on the table name, the name of the indexed column, and the index type (eg. users_email_unique). Here are some examples:

CommandDescription
table.dropPrimary("users_id_primary");Drop a primary key from the "users" table.
table.dropUnique("users_email_unique");Drop a unique index from the "users" table.
table.dropIndex("geo_state_index");Drop a basic index from the "geo" table.
table.dropFullText("posts_body_fulltext");Drop a full text index from the "posts" table.
.dropSpatialIndex("geo_location_spatialindex");Drop a spatial index from the "geo" table (except SQLite).

I may also drop indexes by a column name or column names for composite keys, if you pass a QVector<QString> of columns into a method that drops indexes, the conventional index name will be generated based on the table name, columns, and index type:

Schema::table("geo", [](Blueprint &table)
{
table.dropIndex({"state"}); // Drops index 'geo_state_index'
});

Foreign Key Constraints

TinyORM also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a user_id column on the posts table that references the id column on a users table:

#include <orm/schema.hpp>

using Orm::Constants::ID;

Schema::table("posts", [](Blueprint &table)
{
table.unsignedBigInteger("user_id");

table.foreign("user_id").references(ID).on("users");
});

Since this syntax is rather verbose, TinyORM provides additional, terser methods that use conventions to provide a better developer experience. When using the foreignId method to create your column, the example above can be rewritten like so:

Schema::table("posts", [](Blueprint &table)
{
table.foreignId("user_id").constrained();
});

The foreignId method creates an UNSIGNED BIGINT equivalent column, while the constrained method will use conventions to determine the table and column name being referenced. If your table name does not match TinyORM's conventions, you may specify the table name by passing it as an argument to the constrained method:

Schema::table("posts", [](Blueprint &table)
{
table.foreignId("user_id").constrained("users");
});

You may also specify the desired action for the "on delete" and "on update" properties of the constraint:

#include <orm/constants.hpp>

using Orm::SchemaNs::Constants::Cascade;

table.foreignId("user_id")
.constrained()
.onUpdate("cascade")
.onDelete(Cascade);

An alternative, expressive syntax is also provided for these actions:

MethodDescription
table.cascadeOnUpdate();Updates should cascade.
table.restrictOnUpdate();Updates should be restricted.
table.cascadeOnDelete();Deletes should cascade.
table.restrictOnDelete();Deletes should be restricted.
table.nullOnDelete();Deletes should set the foreign key value to null.

Any additional column modifiers must be called before the constrained method:

table.foreignId("user_id")
.nullable()
.constrained();

Dropping Foreign Keys

To drop a foreign key, you may use the dropForeign method, passing the name of the foreign key constraint to be deleted as an argument. Foreign key constraints use the same naming convention as indexes. In other words, the foreign key constraint name is based on the name of the table and the columns in the constraint, followed by a "_foreign" suffix:

table.dropForeign("posts_user_id_foreign");

Alternatively, you may pass a QVector<QString> containing the column name that holds the foreign key to the dropForeign method. The QVector will be converted to a foreign key constraint name using TinyORM's constraint naming conventions:

table.dropForeign({"user_id"});

Toggling Foreign Key Constraints

You may enable or disable foreign key constraints within your migrations by using the following methods:

Schema::enableForeignKeyConstraints();

Schema::disableForeignKeyConstraints();

Schema::withoutForeignKeyConstraints([]
{
// Constraints disabled within this lambda expression...
});
caution

The SQLite disables foreign key constraints by default. When using SQLite, make sure to enable foreign key support in your database configuration before attempting to create them in your migrations. In addition, SQLite only supports creating foreign keys when creating tables and not when tables are altered.

- - +year

+
info

Names of Char, Double, Enum, and Float column methods are in the CamelCase format to avoid collisions with C++ keywords.

+

bigIncrements()

The bigIncrements method creates an auto-incrementing UNSIGNED BIGINT (primary key) equivalent column:

#include <orm/constants.hpp>

table.bigIncrements(Orm::ID);

bigInteger()

The bigInteger method creates a BIGINT equivalent column:

table.bigInteger("votes");

binary()

The binary method creates a BLOB equivalent column:

table.binary("photo");

boolean()

The boolean method creates a BOOLEAN equivalent column:

table.boolean("confirmed");

Char()

The Char method creates a CHAR equivalent column with of a given length:

#include <orm/constants.hpp>

table.Char(Orm::NAME, 100);

date()

The date method creates a DATE equivalent column:

table.date("created_at");

datetime()

The datetime method creates a DATETIME equivalent column with an optional precision (total digits):

table.datetime("created_at", precision = 0);

datetimes()

The datetimes method creates created_at and updated_at DATETIME equivalent columns with an optional precision (total digits):

table.datetimes(precision = 0);

datetimeTz()

The datetimeTz method creates a DATETIME (with timezone) equivalent column with an optional precision (total digits):

#include <orm/constants.hpp>

table.datetimeTz(Orm::CREATED_AT, precision = 0);

decimal()

The decimal method creates a DECIMAL equivalent column with the given precision (total digits) and scale (decimal digits):

table.decimal("amount", precision = 8, scale = 2);

Double()

The Double method creates a DOUBLE equivalent column with the given precision (total digits) and scale (decimal digits):

table.Double("amount", 8, 2);

Enum()

The Enum method creates a ENUM equivalent column with the given valid values:

table.Enum("difficulty", {"easy", "hard"});

Float()

The Float method creates a FLOAT equivalent column with the given precision (total digits) and scale (decimal digits):

table.Float("amount", 8, 2);

foreignId()

The foreignId method creates an UNSIGNED BIGINT equivalent column:

table.foreignId("user_id");

foreignIdFor()

The foreignIdFor method adds a {column}_id UNSIGNED BIGINT equivalent column for a given model class:

#include "models/user.hpp"

Models::User user;

table.foreignIdFor(User);

foreignUuid()

The foreignUuid method creates a UUID equivalent column:

table.foreignUuid("user_id");

geometry()

The geometry method creates a GEOMETRY equivalent column:

table.geometry("positions");

geometryCollection()

The geometryCollection method creates a GEOMETRYCOLLECTION equivalent column:

table.geometryCollection("positions");

id()

The id method is an alias of the bigIncrements method. By default, the method will create an id column; however, you may pass a column name if you would like to assign a different name to the column:

table.id();

increments()

The increments method creates an auto-incrementing UNSIGNED INTEGER equivalent column as a primary key:

table.increments("id");

integer()

The integer method creates an INTEGER equivalent column:

table.integer("votes");

ipAddress()

The ipAddress method creates a VARCHAR(45) equivalent column:

table.ipAddress("visitor");

json()

The json method creates a JSON equivalent column:

table.json("options");

jsonb()

The jsonb method creates a JSONB equivalent column:

table.jsonb("options");

lineString()

The lineString method creates a LINESTRING equivalent column:

table.lineString("positions");

longBinary()

The longBinary method creates a LONGBLOB equivalent column:

table.longBinary("photo");

longText()

The longText method creates a LONGTEXT equivalent column:

table.longText("description");

macAddress()

The macAddress method creates a column that is intended to hold a MAC address. Some database systems, such as PostgreSQL, have a dedicated column type for this type of data. Other database systems will use a string equivalent VARCHAR(17) column:

table.macAddress("device");

mediumBinary()

The mediumBinary method creates a MEDIUMBLOB equivalent column:

table.mediumBinary("photo");

mediumIncrements()

The mediumIncrements method creates an auto-incrementing UNSIGNED MEDIUMINT equivalent column as a primary key:

table.mediumIncrements("id");

mediumInteger()

The mediumInteger method creates a MEDIUMINT equivalent column:

table.mediumInteger("votes");

mediumText()

The mediumText method creates a MEDIUMTEXT equivalent column:

table.mediumText("description");

multiLineString()

The multiLineString method creates a MULTILINESTRING equivalent column:

table.multiLineString("positions");

multiPoint()

The multiPoint method creates a MULTIPOINT equivalent column:

table.multiPoint("positions");

multiPolygon()

The multiPolygon method creates a MULTIPOLYGON equivalent column:

table.multiPolygon("positions");

point()

The point method creates a POINT equivalent column:

table.point("position");

polygon()

The polygon method creates a POLYGON equivalent column:

table.polygon("position");

rememberToken()

The rememberToken method creates a nullable, VARCHAR(100) equivalent column that is intended to store the current "remember me" authentication token:

table.rememberToken();

set()

The set method creates a SET equivalent column with the given list of valid values:

table.set("flavors", {"strawberry", "vanilla"});

smallIncrements()

The smallIncrements method creates an auto-incrementing UNSIGNED SMALLINT equivalent column as a primary key:

table.smallIncrements("id");

smallInteger()

The smallInteger method creates a SMALLINT equivalent column:

table.smallInteger("votes");

softDeletes()

The softDeletes method adds a nullable deleted_at TIMESTAMP equivalent column with an optional precision (total digits). This column is intended to store the deleted_at timestamp needed for TinyORM's "soft delete" functionality:

table.softDeletes("deleted_at", precision = 0);

softDeletesDatetime()

The softDeletesDatetime method adds a nullable deleted_at DATETIME equivalent column with an optional precision (total digits). This column is intended to store the deleted_at timestamp needed for TinyORM's "soft delete" functionality:

table.softDeletesDatetime("deleted_at", precision = 0);

softDeletesTz()

The softDeletesTz method adds a nullable deleted_at TIMESTAMP (with timezone) equivalent column with an optional precision (total digits). This column is intended to store the deleted_at timestamp needed for TinyORM's "soft delete" functionality:

table.softDeletesTz("deleted_at", precision = 0);

string()

The string method creates a VARCHAR equivalent column of the given length:

#include <orm/constants.hpp>

table.string(Orm::NAME, 100);

text()

The text method creates a TEXT equivalent column:

table.text("description");

time()

The time method creates a TIME equivalent column with an optional precision (total digits):

table.time("sunrise", precision = 0);

timeTz()

The timeTz method creates a TIME (with timezone) equivalent column with an optional precision (total digits):

table.timeTz("sunrise", precision = 0);

timestamp()

The timestamp method creates a TIMESTAMP equivalent column with an optional precision (total digits):

table.timestamp("added_at", precision = 0);

timestampTz()

The timestampTz method creates a TIMESTAMP (with timezone) equivalent column with an optional precision (total digits):

table.timestampTz("added_at", precision = 0);

timestampsTz()

The timestampsTz method creates created_at and updated_at TIMESTAMP (with timezone) equivalent columns with an optional precision (total digits):

table.timestampsTz(precision = 0);

timestamps()

The timestamps method creates created_at and updated_at TIMESTAMP equivalent columns with an optional precision (total digits):

table.timestamps(precision = 0);

tinyBinary()

The tinyBinary method creates a TINYBLOB equivalent column:

table.tinyBinary("photo");

tinyIncrements()

The tinyIncrements method creates an auto-incrementing UNSIGNED TINYINT equivalent column as a primary key:

table.tinyIncrements("id");

tinyInteger()

The tinyInteger method creates a TINYINT equivalent column:

table.tinyInteger("votes");

tinyText()

The tinyText method creates a TINYTEXT equivalent column:

table.tinyText("notes");

unsignedBigInteger()

The unsignedBigInteger method creates an UNSIGNED BIGINT equivalent column:

table.unsignedBigInteger("votes");

unsignedDecimal()

The unsignedDecimal method creates an UNSIGNED DECIMAL equivalent column with an optional precision (total digits) and scale (decimal digits):

table.unsignedDecimal("amount", precision = 8, scale = 2);

unsignedInteger()

The unsignedInteger method creates an UNSIGNED INTEGER equivalent column:

table.unsignedInteger("votes");

unsignedMediumInteger()

The unsignedMediumInteger method creates an UNSIGNED MEDIUMINT equivalent column:

table.unsignedMediumInteger("votes");

unsignedSmallInteger()

The unsignedSmallInteger method creates an UNSIGNED SMALLINT equivalent column:

table.unsignedSmallInteger("votes");

unsignedTinyInteger()

The unsignedTinyInteger method creates an UNSIGNED TINYINT equivalent column:

table.unsignedTinyInteger("votes");

uuid()

The uuid method creates a UUID equivalent column:

table.uuid("id");

year()

The year method creates a YEAR equivalent column:

table.year("birth_year");
+

Column Modifiers

+

In addition to the column types listed above, there are several column "modifiers" you may use when adding a column to a database table. For example, to make the column "nullable", you may use the nullable method:

+
#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.string("email").nullable();
});
+

The following table contains all of the available column modifiers. This list does not include index modifiers:

+
ModifierDescription
.after("column")Place the column "after" another column (MySQL).
.autoIncrement()Set INTEGER columns as auto-incrementing (primary key).
.charset("utf8mb4")Specify a character set for the column (MySQL).
.collation("utf8mb4_unicode_ci")Specify a collation for the column (MySQL/PostgreSQL/SQL Server).
.comment("my comment")Add a comment to a column (MySQL / PostgreSQL).
Special characters are escaped.
.defaultValue(value)Specify a "default" value for the column.
Special characters are escaped.
.first()Place the column "first" in the table (MySQL).
.from(integer)Set the starting value of an auto-incrementing field, an alias for startingValue() (MySQL / PostgreSQL).
.invisible()Make the column "invisible" to SELECT * queries (MySQL).
.nullable(value = true)Allow NULL values to be inserted into the column.
.startingValue(integer)Set the starting value of an auto-incrementing field (MySQL / PostgreSQL).
.storedAs(expression)Create a stored generated column (MySQL / PostgreSQL).
.unsigned()Set INTEGER columns as UNSIGNED (MySQL).
.useCurrent()Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value.
.useCurrentOnUpdate()Set TIMESTAMP columns to use CURRENT_TIMESTAMP when a record is updated.
.virtualAs(expression)Create a virtual generated column (MySQL).
.generatedAs(expression)Create an identity column with specified sequence options (PostgreSQL).
.always()Defines the precedence of sequence values over input for an identity column (PostgreSQL).
.isGeometry()Set spatial column type to geometry - the default type is geography (PostgreSQL).
+

Default Expressions

+

The defaultValue modifier accepts a value or an Orm::Query::Expression instance. Using an Expression instance will prevent TinyORM from wrapping the value in quotes and allow you to use database-specific functions. One situation where this is particularly useful is when you need to assign default values to JSON columns:

+
#include <orm/schema.hpp>

using Orm::Query::Expression;

Schema::create("flights", [](Blueprint &table)
{
table.id();
table.json("detail").defaultValue(Expression("(JSON_ARRAY('none'))"));
table.timestamps();
});
+
note

Support for default expressions depends on your database driver, database version, and the field type. Please refer to your database's documentation.

+
tip

You can obtain an Orm::Query::Expression using the DB::raw method if you have access to the DB facade.

+

Column Order

+

When using the MySQL database, the after method may be used to add columns after an existing column in the schema:

+
table.after("password", [](Blueprint &table)
{
table.string("address_line1");
table.string("address_line2");
table.string("city");
});
+

Modifying Columns

+

The change method allows you to modify the type and attributes of existing columns. For example, you may wish to increase the size of a string column. To see the change method in action, let's increase the size of the name column from 25 to 50. To accomplish this, we simply define the new state of the column and then call the change method:

+
#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.string("name", 50).change();
});
+

When modifying a column, you must explicitly include all of the modifiers you want to keep on the column definition - any missing attribute will be dropped. For example, to retain the unsigned, default, and comment attributes, you must call each modifier explicitly when changing the column:

+
Schema::table("users", [](Blueprint &table)
{
table.integer("votes").isUnsigned().defaultValue(1).comment("my comment").change();
});
+
info

The change method and modifying columns is not implemented for the SQLite database because it doesn't support modifying columns out of the box.

+

Renaming Columns

+

To rename a column, you may use the renameColumn method provided by the schema builder blueprint:

+
Schema::table("users", [](Blueprint &table)
{
table.renameColumn("from", "to");
});
+

Renaming Columns On Legacy Databases

+

Renaming columns is not supported if you are running a database installation older than one of the following releases:

+
    +
  • MySQL <8.0.3
  • +
  • MariaDB <10.5.2
  • +
  • SQLite <3.25.0
  • +
+

Dropping Columns

+

To drop a column, you may use the dropColumn method on the schema builder blueprint:

+
Schema::table("users", [](Blueprint &table)
{
table.dropColumn("votes");
});
+

You may drop multiple columns from a table by passing a QVector<QString> of column names to the dropColumns method, the dropColumns method also provides parameter pack overload:

+
Schema::table("users", [](Blueprint &table)
{
table.dropColumns({"votes", "avatar", "location"});
// Parameter pack overload
table.dropColumns("votes", "avatar", "location");
});
+
warning

The SQLite prior to v3.35.0 doesn't support dropping columns using the ALTER TABLE DROP COLUMN, dropping columns was added in the SQLite v3.35.0 as is described in the release notes.

+

Available Command Aliases

+

TinyORM provides several convenient methods related to dropping common types of columns. Each of these methods is described in the table below:

+
CommandDescription
table.dropRememberToken();Drop the remember_token column.
table.dropSoftDeletes();Drop the deleted_at column.
table.dropSoftDeletesDatetime();Alias of dropSoftDeletes() method.
table.dropSoftDeletesTz();Alias of dropSoftDeletes() method.
table.dropTimestamps();Drop the created_at and updated_at columns.
table.dropTimestampsTz();Alias of dropTimestamps() method.
table.dropDatetimes();Alias of dropTimestamps() method.
+

Indexes

+

Creating Indexes

+

The TinyORM schema builder supports several types of indexes. The following example creates a new email column and specifies that its values should be unique. To create the index, we can chain the unique method onto the column definition:

+
#include <orm/schema.hpp>

Schema::table("users", [](Blueprint &table)
{
table.string("email").unique();
});
+

Alternatively, you may create the index after defining the column. To do so, you should call the unique method on the schema builder blueprint. This method accepts the name of the column that should receive a unique index:

+
table.unique("email");
+

You may even pass a QVector<QString> of columns to an index method to create a compound (or composite) index:

+
table.index({"account_id", "created_at"});
+

When creating an index, TinyORM will automatically generate an index name based on the table, column names, and the index type (eg. users_email_unique), but you may pass a second argument to the method to specify the index name yourself:

+
table.unique("email", "unique_email");
+

Available Index Types

+

TinyORM's schema builder blueprint class provides methods for creating each type of index supported by TinyORM. Each index method accepts an optional second argument to specify the name of the index. If omitted, the name will be derived from the names of the table and column(s) used for the index, as well as the index type (eg. users_email_fulltext). Each of the available index methods is described in the table below:

+
CommandDescription
table.primary("id");Adds a primary key.
table.primary({"id", "parent_id"});Adds composite keys.
table.unique("email");Adds a unique index.
table.index("state");Adds an index.
table.fullText("body");Adds a full text index (MySQL/PostgreSQL).
table.fullText("body").language("english");Adds a full text index of the specified language (PostgreSQL).
table.spatialIndex("location");Adds a spatial index (except SQLite).
+

Index Lengths & MySQL / MariaDB

+

By default, TinyORM uses the utf8mb4 character set. If you are running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations in order for MySQL to create indexes for them. You may configure the default string length by calling the Schema::defaultStringLength method:

+
#include <orm/schema.hpp>

Schema::defaultStringLength(191);
+
tip

Alternatively, you may enable the innodb_large_prefix option for your database (enabled by default in >=MySQL 5.7.7). Refer to your database's documentation for instructions on how to properly enable this option.

+

Renaming Indexes

+

To rename an index, you may use the renameIndex method provided by the schema builder blueprint. This method accepts the current index name as its first argument and the desired name as its second argument:

+
table.renameIndex("from", "to");
+

Dropping Indexes

+

To drop an index, you must specify the index's name. By default, TinyORM automatically assigns an index name based on the table name, the name of the indexed column, and the index type (eg. users_email_unique). Here are some examples:

+
CommandDescription
table.dropPrimary("users_id_primary");Drop a primary key from the "users" table.
table.dropUnique("users_email_unique");Drop a unique index from the "users" table.
table.dropIndex("geo_state_index");Drop a basic index from the "geo" table.
table.dropFullText("posts_body_fulltext");Drop a full text index from the "posts" table.
.dropSpatialIndex("geo_location_spatialindex");Drop a spatial index from the "geo" table (except SQLite).
+

I may also drop indexes by a column name or column names for composite keys, if you pass a QVector<QString> of columns into a method that drops indexes, the conventional index name will be generated based on the table name, columns, and index type:

+
Schema::table("geo", [](Blueprint &table)
{
table.dropIndex({"state"}); // Drops index 'geo_state_index'
});
+

Foreign Key Constraints

+

TinyORM also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a user_id column on the posts table that references the id column on a users table:

+
#include <orm/schema.hpp>

using Orm::Constants::ID;

Schema::table("posts", [](Blueprint &table)
{
table.unsignedBigInteger("user_id");

table.foreign("user_id").references(ID).on("users");
});
+

Since this syntax is rather verbose, TinyORM provides additional, terser methods that use conventions to provide a better developer experience. When using the foreignId method to create your column, the example above can be rewritten like so:

+
Schema::table("posts", [](Blueprint &table)
{
table.foreignId("user_id").constrained();
});
+

The foreignId method creates an UNSIGNED BIGINT equivalent column, while the constrained method will use conventions to determine the table and column name being referenced. If your table name does not match TinyORM's conventions, you may specify the table name by passing it as an argument to the constrained method:

+
Schema::table("posts", [](Blueprint &table)
{
table.foreignId("user_id").constrained("users");
});
+

You may also specify the desired action for the "on delete" and "on update" properties of the constraint:

+
#include <orm/constants.hpp>

using Orm::SchemaNs::Constants::Cascade;

table.foreignId("user_id")
.constrained()
.onUpdate("cascade")
.onDelete(Cascade);
+

An alternative, expressive syntax is also provided for these actions:

+
MethodDescription
table.cascadeOnUpdate();Updates should cascade.
table.restrictOnUpdate();Updates should be restricted.
table.cascadeOnDelete();Deletes should cascade.
table.restrictOnDelete();Deletes should be restricted.
table.nullOnDelete();Deletes should set the foreign key value to null.
+

Any additional column modifiers must be called before the constrained method:

+
table.foreignId("user_id")
.nullable()
.constrained();
+

Dropping Foreign Keys

+

To drop a foreign key, you may use the dropForeign method, passing the name of the foreign key constraint to be deleted as an argument. Foreign key constraints use the same naming convention as indexes. In other words, the foreign key constraint name is based on the name of the table and the columns in the constraint, followed by a "_foreign" suffix:

+
table.dropForeign("posts_user_id_foreign");
+

Alternatively, you may pass a QVector<QString> containing the column name that holds the foreign key to the dropForeign method. The QVector will be converted to a foreign key constraint name using TinyORM's constraint naming conventions:

+
table.dropForeign({"user_id"});
+

Toggling Foreign Key Constraints

+

You may enable or disable foreign key constraints within your migrations by using the following methods:

+
Schema::enableForeignKeyConstraints();

Schema::disableForeignKeyConstraints();

Schema::withoutForeignKeyConstraints([]
{
// Constraints disabled within this lambda expression...
});
+
warning

The SQLite disables foreign key constraints by default. When using SQLite, make sure to enable foreign key support in your database configuration before attempting to create them in your migrations. In addition, SQLite only supports creating foreign keys when creating tables and not when tables are altered.

\ No newline at end of file diff --git a/database/query-builder.html b/database/query-builder.html index c05afdca5..caa9039ea 100644 --- a/database/query-builder.html +++ b/database/query-builder.html @@ -1,9 +1,9 @@ - + - -Database: Query Builder - TinyORM + +Database: Query Builder - TinyORM @@ -13,14 +13,340 @@ - - - + + + -
-

Database: Query Builder

Introduction

TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application.

The TinyORM query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.

danger

QSqlQuery does not support binding column names. Therefore, you should never allow user input to dictate the column names referenced by your queries, including "order by" columns.

danger

The QMYSQL Qt driver contains a bug, if your table contains a json column type, then you must explicitly name columns other than json columns instead of the * shorthand, otherwise, you will get an empty result, or all column values will be invalid QVariant-s, or it may even return half of the columns. The QPSQL driver returns correct results and doesn't have problem with json columns. It was fixed in the Qt 5.15.12, 6.2.7, 6.5.0 QTBUG-101680.

Running Database Queries

Retrieving All Rows From A Table

You may use the table method provided by the DB facade to begin a query. The table method returns a fluent query builder instance for the given table, allowing you to chain more constraints onto the query and then finally retrieve the results of the query using the get method:

#include <orm/db.hpp>

// Log a list of all of the application's users
auto query = DB::table("users")->get();

while (query.next())
qDebug() << "id :" << query.value("id").toULongLong() << ";"
<< "name :" << query.value("name").toString();

The get method returns a QSqlQuery containing the results of the query where each result can be accessed by QSqlQuery::next method, look into the QSqlQuery documentation how to obtain results from the "query". You may access each column's value by QSqlQuery::value method. The first bool return value is the value returned from QSqlQuery::exec method:

#include <QDebug>

#include <orm/db.hpp>

auto users = DB::table("users")->get();

while(users.next())
qDebug() << users.value("name").toString();

Retrieving A Single Row / Column From A Table

If you just need to retrieve a single row from a database table, you may use the QueryBuilder::first method. This method will return a QSqlQuery object, on which was internally called QSqlQuery::first method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:

auto user = DB::table("users")->whereEq("name", "John").first();

user.value("email").toString();

If you don't need an entire row, you may extract a single value from a record using the value method. This method will return the value of the column directly as QVariant:

auto email = DB::table("users")->whereEq("name", "John").value("email").toString();

To retrieve a single row by its id column value, use the find method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:

auto user = DB::table("users")->find(3);

user.value("email").toString();

Retrieving A List Of Column Values

If you would like to retrieve the QVector<QVariant> instance containing the values of a single column, you may use the pluck method. In this example, we'll retrieve a collection of user titles:

#include <QDebug>

#include <orm/db.hpp>

const auto titles = DB::table("users")->pluck("title");

for (const auto &title : titles)
qDebug() << title.value<QString>();

You may specify the column that the resulting collection should use as its keys by providing a second argument to the pluck method, following example returns the std::map<QString, QVariant> of "titles" keyed by "names":

#include <orm/db.hpp>

auto titles = DB::table("users")->pluck<QString>("title", "name");

for (auto &&[name, title] : titles)
qDebug() << name << ":" << title.value<QString>();

You may also use pluck<quint64>("name", "id"), it returns the std::map<quint64, QVariant> of "names" keyed by its "ids".

note

This second pluck overload returns std::map<T, QVariant> so you have to provide a template argument for the key type.

Concatenate column values

The implode method can be used to join column values. For example, you may use this method to concatenate prices with the , character as the glue:

DB::table("orders")->where("price", ">", 100).implode("price", ", ");

Chunking Results

If you need to work with thousands of database records, consider using the chunk method provided by the DB facade. This method retrieves a small chunk of results at a time and feeds each chunk into a lambda expression for processing. For example, let's retrieve the entire users table in chunks of 100 records at a time:

DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)
{
while (users.next()) {
//
}

return true;
});

You may stop further chunks from being processed by returning false from the closure:

DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)
{
// Process the records...

return false;
});

If you are updating database records while chunking results, your chunk results could change in unexpected ways. If you plan to update the retrieved records while chunking, it is always best to use the chunkById method instead. This method will automatically paginate the results based on the record's primary key:

DB::table("users")
->whereEq("active", false)
.orderBy("id")
.chunkById(100, [](QSqlQuery &users, const int /*unused*/)
{
while (users.next())
DB::table("users")
->whereEq("id", users.value("id"))
.update({{"active", true}});

return true;
});
caution

When updating or deleting records inside the chunk lambda expression, any changes to the primary key or foreign keys could affect the chunk query. This could potentially result in records not being included in the chunked results, it can be avoided using the chunkById method.

Aggregates

The query builder also provides a variety of methods for retrieving aggregate values like count, max, min, avg, and sum. You may call any of these methods after constructing your query:

#include <orm/db.hpp>

auto users = DB::table("users")->count();

auto price = DB::table("orders")->max("price");

Of course, you may combine these methods with other clauses to fine-tune how your aggregate value is calculated:

auto price = DB::table("orders")
->whereEq("finalized", 1)
.avg("price");

Determining If Records Exist

Instead of using the count method to determine if any records exist that match your query's constraints, you may use the exists and doesntExist methods:

if (DB::table("orders")->whereEq("finalized", 1).exists()) {
// ...
}

if (DB::table("orders")->whereEq("finalized", 1).doesntExist()) {
// ...
}

Select Statements

Specifying A Select Clause

You may not always want to select all columns from a database table. Using the select method, you can specify a custom "select" clause for the query:

#include <orm/db.hpp>

auto users = DB::table("users")
->select({"name", "email as user_email"})
.get();

The distinct method allows you to force the query to return distinct results:

auto users = DB::table("users")->distinct().get();

If you already have a query builder instance and you wish to add a column to its existing select clause, you may use the addSelect method:

auto query = DB::table("users")->select("name");

auto users = query.addSelect("age").get();
note

You can also pass subqueries to the select and addSelect methods. A subquery can be a lambda expression, raw string, or the QueryBuilder instance.

Raw Expressions

Sometimes you may need to insert an arbitrary string into a query. To create a raw string expression, you may use the raw method provided by the DB facade:

auto users = DB::table("users")
->select(DB::raw("count(*) as user_count, status"))
.where("status", "<>", 1)
.groupBy("status")
.get();
danger

Raw statements will be injected into the query as strings, so you should be extremely careful to avoid creating SQL injection vulnerabilities.

Raw Methods

Instead of using the DB::raw method, you may also use the following methods to insert a raw expression into various parts of your query. Remember, TinyORM can not guarantee that any query using raw expressions is protected against SQL injection vulnerabilities.

selectRaw

The selectRaw method can be used in place of addSelect(DB::raw(...)). This method accepts an optional vector of bindings as its second argument:

auto orders = DB::table("orders")
->selectRaw("price * ? as price_with_tax", {1.0825})
.get();

fromRaw

The fromRaw method may be used to provide a raw string as the value of the "from" clause:

auto users = DB::connection("postgres").query()
->fromRaw("(select id, name from users where id < ?) as u", {5})
.where("id", "<", 3)
.get();

whereRaw / orWhereRaw

The whereRaw and orWhereRaw methods can be used to inject a raw "where" clause into your query. These methods accept an optional vector of bindings as their second argument:

auto orders = DB::table("orders")
->whereRaw("price > IF(state = \"TX\", ?, 100)", {200})
.get();

groupByRaw

The groupByRaw method may be used to provide a raw string as the value of the group by clause:

auto orders = DB::table("orders")
->select({"city", "state"})
.groupByRaw("city, state")
.get();

havingRaw / orHavingRaw

The havingRaw and orHavingRaw methods may be used to provide a raw string as the value of the "having" clause. These methods accept an optional vector of bindings as their second argument:

auto orders = DB::table("orders")
->select({"department", DB::raw("SUM(price) as total_sales")})
.groupBy("department")
.havingRaw("SUM(price) > ?", {2500})
.get();

orderByRaw

The orderByRaw method may be used to provide a raw string as the value of the "order by" clause:

auto orders = DB::table("orders")
->orderByRaw("updated_at - created_at DESC")
.get();

Joins

Inner Join Clause

The query builder may also be used to add join clauses to your queries. To perform a basic "inner join", you may use the join method on a query builder instance. The first argument passed to the join method is the name of the table you need to join to, while the remaining arguments specify the column constraints for the join. You may even join multiple tables in a single query:

#include <orm/db.hpp>

auto users = DB::table("users")
->join("contacts", "users.id", "=", "contacts.user_id")
.join("orders", "users.id", "=", "orders.user_id")
.select({"users.*", "contacts.phone", "orders.price"})
.get();

Left Join / Right Join Clause

If you would like to perform a "left join" or "right join" instead of an "inner join", use the leftJoin or rightJoin methods. These methods have the same signature as the join method:

auto users = DB::table("users")
->leftJoin("posts", "users.id", "=", "posts.user_id")
.get();

auto users = DB::table("users")
->rightJoin("posts", "users.id", "=", "posts.user_id")
.get();

Cross Join Clause

You may use the crossJoin method to perform a "cross join". Cross joins generate a cartesian product between the first table and the joined table:

auto sizes = DB::table("sizes")
->crossJoin("colors")
.get();

Advanced Join Clauses

You may also specify more advanced join clauses. To get started, pass a lambda expression as the second argument to the join method. The lambda expression will receive a Orm::Query::JoinClause instance which allows you to specify constraints on the "join" clause:

#include <orm/db.hpp>
#include <orm/query/joinclause.hpp>

DB::table("users")
->join("contacts", [](auto &join)
{
join.on("users.id", "=", "contacts.user_id")
.orOn(...);
})
.get();

If you would like to use a "where" clause on your joins, you may use the where and orWhere methods provided by the Orm::Query::JoinClause instance. Instead of comparing two columns, these methods will compare the column against a value:

DB::table("users")
->join("contacts", [](auto &join)
{
join.on("users.id", "=", "contacts.user_id")
.where("contacts.user_id", ">", 5);
})
.get();

Subquery Joins

You may use the joinSub, leftJoinSub, and rightJoinSub methods to join a query to a subquery. Each of these methods receives three arguments: the subquery, its table alias, and a lambda expression that defines the related columns. In this example, we will retrieve a collection of users where each user record also contains the created_at timestamp of the user's most recently published blog post:

auto latestPosts = DB::table("posts")
->select({"user_id", DB::raw("MAX(created_at) as last_post_created_at")})
.whereEq("is_published", true)
.groupBy("user_id");

auto users = DB::table("users")
->joinSub(latestPosts, "latest_posts", [](auto &join)
{
join.on("users.id", "=", "latest_posts.user_id");
}).get();

Basic Where Clauses

Where Clauses

You may use the query builder's where method to add "where" clauses to the query. The most basic call to the where method requires three arguments. The first argument is the name of the column. The second argument is an operator, which can be any of the database's supported operators. The third argument is the value to compare against the column's value.

For example, the following query retrieves users where the value of the votes column is equal to 100 and the value of the age column is greater than 35:

auto users = DB::table("users")
->where("votes", "=", 100)
.where("age", ">", 35)
.get();

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

auto users = DB::table("users")->whereEq("votes", 100).get();

As previously mentioned, you may use any operator that is supported by your database system:

auto users = DB::table("users")
->where("votes", ">=", 100)
.get();

auto users = DB::table("users")
->where("votes", "<>", 100)
.get();

auto users = DB::table("users")
->where("name", "like", "T%")
.get();

You may also pass a QVector<Orm::WhereItem> of conditions to the where function. Each Orm::WhereItem structure should contain the four arguments typically passed to the where method:

auto users = DB::table("users")
->where({
{"status", 1}, // "=" by default
{"subscribed", 1, "<>"},
}).get();

Or Where Clauses

When chaining together calls to the query builder's where method, the "where" clauses will be joined together using the and operator. However, you may use the orWhere or orWhereEq method to join a clause to the query using the or operator. The orWhere method accepts the same arguments as the where method:

auto users = DB::table("users")
->where("votes", ">", 100)
.orWhere("name", "=", "John")
.orWhereEq("name", "Jack")
.get();

If you need to group an "or" condition within parentheses, you may pass a lambda expression as the first argument to the orWhere method:

auto users = DB::table("users")
->where("votes", ">", 100)
.orWhere([](auto &query)
{
query.whereEq("name", "Abigail")
.where("votes", ">", 50);
})
.get();

The example above will produce the following SQL:

select * from users where votes > 100 or (name = "Abigail" and votes > 50)

Condition Operator Overriding

The where method overload with a QVector<Orm::WhereItem> as the first argument joins conditions using the and operator by default:

auto users = DB::table("users")
->where({
{"first_name", "John"},
{"votes", 50, ">"},
}).get();

Conditions operator can be overridden by the fourth argument in the Orm::WhereItem structure:

auto users = DB::table("users")
->where({
{"first_name", "John"},
{"votes", 50, ">", "or"},
}).get();

Or by the second where argument, in this case all conditions will be joined by this condition, but it is still possible to override them by the fourth argument in the Orm::WhereItem structure:

auto users = DB::table("users")
->where({
{"first_name", "John"},
{"last_name", "Smith"},
{"votes", 50, ">", "and"},
}, "or")
.get();

The example above will produce the following SQL:

select * from users where (first_name = "John" or last_name = "Smith" and votes > 50)
tip

Still, it is a better idea to use Logical Grouping described few lines below, which allows better control of the parentheses.

Where Not Clauses

The whereNot and orWhereNot methods may be used to negate a given group of query constraints. For example, the following query excludes products that are on clearance or which have a price that is less than ten:

auto products = DB::table("products")
->whereNot([](auto &query) {
query.whereEq("clearance", true)
.orWhere("price", "<", 10);
})
.get();

Additional Where Clauses

whereBetween / orWhereBetween

The whereBetween method verifies that a column's value is between two values:

auto users = DB::table("users")
->whereBetween("votes", {1, 100})
.get();

whereNotBetween / orWhereNotBetween

The whereNotBetween method verifies that a column's value lies outside of two values:

auto users = DB::table("users")
->whereNotBetween("votes", {1, 100})
.get();

whereBetweenColumns / orWhereBetweenColumns

The whereBetweenColumns method verifies that a column's value is between two values in given columns:

auto files = DB::table("files")
->whereBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})
.get();

whereNotBetweenColumns / orWhereNotBetweenColumns

The whereNotBetweenColumns method verifies that a column's value lies outside of two values in given columns:

auto files = DB::table("files")
->whereNotBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})
.get();

whereIn / whereNotIn / orWhereIn / orWhereNotIn

The whereIn method verifies that a given column's value is contained within the given QVector<QVariant>:

auto users = DB::table("users")
->whereIn("id", {1, 2, 3})
.get();

The whereNotIn method verifies that the given column's value is not contained in the given QVector<QVariant>:

auto users = DB::table("users")
->whereNotIn("id", {1, 2, 3})
.get();

whereNull / whereNotNull / orWhereNull / orWhereNotNull

The whereNull method verifies that the value of the given column is NULL:

auto users = DB::table("users")
->whereNull("updated_at")
.get();

The whereNotNull method verifies that the column's value is not NULL:

auto users = DB::table("users")
->whereNotNull("updated_at")
.get();

whereDate / whereTime / whereDay / whereMonth / whereYear

The whereDate method may be used to compare a column's value against a date:

auto users = DB::table("users")
->whereDate("created_at", EQ, QDate(2022, 11, 18))
.get();

The whereTime method may be used to compare a column's value against a specific time:

auto users = DB::table("users")
->whereTime("created_at", "=", QTime(11, 14, 23))
.get();

The whereDay method may be used to compare a column's value against a specific day of the month:

auto users = DB::table("users")
->whereDay("created_at", "<=", 15)
.get();

The whereMonth method may be used to compare a column's value against a specific month:

auto users = DB::table("users")
->whereEqMonth("created_at", 12)
.get();

The whereYear method may be used to compare a column's value against a specific year:

auto users = DB::table("users")
->whereEqYear("created_at", 2016)
.get();

The whereDate and whereTime methods also accept a QDateTime instance or you can pass values as a QString in 2022-12-31 or 09:15:11 formats.

The whereDay, whereMoth, and whereYear accept QDate or QDateTime instances, an integral number or a QString that contains an integral number.

info

All the above methods offer whereEqXyz and orWhereXyz shortcut methods.

whereColumn / orWhereColumn

The whereColumnEq method may be used to verify that two columns are equal:

auto users = DB::table("users")
->whereColumnEq("first_name", "last_name")
.get();

You may also pass a comparison operator to the whereColumn method:

auto users = DB::table("users")
->whereColumn("updated_at", ">", "created_at")
.get();

You may also pass a QVector<Orm::WhereColumnItem> of column comparisons to the whereColumn method. These conditions will be joined using the and operator:

auto users = DB::table("users")
->whereColumn({
{"first_name", "last_name"},
{"updated_at", "created_at", ">"},
}).get();

Conditions operator can also be overridden by the fourth argument in the Orm::WhereColumnItem structure:

auto users = DB::table("users")
->whereColumn({
{"first_name", "last_name"},
{"updated_at", "created_at", ">", "or"},
}).get();

Or by the second whereColumn argument:

auto users = DB::table("users")
->whereColumn({
{"first_name", "last_name"},
{"updated_at", "created_at", ">"},
}, "or")
.get();

Logical Grouping

Sometimes you may need to group several "where" clauses within parentheses in order to achieve your query's desired logical grouping. In fact, you should generally always group calls to the orWhere method in parentheses in order to avoid unexpected query behavior. To accomplish this, you may pass a lambda expression to the where method:

auto users = DB::table("users")
->where("name", "=", "John")
.where([](auto &query)
{
query.where("votes", ">", 100)
.orWhere("title", "=", "Admin");
})
.get();

As you can see, passing a lambda expression into the where method instructs the query builder to begin a constraint group. The lambda expression will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL:

select * from users where name = "John" and (votes > 100 or title = "Admin")

Advanced Where Clauses

Where Exists Clauses

The whereExists method allows you to write "where exists" SQL clauses. The whereExists method accepts a lambda expression which will receive a query builder instance, allowing you to define the query that should be placed inside of the "exists" clause:

auto users = DB::table("users")
->whereExists([](auto &query)
{
query.select(DB::raw(1))
.from("orders")
.whereColumnEq("orders.user_id", "users.id");
})
.get();

Alternatively, you may provide a query object to the whereExists method instead of a lambda expression:

// Ownership of the std::shared_ptr<QueryBuilder>
auto builder = DB::table("orders");
auto orders = builder->select(DB::raw(1))
.whereColumnEq("orders.user_id", "users.id");

auto users = DB::table("users")
->whereExists(orders)
.get();

Or directly:

auto users = DB::table("users")
->whereExists(DB::table("orders")
->select(DB::raw(1))
.whereColumnEq("orders.user_id", "users.id"))
.get();

All of the examples above will produce the following SQL:

select * from users
where exists (
select 1
from orders
where orders.user_id = users.id
)

Subquery Where Clauses

Sometimes you may need to construct a "where" clause that compares the results of a subquery to a given value. You may accomplish this by passing a lambda expression and a value to the where method. For example, the following query will retrieve all users who have a recent "membership" of a given type:

#include "models/user.hpp"

auto users = User::whereEq([](auto &query)
{
query.select("type")
.from("membership")
.whereColumnEq("membership.user_id", "users.id")
.orderByDesc("membership.start_date")
.limit(1);
}, "Pro")->get();

Or, you may need to construct a "where" clause that compares a column to the results of a subquery. You may accomplish this by passing a column, operator, and lambda expression to the where method. For example, the following query will retrieve all income records where the amount is less than average;

#include "models/income.hpp"

auto incomes = Income::where("amount", "<", [](auto &query)
{
query.selectRaw("avg(i.amount)").from("incomes as i");
})->get();

Ordering, Grouping, Limit & Offset

Ordering

The orderBy Method

The orderBy method allows you to sort the results of the query by a given column. The first argument accepted by the orderBy method should be the column you wish to sort by, while the second argument determines the direction of the sort and may be either asc or desc:

auto users = DB::table("users")
->orderBy("name", "desc")
.get();

To sort by multiple columns, you may simply invoke orderBy as many times as necessary:

auto users = DB::table("users")
->orderBy("name", "desc")
.orderBy("email", "asc")
.get();

The latest & oldest Methods

The latest and oldest methods allow you to easily order results by date. By default, the result will be ordered by the table's created_at column. Or, you may pass the column name that you wish to sort by:

auto user = DB::table("users")
->latest()
.first();

Random Ordering

The inRandomOrder method may be used to sort the query results randomly. For example, you may use this method to fetch a random user:

auto randomUser = DB::table("users")
->inRandomOrder()
.first();

Removing Existing Orderings

The reorder method removes all of the "order by" clauses that have previously been applied to the query:

auto &query = DB::table("users")->orderBy("name");

auto unorderedUsers = query.reorder().get();

You may pass a column and direction when calling the reorder method in order to remove all existing "order by" clauses and apply an entirely new order to the query:

auto &query = DB::table("users")->orderBy("name");

auto usersOrderedByEmail = query.reorder("email", "desc").get();

Grouping

The groupBy & having Methods

As you might expect, the groupBy and having methods may be used to group the query results. The having method's signature is similar to that of the where method:

auto users = DB::table("users")
->groupBy("account_id")
.having("account_id", ">", 100)
.get();

You may pass multiple items to the groupBy method to group by multiple columns:

auto users = DB::table("users")
->groupBy({"first_name", "status"})
.having("account_id", ">", 100)
.get();

Limit & Offset

The skip & take Methods

You may use the skip and take methods to limit the number of results returned from the query or to skip a given number of results in the query:

auto users = DB::table("users")->skip(10).take(5).get();

Alternatively, you may use the limit and offset methods. These methods are functionally equivalent to the take and skip methods, respectively:

auto users = DB::table("users")
->offset(10)
.limit(5)
.get();

Insert Statements

The query builder also provides an insert method that may be used to insert records into the database table. The insert method accepts the QVariantMap of column names and values:

DB::table("users")->insert({
{"email", "kayla@example.com"},
{"votes", 0},
});

You may insert several records at once by passing a QVector<QString> for column names as the first argument and QVector<QVector<QVariant>> for values as the second argument. Each QVector<QVariant> represents a record that should be inserted into the table. This overload is useful for multi-insert and allows to specify column names only once:

DB::table("users")->insert({"email", "votes"},
{
{"picard@example.com", 0},
{"janeway@example.com", 0},
});

You may also insert several records at once by passing a QVector<QVariantMap>. Each QVariantMap represents a record that should be inserted into the table:

DB::table("users")->insert({
{{"email", "picard@example.com"}, {"votes", 0}},
{{"email", "janeway@example.com"}, {"votes", 0}},
});

The insertOrIgnore method will ignore duplicate record errors while inserting records into the database and also provides the same overloads like the insert method. When using this method, you should be aware that duplicate record errors will be ignored and other types of errors may also be ignored depending on the database engine. For example, insertOrIgnore will bypass MySQL's strict mode:

DB::table("users")->insertOrIgnore({"id", "email"},
{
{1, "sisko@example.com"},
{2, "archer@example.com"},
});

DB::table("users")->insertOrIgnore({
{{"id", 1}, {"email", "sisko@example.com"}},
{{"id", 2}, {"email", "archer@example.com"}},
});

Auto-Incrementing IDs

If the table has an auto-incrementing id, use the insertGetId method to insert a record and then retrieve the ID:

auto id = DB::table("users")->insertGetId({
{"email", "john@example.com"},
{"votes", 0},
});

Upserts

The upsert method will insert records that do not exist and update the records that already exist with new values that you may specify. 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 a vector of columns that should be updated if a matching record already exists in the database:

DB::table("flights")->upsert(
{{{"departure", "Oakland"}, {"destination", "San Diego"}, {"price", 99}},
{{"departure", "Chicago"}, {"destination", "New York"}, {"price", 150}}},
{"departure", "destination"},
{"price"}
);

In the example above, TinyORM will attempt to insert two records. If a record already exists with the same departure and destination column values, TinyORM will update that record's price column.

caution

All databases except SQL Server require the columns in the second argument of the upsert method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the upsert method and always uses the "primary" and "unique" indexes of the table to detect existing records.

info

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 documentation. The MySQL server version is auto-detected and can be overridden in the configuration.

Update Statements

In addition to inserting records into the database, the query builder can also update existing records using the update method. The update method, accepts a QVector<Orm::UpdateItem> of column and value pairs, indicating the columns to be updated and returns a std::tuple<int, QSqlQuery> . You may constrain the update query using where clauses:

auto [affected, query] = DB::table("users")
->whereEq("id", 1)
.update({{"votes", 1}});
note

An update and delete are affecting statements, so they return std::tuple<int, QSqlQuery>.

Update Or Insert

Sometimes you may want to update an existing record in the database or create it if no matching record exists. In this scenario, the updateOrInsert method may be used. The updateOrInsert method accepts two arguments: a vector of conditions by which to find the record, and a vector of column and value pairs indicating the columns to be updated.

The updateOrInsert method will attempt to locate a matching database record using the first argument's column and value pairs. If the record exists, it will be updated with the values in the second argument. If the record can not be found, a new record will be inserted with the merged attributes of both arguments:

DB::table("users")
->updateOrInsert(
{{"email", "john@example.com"}, {"name", "John"}},
{{"votes", 2}}
);

Increment & Decrement

The query builder also provides convenient methods for incrementing or decrementing the value of a given column. Both of these methods accept at least one argument: the column to modify. A second argument may be provided to specify the amount by which the column should be incremented or decremented:

DB::table("users")->increment<int>("votes");

DB::table("users")->increment("votes", 5);

DB::table("users")->decrement<int>("votes");

DB::table("users")->decrement("votes", 5.2); // float or double type

You may also specify additional columns to update during the operation as a QVector<Orm::UpdateItem>:

DB::table("users")->increment("votes", 1, {{"name", "John"}});

You should constrain increment, decrement by where to update only specific record in the database, otherwise a column in all records will be modified.

DB::table("users")->whereEq("id", 1).increment("votes", 5);

Delete Statements

The query builder's remove, or an alias deleteRow method may be used to delete records from the table. You may constrain delete statements by adding "where" clauses before calling the delete method:

DB::table("users")->remove();

DB::table("users")->where("votes", ">", 100).remove();
note

delete can not be used as the method name because it is the reserved word.

You may also pass record id to the remove method as the first argument, it is the shortcut method, which internally calls where:

DB::table("users")->remove(2);

Truncate Statement

If you wish to truncate an entire table, which will remove all records from the table and reset the auto-incrementing ID to zero, you may use the truncate method:

DB::table("users")->truncate();

Table Truncation & PostgreSQL

When truncating a PostgreSQL database, the CASCADE behavior will be applied. This means that all foreign key related records in other tables will be deleted as well.

Pessimistic Locking

The query builder also includes a few functions to help you achieve "pessimistic locking" when executing your select statements. To execute a statement with a "shared lock", you may call the sharedLock method. A shared lock prevents the selected rows from being modified until your transaction is committed:

DB::table("users")
->where("votes", ">", 100)
.sharedLock()
.get();

Alternatively, you may use the lockForUpdate method. A "for update" lock prevents the selected records from being modified or from being selected with another shared lock:

DB::table("users")
->where("votes", ">", 100)
.lockForUpdate()
.get();

Debugging

You may use the dd and dump methods while building a query to dump the current query bindings and SQL. The dd method will display the debug information and then stop executing using the exit(1). The dump method will display the debug information and continue executing:

DB::table("users")->where("votes", ">", 100).dd();

DB::table("users")->where("votes", ">", 100).dump();
- - +

Database: Query Builder

+ +

Introduction

+

TinyORM's database query builder provides a convenient, fluent interface to creating and running database queries. It can be used to perform most database operations in your application.

+

The TinyORM query builder uses QSqlQuery parameter binding to protect your application against SQL injection attacks. There is no need to clean or sanitize strings passed to the query builder as query bindings.

+
danger

QSqlQuery does not support binding column names. Therefore, you should never allow user input to dictate the column names referenced by your queries, including "order by" columns.

+
danger

The QMYSQL Qt driver contains a bug, if your table contains a json column type, then you must explicitly name columns other than json columns instead of the * shorthand, otherwise, you will get an empty result, or all column values will be invalid QVariant-s, or it may even return half of the columns. The QPSQL driver returns correct results and doesn't have problem with json columns. It was fixed in the Qt 5.15.12, 6.2.7, 6.5.0 QTBUG-101680.

+

Running Database Queries

+

Retrieving All Rows From A Table

+

You may use the table method provided by the DB facade to begin a query. The table method returns a fluent query builder instance for the given table, allowing you to chain more constraints onto the query and then finally retrieve the results of the query using the get method:

+
#include <orm/db.hpp>

// Log a list of all of the application's users
auto query = DB::table("users")->get();

while (query.next())
qDebug() << "id :" << query.value("id").toULongLong() << ";"
<< "name :" << query.value("name").toString();
+

The get method returns a QSqlQuery containing the results of the query where each result can be accessed by QSqlQuery::next method, look into the QSqlQuery documentation how to obtain results from the "query". You may access each column's value by QSqlQuery::value method. The first bool return value is the value returned from QSqlQuery::exec method:

+
#include <QDebug>

#include <orm/db.hpp>

auto users = DB::table("users")->get();

while(users.next())
qDebug() << users.value("name").toString();
+

Retrieving A Single Row / Column From A Table

+

If you just need to retrieve a single row from a database table, you may use the QueryBuilder::first method. This method will return a QSqlQuery object, on which was internally called QSqlQuery::first method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:

+
auto user = DB::table("users")->whereEq("name", "John").first();

user.value("email").toString();
+

If you don't need an entire row, you may extract a single value from a record using the value method. This method will return the value of the column directly as QVariant:

+
auto email = DB::table("users")->whereEq("name", "John").value("email").toString();
+

To retrieve a single row by its id column value, use the find method. This method retrieves the first record in the result, if available, and positions the query on the retrieved record:

+
auto user = DB::table("users")->find(3);

user.value("email").toString();
+

Retrieving A List Of Column Values

+

If you would like to retrieve the QVector<QVariant> instance containing the values of a single column, you may use the pluck method. In this example, we'll retrieve a collection of user titles:

+
#include <QDebug>

#include <orm/db.hpp>

const auto titles = DB::table("users")->pluck("title");

for (const auto &title : titles)
qDebug() << title.value<QString>();
+

You may specify the column that the resulting collection should use as its keys by providing a second argument to the pluck method, following example returns the std::map<QString, QVariant> of "titles" keyed by "names":

+
#include <orm/db.hpp>

auto titles = DB::table("users")->pluck<QString>("title", "name");

for (auto &&[name, title] : titles)
qDebug() << name << ":" << title.value<QString>();
+

You may also use pluck<quint64>("name", "id"), it returns the std::map<quint64, QVariant> of "names" keyed by its "ids".

+
note

This second pluck overload returns std::map<T, QVariant> so you have to provide a template argument for the key type.

+

Concatenate column values

+

The implode method can be used to join column values. For example, you may use this method to concatenate prices with the , character as the glue:

+
DB::table("orders")->where("price", ">", 100).implode("price", ", ");
+

Chunking Results

+

If you need to work with thousands of database records, consider using the chunk method provided by the DB facade. This method retrieves a small chunk of results at a time and feeds each chunk into a lambda expression for processing. For example, let's retrieve the entire users table in chunks of 100 records at a time:

+
DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)
{
while (users.next()) {
//
}

return true;
});
+

You may stop further chunks from being processed by returning false from the closure:

+
DB::table("users")->orderBy("id").chunk(100, [](QSqlQuery &users, const int page)
{
// Process the records...

return false;
});
+

If you are updating database records while chunking results, your chunk results could change in unexpected ways. If you plan to update the retrieved records while chunking, it is always best to use the chunkById method instead. This method will automatically paginate the results based on the record's primary key:

+
DB::table("users")
->whereEq("active", false)
.orderBy("id")
.chunkById(100, [](QSqlQuery &users, const int /*unused*/)
{
while (users.next())
DB::table("users")
->whereEq("id", users.value("id"))
.update({{"active", true}});

return true;
});
+
caution

When updating or deleting records inside the chunk lambda expression, any changes to the primary key or foreign keys could affect the chunk query. This could potentially result in records not being included in the chunked results, it can be avoided using the chunkById method.

+

Aggregates

+

The query builder also provides a variety of methods for retrieving aggregate values like count, max, min, avg, and sum. You may call any of these methods after constructing your query:

+
#include <orm/db.hpp>

auto users = DB::table("users")->count();

auto price = DB::table("orders")->max("price");
+

Of course, you may combine these methods with other clauses to fine-tune how your aggregate value is calculated:

+
auto price = DB::table("orders")
->whereEq("finalized", 1)
.avg("price");
+

Determining If Records Exist

+

Instead of using the count method to determine if any records exist that match your query's constraints, you may use the exists and doesntExist methods:

+
if (DB::table("orders")->whereEq("finalized", 1).exists()) {
// ...
}

if (DB::table("orders")->whereEq("finalized", 1).doesntExist()) {
// ...
}
+

Select Statements

+

Specifying A Select Clause

+

You may not always want to select all columns from a database table. Using the select method, you can specify a custom "select" clause for the query:

+
#include <orm/db.hpp>

auto users = DB::table("users")
->select({"name", "email as user_email"})
.get();
+

The distinct method allows you to force the query to return distinct results:

+
auto users = DB::table("users")->distinct().get();
+

If you already have a query builder instance and you wish to add a column to its existing select clause, you may use the addSelect method:

+
auto query = DB::table("users")->select("name");

auto users = query.addSelect("age").get();
+
note

You can also pass subqueries to the select and addSelect methods. A subquery can be a lambda expression, raw string, or the QueryBuilder instance.

+

Raw Expressions

+

Sometimes you may need to insert an arbitrary string into a query. To create a raw string expression, you may use the raw method provided by the DB facade:

+
auto users = DB::table("users")
->select(DB::raw("count(*) as user_count, status"))
.where("status", "<>", 1)
.groupBy("status")
.get();
+
danger

Raw statements will be injected into the query as strings, so you should be extremely careful to avoid creating SQL injection vulnerabilities.

+

Raw Methods

+

Instead of using the DB::raw method, you may also use the following methods to insert a raw expression into various parts of your query. Remember, TinyORM can not guarantee that any query using raw expressions is protected against SQL injection vulnerabilities.

+

selectRaw

+

The selectRaw method can be used in place of addSelect(DB::raw(...)). This method accepts an optional vector of bindings as its second argument:

+
auto orders = DB::table("orders")
->selectRaw("price * ? as price_with_tax", {1.0825})
.get();
+

fromRaw

+

The fromRaw method may be used to provide a raw string as the value of the "from" clause:

+
auto users = DB::connection("postgres").query()
->fromRaw("(select id, name from users where id < ?) as u", {5})
.where("id", "<", 3)
.get();
+

whereRaw / orWhereRaw

+

The whereRaw and orWhereRaw methods can be used to inject a raw "where" clause into your query. These methods accept an optional vector of bindings as their second argument:

+
auto orders = DB::table("orders")
->whereRaw("price > IF(state = \"TX\", ?, 100)", {200})
.get();
+

groupByRaw

+

The groupByRaw method may be used to provide a raw string as the value of the group by clause:

+
auto orders = DB::table("orders")
->select({"city", "state"})
.groupByRaw("city, state")
.get();
+

havingRaw / orHavingRaw

+

The havingRaw and orHavingRaw methods may be used to provide a raw string as the value of the "having" clause. These methods accept an optional vector of bindings as their second argument:

+
auto orders = DB::table("orders")
->select({"department", DB::raw("SUM(price) as total_sales")})
.groupBy("department")
.havingRaw("SUM(price) > ?", {2500})
.get();
+

orderByRaw

+

The orderByRaw method may be used to provide a raw string as the value of the "order by" clause:

+
auto orders = DB::table("orders")
->orderByRaw("updated_at - created_at DESC")
.get();
+

Joins

+

Inner Join Clause

+

The query builder may also be used to add join clauses to your queries. To perform a basic "inner join", you may use the join method on a query builder instance. The first argument passed to the join method is the name of the table you need to join to, while the remaining arguments specify the column constraints for the join. You may even join multiple tables in a single query:

+
#include <orm/db.hpp>

auto users = DB::table("users")
->join("contacts", "users.id", "=", "contacts.user_id")
.join("orders", "users.id", "=", "orders.user_id")
.select({"users.*", "contacts.phone", "orders.price"})
.get();
+

Left Join / Right Join Clause

+

If you would like to perform a "left join" or "right join" instead of an "inner join", use the leftJoin or rightJoin methods. These methods have the same signature as the join method:

+
auto users = DB::table("users")
->leftJoin("posts", "users.id", "=", "posts.user_id")
.get();

auto users = DB::table("users")
->rightJoin("posts", "users.id", "=", "posts.user_id")
.get();
+

Cross Join Clause

+

You may use the crossJoin method to perform a "cross join". Cross joins generate a cartesian product between the first table and the joined table:

+
auto sizes = DB::table("sizes")
->crossJoin("colors")
.get();
+

Advanced Join Clauses

+

You may also specify more advanced join clauses. To get started, pass a lambda expression as the second argument to the join method. The lambda expression will receive a Orm::Query::JoinClause instance which allows you to specify constraints on the "join" clause:

+
#include <orm/db.hpp>
#include <orm/query/joinclause.hpp>

DB::table("users")
->join("contacts", [](auto &join)
{
join.on("users.id", "=", "contacts.user_id")
.orOn(...);
})
.get();
+

If you would like to use a "where" clause on your joins, you may use the where and orWhere methods provided by the Orm::Query::JoinClause instance. Instead of comparing two columns, these methods will compare the column against a value:

+
DB::table("users")
->join("contacts", [](auto &join)
{
join.on("users.id", "=", "contacts.user_id")
.where("contacts.user_id", ">", 5);
})
.get();
+

Subquery Joins

+

You may use the joinSub, leftJoinSub, and rightJoinSub methods to join a query to a subquery. Each of these methods receives three arguments: the subquery, its table alias, and a lambda expression that defines the related columns. In this example, we will retrieve a collection of users where each user record also contains the created_at timestamp of the user's most recently published blog post:

+
auto latestPosts = DB::table("posts")
->select({"user_id", DB::raw("MAX(created_at) as last_post_created_at")})
.whereEq("is_published", true)
.groupBy("user_id");

auto users = DB::table("users")
->joinSub(latestPosts, "latest_posts", [](auto &join)
{
join.on("users.id", "=", "latest_posts.user_id");
}).get();
+

Basic Where Clauses

+

Where Clauses

+

You may use the query builder's where method to add "where" clauses to the query. The most basic call to the where method requires three arguments. The first argument is the name of the column. The second argument is an operator, which can be any of the database's supported operators. The third argument is the value to compare against the column's value.

+

For example, the following query retrieves users where the value of the votes column is equal to 100 and the value of the age column is greater than 35:

+
auto users = DB::table("users")
->where("votes", "=", 100)
.where("age", ">", 35)
.get();
+

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

+
auto users = DB::table("users")->whereEq("votes", 100).get();
+

As previously mentioned, you may use any operator that is supported by your database system:

+
auto users = DB::table("users")
->where("votes", ">=", 100)
.get();

auto users = DB::table("users")
->where("votes", "<>", 100)
.get();

auto users = DB::table("users")
->where("name", "like", "T%")
.get();
+

You may also pass a QVector<Orm::WhereItem> of conditions to the where function. Each Orm::WhereItem structure should contain the four arguments typically passed to the where method:

+
auto users = DB::table("users")
->where({
{"status", 1}, // "=" by default
{"subscribed", 1, "<>"},
}).get();
+

Or Where Clauses

+

When chaining together calls to the query builder's where method, the "where" clauses will be joined together using the and operator. However, you may use the orWhere or orWhereEq method to join a clause to the query using the or operator. The orWhere method accepts the same arguments as the where method:

+
auto users = DB::table("users")
->where("votes", ">", 100)
.orWhere("name", "=", "John")
.orWhereEq("name", "Jack")
.get();
+

If you need to group an "or" condition within parentheses, you may pass a lambda expression as the first argument to the orWhere method:

+
auto users = DB::table("users")
->where("votes", ">", 100)
.orWhere([](auto &query)
{
query.whereEq("name", "Abigail")
.where("votes", ">", 50);
})
.get();
+

The example above will produce the following SQL:

+
select * from users where votes > 100 or (name = "Abigail" and votes > 50)
+

Condition Operator Overriding

+

The where method overload with a QVector<Orm::WhereItem> as the first argument joins conditions using the and operator by default:

+
auto users = DB::table("users")
->where({
{"first_name", "John"},
{"votes", 50, ">"},
}).get();
+

Conditions operator can be overridden by the fourth argument in the Orm::WhereItem structure:

+
auto users = DB::table("users")
->where({
{"first_name", "John"},
{"votes", 50, ">", "or"},
}).get();
+

Or by the second where argument, in this case all conditions will be joined by this condition, but it is still possible to override them by the fourth argument in the Orm::WhereItem structure:

+
auto users = DB::table("users")
->where({
{"first_name", "John"},
{"last_name", "Smith"},
{"votes", 50, ">", "and"},
}, "or")
.get();
+

The example above will produce the following SQL:

+
select * from users where (first_name = "John" or last_name = "Smith" and votes > 50)
+
tip

Still, it is a better idea to use Logical Grouping described few lines below, which allows better control of the parentheses.

+

Where Not Clauses

+

The whereNot and orWhereNot methods may be used to negate a given group of query constraints. For example, the following query excludes products that are on clearance or which have a price that is less than ten:

+
auto products = DB::table("products")
->whereNot([](auto &query) {
query.whereEq("clearance", true)
.orWhere("price", "<", 10);
})
.get();
+

Additional Where Clauses

+

whereBetween / orWhereBetween

+

The whereBetween method verifies that a column's value is between two values:

+
auto users = DB::table("users")
->whereBetween("votes", {1, 100})
.get();
+

whereNotBetween / orWhereNotBetween

+

The whereNotBetween method verifies that a column's value lies outside of two values:

+
auto users = DB::table("users")
->whereNotBetween("votes", {1, 100})
.get();
+

whereBetweenColumns / orWhereBetweenColumns

+

The whereBetweenColumns method verifies that a column's value is between two values in given columns:

+
auto files = DB::table("files")
->whereBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})
.get();
+

whereNotBetweenColumns / orWhereNotBetweenColumns

+

The whereNotBetweenColumns method verifies that a column's value lies outside of two values in given columns:

+
auto files = DB::table("files")
->whereNotBetweenColumns("quota", {"min_allowed_quota", "max_allowed_quota"})
.get();
+

whereIn / whereNotIn / orWhereIn / orWhereNotIn

+

The whereIn method verifies that a given column's value is contained within the given QVector<QVariant>:

+
auto users = DB::table("users")
->whereIn("id", {1, 2, 3})
.get();
+

The whereNotIn method verifies that the given column's value is not contained in the given QVector<QVariant>:

+
auto users = DB::table("users")
->whereNotIn("id", {1, 2, 3})
.get();
+

whereNull / whereNotNull / orWhereNull / orWhereNotNull

+

The whereNull method verifies that the value of the given column is NULL:

+
auto users = DB::table("users")
->whereNull("updated_at")
.get();
+

The whereNotNull method verifies that the column's value is not NULL:

+
auto users = DB::table("users")
->whereNotNull("updated_at")
.get();
+

whereDate / whereTime / whereDay / whereMonth / whereYear

+

The whereDate method may be used to compare a column's value against a date:

+
auto users = DB::table("users")
->whereDate("created_at", EQ, QDate(2022, 11, 18))
.get();
+

The whereTime method may be used to compare a column's value against a specific time:

+
auto users = DB::table("users")
->whereTime("created_at", "=", QTime(11, 14, 23))
.get();
+

The whereDay method may be used to compare a column's value against a specific day of the month:

+
auto users = DB::table("users")
->whereDay("created_at", "<=", 15)
.get();
+

The whereMonth method may be used to compare a column's value against a specific month:

+
auto users = DB::table("users")
->whereEqMonth("created_at", 12)
.get();
+

The whereYear method may be used to compare a column's value against a specific year:

+
auto users = DB::table("users")
->whereEqYear("created_at", 2016)
.get();
+

The whereDate and whereTime methods also accept a QDateTime instance or you can pass values as a QString in 2022-12-31 or 09:15:11 formats.

+

The whereDay, whereMoth, and whereYear accept QDate or QDateTime instances, an integral number or a QString that contains an integral number.

+
info

All the above methods offer whereEqXyz and orWhereXyz shortcut methods.

+

whereColumn / orWhereColumn

+

The whereColumnEq method may be used to verify that two columns are equal:

+
auto users = DB::table("users")
->whereColumnEq("first_name", "last_name")
.get();
+

You may also pass a comparison operator to the whereColumn method:

+
auto users = DB::table("users")
->whereColumn("updated_at", ">", "created_at")
.get();
+

You may also pass a QVector<Orm::WhereColumnItem> of column comparisons to the whereColumn method. These conditions will be joined using the and operator:

+
auto users = DB::table("users")
->whereColumn({
{"first_name", "last_name"},
{"updated_at", "created_at", ">"},
}).get();
+

Conditions operator can also be overridden by the fourth argument in the Orm::WhereColumnItem structure:

+
auto users = DB::table("users")
->whereColumn({
{"first_name", "last_name"},
{"updated_at", "created_at", ">", "or"},
}).get();
+

Or by the second whereColumn argument:

+
auto users = DB::table("users")
->whereColumn({
{"first_name", "last_name"},
{"updated_at", "created_at", ">"},
}, "or")
.get();
+

Logical Grouping

+

Sometimes you may need to group several "where" clauses within parentheses in order to achieve your query's desired logical grouping. In fact, you should generally always group calls to the orWhere method in parentheses in order to avoid unexpected query behavior. To accomplish this, you may pass a lambda expression to the where method:

+
auto users = DB::table("users")
->where("name", "=", "John")
.where([](auto &query)
{
query.where("votes", ">", 100)
.orWhere("title", "=", "Admin");
})
.get();
+

As you can see, passing a lambda expression into the where method instructs the query builder to begin a constraint group. The lambda expression will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL:

+
select * from users where name = "John" and (votes > 100 or title = "Admin")
+

Advanced Where Clauses

+

Where Exists Clauses

+

The whereExists method allows you to write "where exists" SQL clauses. The whereExists method accepts a lambda expression which will receive a query builder instance, allowing you to define the query that should be placed inside of the "exists" clause:

+
auto users = DB::table("users")
->whereExists([](auto &query)
{
query.select(DB::raw(1))
.from("orders")
.whereColumnEq("orders.user_id", "users.id");
})
.get();
+

Alternatively, you may provide a query object to the whereExists method instead of a lambda expression:

+
// Ownership of the std::shared_ptr<QueryBuilder>
auto builder = DB::table("orders");
auto orders = builder->select(DB::raw(1))
.whereColumnEq("orders.user_id", "users.id");

auto users = DB::table("users")
->whereExists(orders)
.get();
+

Or directly:

+
auto users = DB::table("users")
->whereExists(DB::table("orders")
->select(DB::raw(1))
.whereColumnEq("orders.user_id", "users.id"))
.get();
+

All of the examples above will produce the following SQL:

+
select * from users
where exists (
select 1
from orders
where orders.user_id = users.id
)
+

Subquery Where Clauses

+

Sometimes you may need to construct a "where" clause that compares the results of a subquery to a given value. You may accomplish this by passing a lambda expression and a value to the where method. For example, the following query will retrieve all users who have a recent "membership" of a given type:

+
#include "models/user.hpp"

auto users = User::whereEq([](auto &query)
{
query.select("type")
.from("membership")
.whereColumnEq("membership.user_id", "users.id")
.orderByDesc("membership.start_date")
.limit(1);
}, "Pro")->get();
+

Or, you may need to construct a "where" clause that compares a column to the results of a subquery. You may accomplish this by passing a column, operator, and lambda expression to the where method. For example, the following query will retrieve all income records where the amount is less than average;

+
#include "models/income.hpp"

auto incomes = Income::where("amount", "<", [](auto &query)
{
query.selectRaw("avg(i.amount)").from("incomes as i");
})->get();
+

Ordering, Grouping, Limit & Offset

+

Ordering

+

The orderBy Method

+

The orderBy method allows you to sort the results of the query by a given column. The first argument accepted by the orderBy method should be the column you wish to sort by, while the second argument determines the direction of the sort and may be either asc or desc:

+
auto users = DB::table("users")
->orderBy("name", "desc")
.get();
+

To sort by multiple columns, you may simply invoke orderBy as many times as necessary:

+
auto users = DB::table("users")
->orderBy("name", "desc")
.orderBy("email", "asc")
.get();
+

The latest & oldest Methods

+

The latest and oldest methods allow you to easily order results by date. By default, the result will be ordered by the table's created_at column. Or, you may pass the column name that you wish to sort by:

+
auto user = DB::table("users")
->latest()
.first();
+

Random Ordering

+

The inRandomOrder method may be used to sort the query results randomly. For example, you may use this method to fetch a random user:

+
auto randomUser = DB::table("users")
->inRandomOrder()
.first();
+

Removing Existing Orderings

+

The reorder method removes all of the "order by" clauses that have previously been applied to the query:

+
auto &query = DB::table("users")->orderBy("name");

auto unorderedUsers = query.reorder().get();
+

You may pass a column and direction when calling the reorder method in order to remove all existing "order by" clauses and apply an entirely new order to the query:

+
auto &query = DB::table("users")->orderBy("name");

auto usersOrderedByEmail = query.reorder("email", "desc").get();
+

Grouping

+

The groupBy & having Methods

+

As you might expect, the groupBy and having methods may be used to group the query results. The having method's signature is similar to that of the where method:

+
auto users = DB::table("users")
->groupBy("account_id")
.having("account_id", ">", 100)
.get();
+

You may pass multiple items to the groupBy method to group by multiple columns:

+
auto users = DB::table("users")
->groupBy({"first_name", "status"})
.having("account_id", ">", 100)
.get();
+

Limit & Offset

+

The skip & take Methods

+

You may use the skip and take methods to limit the number of results returned from the query or to skip a given number of results in the query:

+
auto users = DB::table("users")->skip(10).take(5).get();
+

Alternatively, you may use the limit and offset methods. These methods are functionally equivalent to the take and skip methods, respectively:

+
auto users = DB::table("users")
->offset(10)
.limit(5)
.get();
+

Insert Statements

+

The query builder also provides an insert method that may be used to insert records into the database table. The insert method accepts the QVariantMap of column names and values:

+
DB::table("users")->insert({
{"email", "kayla@example.com"},
{"votes", 0},
});
+ +

You may insert several records at once by passing a QVector<QString> for column names as the first argument and QVector<QVector<QVariant>> for values as the second argument. Each QVector<QVariant> represents a record that should be inserted into the table. This overload is useful for multi-insert and allows to specify column names only once:

+
DB::table("users")->insert({"email", "votes"},
{
{"picard@example.com", 0},
{"janeway@example.com", 0},
});
+

You may also insert several records at once by passing a QVector<QVariantMap>. Each QVariantMap represents a record that should be inserted into the table:

+
DB::table("users")->insert({
{{"email", "picard@example.com"}, {"votes", 0}},
{{"email", "janeway@example.com"}, {"votes", 0}},
});
+

The insertOrIgnore method will ignore duplicate record errors while inserting records into the database and also provides the same overloads like the insert method. When using this method, you should be aware that duplicate record errors will be ignored and other types of errors may also be ignored depending on the database engine. For example, insertOrIgnore will bypass MySQL's strict mode:

+
DB::table("users")->insertOrIgnore({"id", "email"},
{
{1, "sisko@example.com"},
{2, "archer@example.com"},
});

DB::table("users")->insertOrIgnore({
{{"id", 1}, {"email", "sisko@example.com"}},
{{"id", 2}, {"email", "archer@example.com"}},
});
+

Auto-Incrementing IDs

+

If the table has an auto-incrementing id, use the insertGetId method to insert a record and then retrieve the ID:

+
auto id = DB::table("users")->insertGetId({
{"email", "john@example.com"},
{"votes", 0},
});
+

Upserts

+

The upsert method will insert records that do not exist and update the records that already exist with new values that you may specify. 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 a vector of columns that should be updated if a matching record already exists in the database:

+
DB::table("flights")->upsert(
{{{"departure", "Oakland"}, {"destination", "San Diego"}, {"price", 99}},
{{"departure", "Chicago"}, {"destination", "New York"}, {"price", 150}}},
{"departure", "destination"},
{"price"}
);
+

In the example above, TinyORM will attempt to insert two records. If a record already exists with the same departure and destination column values, TinyORM will update that record's price column.

+
caution

All databases except SQL Server require the columns in the second argument of the upsert method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the upsert method and always uses the "primary" and "unique" indexes of the table to detect existing records.

+
info

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 documentation. The MySQL server version is auto-detected and can be overridden in the configuration.

+

Update Statements

+

In addition to inserting records into the database, the query builder can also update existing records using the update method. The update method, accepts a QVector<Orm::UpdateItem> of column and value pairs, indicating the columns to be updated and returns a std::tuple<int, QSqlQuery> . You may constrain the update query using where clauses:

+
auto [affected, query] = DB::table("users")
->whereEq("id", 1)
.update({{"votes", 1}});
+
note

An update and delete are affecting statements, so they return std::tuple<int, QSqlQuery>.

+

Update Or Insert

+

Sometimes you may want to update an existing record in the database or create it if no matching record exists. In this scenario, the updateOrInsert method may be used. The updateOrInsert method accepts two arguments: a vector of conditions by which to find the record, and a vector of column and value pairs indicating the columns to be updated.

+

The updateOrInsert method will attempt to locate a matching database record using the first argument's column and value pairs. If the record exists, it will be updated with the values in the second argument. If the record can not be found, a new record will be inserted with the merged attributes of both arguments:

+
DB::table("users")
->updateOrInsert(
{{"email", "john@example.com"}, {"name", "John"}},
{{"votes", 2}}
);
+

Increment & Decrement

+

The query builder also provides convenient methods for incrementing or decrementing the value of a given column. Both of these methods accept at least one argument: the column to modify. A second argument may be provided to specify the amount by which the column should be incremented or decremented:

+
DB::table("users")->increment<int>("votes");

DB::table("users")->increment("votes", 5);

DB::table("users")->decrement<int>("votes");

DB::table("users")->decrement("votes", 5.2); // float or double type
+

You may also specify additional columns to update during the operation as a QVector<Orm::UpdateItem>:

+
DB::table("users")->increment("votes", 1, {{"name", "John"}});
+

You should constrain increment, decrement by where to update only specific record in the database, otherwise a column in all records will be modified.

+
DB::table("users")->whereEq("id", 1).increment("votes", 5);
+

Delete Statements

+

The query builder's remove, or an alias deleteRow method may be used to delete records from the table. You may constrain delete statements by adding "where" clauses before calling the delete method:

+
DB::table("users")->remove();

DB::table("users")->where("votes", ">", 100).remove();
+
note

delete can not be used as the method name because it is the reserved word.

+

You may also pass record id to the remove method as the first argument, it is the shortcut method, which internally calls where:

+
DB::table("users")->remove(2);
+

Truncate Statement

+

If you wish to truncate an entire table, which will remove all records from the table and reset the auto-incrementing ID to zero, you may use the truncate method:

+
DB::table("users")->truncate();
+

Table Truncation & PostgreSQL

+

When truncating a PostgreSQL database, the CASCADE behavior will be applied. This means that all foreign key related records in other tables will be deleted as well.

+

Pessimistic Locking

+

The query builder also includes a few functions to help you achieve "pessimistic locking" when executing your select statements. To execute a statement with a "shared lock", you may call the sharedLock method. A shared lock prevents the selected rows from being modified until your transaction is committed:

+
DB::table("users")
->where("votes", ">", 100)
.sharedLock()
.get();
+

Alternatively, you may use the lockForUpdate method. A "for update" lock prevents the selected records from being modified or from being selected with another shared lock:

+
DB::table("users")
->where("votes", ">", 100)
.lockForUpdate()
.get();
+

Debugging

+

You may use the dd and dump methods while building a query to dump the current query bindings and SQL. The dd method will display the debug information and then stop executing using the exit(1). The dump method will display the debug information and continue executing:

+
DB::table("users")->where("votes", ">", 100).dd();

DB::table("users")->where("votes", ">", 100).dump();
\ No newline at end of file diff --git a/database/seeding.html b/database/seeding.html index 6fb3c4d28..8336c40f8 100644 --- a/database/seeding.html +++ b/database/seeding.html @@ -1,9 +1,9 @@ - + - -Database: Seeding - TinyORM + +Database: Seeding - TinyORM @@ -13,14 +13,52 @@ - - - + + + -
-

Database: Seeding

Introduction

TinyORM includes the ability to seed your database with data using seed classes. All seed classes should be stored in the database/seeders directory. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the call method to run other seed classes, allowing you to control the seeding order.

tip

Mass assignment protection is automatically disabled during database seeding.

Writing Seeders

To generate a seeder, execute the make:seeder tom command. A new seeder will be placed in the database/seeders directory relative to the current pwd:

tom make:seeder UserSeeder
tip

You can omit the Seeder word in the class name, tom appends it for you.

A seeder class only contains one method by default: run. This method is called when the db:seed tom command is executed. Within the run method, you may insert data into your database however you wish. You may use the query builder to manually insert data.

As an example, let's modify the default DatabaseSeeder class and add a database insert statement to the run method:

#pragma once

#include <tom/seeder.hpp>

namespace Seeders
{

/*! Main database seeder. */
struct DatabaseSeeder : Seeder
{
/*! Run the database seeders. */
void run() override
{
DB::table("users")->insert({"name", "email"},
{
{"1. user", "user1@example.com"},
{"2. user", "user2@example.com"},
});
}
};

} // namespace Seeders
tip

The multi-insert insert method overload is ideal for seeding data.

Calling Additional Seeders

Within the DatabaseSeeder class, you may use the call method to execute additional seed classes. Using the call method allows you to break up your database seeding into multiple files so that no single seeder class becomes too large. The call method accepts the template parameter pack of seeder classes that should be executed:

/*! Run the database seeders. */
void run() override
{
call<UserSeeder, PostSeeder, CommentSeeder>();
}

Call with additional arguments

The call method allows to pass additional arguments to the seeder/s, but it has additional requirements.

If you define a run method without parameters then this method is called using the virtual dispatch (polymorphism) and in this case, you should use the override specifier.

If you define your run method eg. like this run(bool shouldSeed) or whatever parameters you want, then this method is called using the fold expression (virtual dispatch is not used in this case) so you can't use the override specifier and you must call the call<>() method with exactly the same arguments like the run method was defined with, in our example, it should look like this call<ExampleSeeder>(true).

Let's demonstrate it on a small example, following is the run method in the root DatabaseSeeder class.

/*! Run the database seeders. */
void run() override
{
// This value can be based eg. on data from the database
const auto shouldSeed = true;

call<UserSeeder>(shouldSeed);
}

The run method in the UserSeeder class.

/*! Run the database seeders. */
void run(const bool shouldSeed)
{
if (!shouldSeed)
return;

DB::table("users")->insert({
{"name", "1. user"},
});
}
tip

The call method provides two shortcut methods, callWith and callSilent (no output from seeders).

Running Seeders

You may execute the db:seed tom command to seed your database. By default, the db:seed command runs the Seeders::DatabaseSeeder class, which may in turn invoke other seed classes. However, you may use the --class option to specify a specific seeder class to run individually:

tom db:seed

tom db:seed --class=UserSeeder

You may also seed your database using the migrate, migrate:fresh or migrate:refresh commands in combination with the --seed option. For example the migrate:fresh command drops all tables and re-run all of your migrations. This command is useful for completely re-building your database:

tom migrate:fresh --seed
tip

You can change the default seeders path as is described in the C preprocessor macros, CMake provides the TOM_SEEDERS_DIR option.

Forcing Seeders To Run In Production

Some seeding operations may cause you to alter or lose data. In order to protect you from running seeding commands against your production database, you will be prompted for confirmation before the seeders are executed in the production environment. To force the seeders to run without a prompt, use the --force flag:

tom db:seed --force
- - +

Database: Seeding

+ +

Introduction

+

TinyORM includes the ability to seed your database with data using seed classes. All seed classes should be stored in the database/seeders directory. The DatabaseSeeder class is considered as the root seeder. From this class, you may use the call method to run other seed classes, allowing you to control the seeding order.

+
tip

Mass assignment protection is automatically disabled during database seeding.

+

Writing Seeders

+

To generate a seeder, execute the make:seeder tom command. A new seeder will be placed in the database/seeders directory relative to the current pwd:

+
tom make:seeder UserSeeder
+
tip

You can omit the Seeder word in the class name, tom appends it for you.

+

A seeder class only contains one method by default: run. This method is called when the db:seed tom command is executed. Within the run method, you may insert data into your database however you wish. You may use the query builder to manually insert data.

+

As an example, let's modify the default DatabaseSeeder class and add a database insert statement to the run method:

+
#pragma once

#include <tom/seeder.hpp>

namespace Seeders
{

/*! Main database seeder. */
struct DatabaseSeeder : Seeder
{
/*! Run the database seeders. */
void run() override
{
DB::table("users")->insert({"name", "email"},
{
{"1. user", "user1@example.com"},
{"2. user", "user2@example.com"},
});
}
};

} // namespace Seeders
+
tip

The multi-insert insert method overload is ideal for seeding data.

+

Calling Additional Seeders

+

Within the DatabaseSeeder class, you may use the call method to execute additional seed classes. Using the call method allows you to break up your database seeding into multiple files so that no single seeder class becomes too large. The call method accepts the template parameter pack of seeder classes that should be executed:

+
/*! Run the database seeders. */
void run() override
{
call<UserSeeder, PostSeeder, CommentSeeder>();
}
+

Call with additional arguments

+

The call method allows to pass additional arguments to the seeder/s, but it has additional requirements.

+

If you define a run method without parameters then this method is called using the virtual dispatch (polymorphism) and in this case, you should use the override specifier.

+

If you define your run method eg. like this run(bool shouldSeed) or whatever parameters you want, then this method is called using the fold expression (virtual dispatch is not used in this case) so you can't use the override specifier and you must call the call<>() method with exactly the same arguments like the run method was defined with, in our example, it should look like this call<ExampleSeeder>(true).

+

Let's demonstrate it on a small example, following is the run method in the root DatabaseSeeder class.

+
/*! Run the database seeders. */
void run() override
{
// This value can be based eg. on data from the database
const auto shouldSeed = true;

call<UserSeeder>(shouldSeed);
}
+

The run method in the UserSeeder class.

+
/*! Run the database seeders. */
void run(const bool shouldSeed)
{
if (!shouldSeed)
return;

DB::table("users")->insert({
{"name", "1. user"},
});
}
+
tip

The call method provides two shortcut methods, callWith and callSilent (no output from seeders).

+

Running Seeders

+

You may execute the db:seed tom command to seed your database. By default, the db:seed command runs the Seeders::DatabaseSeeder class, which may in turn invoke other seed classes. However, you may use the --class option to specify a specific seeder class to run individually:

+
tom db:seed

tom db:seed --class=UserSeeder
+

You may also seed your database using the migrate, migrate:fresh or migrate:refresh commands in combination with the --seed option. For example the migrate:fresh command drops all tables and re-run all of your migrations. This command is useful for completely re-building your database:

+
tom migrate:fresh --seed
+
tip

You can change the default seeders path as is described in the C preprocessor macros, CMake provides the TOM_SEEDERS_DIR option.

+

Forcing Seeders To Run In Production

+

Some seeding operations may cause you to alter or lose data. In order to protect you from running seeding commands against your production database, you will be prompted for confirmation before the seeders are executed in the production environment. To force the seeders to run without a prompt, use the --force flag:

+
tom db:seed --force
\ No newline at end of file diff --git a/dependencies.html b/dependencies.html index dd21b8a70..88f337994 100644 --- a/dependencies.html +++ b/dependencies.html @@ -1,9 +1,9 @@ - + - -Dependencies - TinyORM + +Dependencies - TinyORM @@ -13,15 +13,31 @@ - - - + + + -
-

Dependencies

The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-18, so may be assumed it will work on future releases of these compilers. Minimum required ISO C++ standard is C++20. -The Qt framework version used during development was 5.15.2 and >=6.2.

Required
caution

Be aware that the standard support for the last release of the Qt 5 series ended on 26. May 2023. [1][2]

Optional
info

The TinyORM will support Qt versions that aren't end-of-life.

note

You can view the supported database servers in the Database - Getting Started section.

Install dependencies

On Linux, you can install dependencies with the package manager.

MySQL C library
Arch   - pacman -S mariadb-libs
Gentoo - emerge dev-db/mysql (package.use: -server -perl)
Ubuntu - apt install libmysqlclient-dev
range-v3 library (header only)
Arch   - pacman -S range-v3
Gentoo - emerge dev-cpp/range-v3
Ubuntu - apt install librange-v3-dev
ccache
Arch   - pacman -S ccache
Gentoo - emerge dev-util/ccache
Ubuntu - apt install ccache
- - +

Dependencies

+

The code was developed on MSVC 16.9-16.11, MSVC 17.2-17.9, GCC 10.2-13.2, and Clang 11-18, so may be assumed it will work on future releases of these compilers. Minimum required ISO C++ standard is C++20. +The Qt framework version used during development was 5.15.2 and >=6.2.

+
Required
+ +
warning

Be aware that the standard support for the last release of the Qt 5 series ended on 26. May 2023. [1][2]

+
Optional
+ +
info

The TinyORM will support Qt versions that aren't end-of-life.

+
note

You can view the supported database servers in the Database - Getting Started section.

+

Install dependencies

+

On Linux, you can install dependencies with the package manager.

+
MySQL C library
Arch   - pacman -S mariadb-libs
Gentoo - emerge dev-db/mysql (package.use: -server -perl)
Ubuntu - apt install libmysqlclient-dev
range-v3 library (header only)
Arch   - pacman -S range-v3
Gentoo - emerge dev-cpp/range-v3
Ubuntu - apt install librange-v3-dev
ccache
Arch   - pacman -S ccache
Gentoo - emerge dev-util/ccache
Ubuntu - apt install ccache
\ No newline at end of file diff --git a/features-summary.html b/features-summary.html index 0e4383858..f467c98b6 100644 --- a/features-summary.html +++ b/features-summary.html @@ -1,9 +1,9 @@ - + - -Features Summary - TinyORM + +Features Summary - TinyORM @@ -13,14 +13,102 @@ - - - + + + -
-

Features Summary

Summary List

The following list fastly summarizes all the TinyORM features.

  • simple database connections management 🧬
    • database manager that helps with the database connections management
    • Orm::DB facade class for nicer and shorter syntax
    • MySQL, MariaDB, SQLite, and PostgreSQL support for all features 💎
    • multi-threading support 👀
    • SSL connections support 🔒
  • impressive query builder 🔧
    • allows passing sub-queries and raw expressions practically everywhere, to column names, values, and to every SQL clause as select, where, joins, group by, having, order by 🔥
    • a logical grouping that offers to wrap logical groups in parenthesis
    • chunked results for lower memory footprint ✨
    • raw methods for all SQL clauses
    • all join types (left, right, cross, inner) and also join where clause support 🫤
    • aggregate methods min, max, sum, increment, decrement, ...
    • whereExists and exists methods for an existence queries
    • transactions and pessimistic locking 🔒
    • of course, insert, update, and delete SQL clauses support
    • correct QDateTime time zone using the qt_timezone connection configuration option 📅 (returned QDateTime instances will have the correct time zone, and also works for an ORM)
      • this feature allows you to set up the database server time zone to the UTC and all returned QDateTime instances will have the correct UTC time zone
  • clever ORM with all relation types support 🎉
    • one-to-one, one-to-many, and many-to-many relation types (also inverse relationships) 🧨
    • eager and lazy loading with custom select and constraints 🚀
    • fluent ModelsCollection that expose a variety of map / reduce operations that may be chained using an intuitive interface ✨
    • all query builder methods are proxied from the model instances and also from the relation instances back to the query builder 🤯 (everything that can be called on the query builder can also be called on the model and relation instances)
    • clean active record pattern
    • advanced features like timestamps, touching parent timestamps, soft deleting, default models, default model attributes, and attribute casting 🤓
    • querying relationships existence/absence using the has, whereHas, and hasNested methods (using dot notation for selecting nested relationships users.posts.comments)
    • serializing models and collection of models including all nested relations to JSON and converting to vectors and maps 🪡
      • supports controlling a custom date format during serialization
      • supports hiding and appending attributes
  • compiled database migrations and seeders 🕺
    • create, update, drop, and rename database tables
    • create, drop, and rename table columns
    • extensive schema builder that allows creating of all possible column types
    • terser syntax for creating foreign keys and foreign key constraints
    • supports creating, and dropping column indexes (primary, unique, fulltext, spatial)
  • the tom console application with tab completion for all shells (pwsh, bash, zsh) 🥳
    • scaffolding of models, migrations, and seeders
    • impressive models scaffolding, every feature that is supported by models can be generated using the tom make:model cli command
  • a huge amount of code is unit tested, currently 3366 unit tests 🤯
  • C++20 only, with all the latest features used like concepts/constraints, ranges, smart pointers (no new keyword in the whole code 😎), folding expressions
  • qmake and CMake build systems support
    • CMake FetchContent module support 🤙
  • vcpkg support (also the vcpkg port, currently not committed to the vcpkg repository ☹️)
  • it's really fast, you can run 1000 complex queries in 500ms (heavily DB dependant, the PostgreSQL is by far the fastest) ⌚
  • extensive documentation 📃
  • ...
info

See the TinyDrivers Features summary.

Showcase Images

Tom console application
TinyORM - Tom console application - Showcase
Passed all unit tests 🥳
TinyORM - Passed all unit tests - Showcase

TinyOrmPlayground

The TinyOrmPlayground project is my personal project where I have tested all the TinyORM database queries in the early development phases, currently, it executes ~1600 database queries across the whole TinyORM framework. Every query has a nice title header, is logged to the console, and is counted and measured (elapsed time). Every query also runs on all supported databases.

The TinyOrmPlayground project can be compiled in a single-threaded or multi-threaded mode. In the multi-threaded mode, every database connection runs in its own thread. At the end of every database connection is logged a connection summary and before an exit is logged the application summary. Whole TinyOrmPlayground application is configurable through the src/configuration.hpp class.

TinyOrmPlayground single-threaded
TinyORM - Invoked TinyOrmPlayground single-threaded - Showcase
TinyOrmPlayground multi-threaded
TinyORM - Invoked TinyOrmPlayground multi-threaded - Showcase
- - +

Features Summary

+ +

Summary List

+

The following list fastly summarizes all the TinyORM features.

+
    +
  • simple database connections management 🧬 +
      +
    • database manager that helps with the database connections management
    • +
    • Orm::DB facade class for nicer and shorter syntax
    • +
    • MySQL, MariaDB, SQLite, and PostgreSQL support for all features 💎
    • +
    • multi-threading support 👀
    • +
    • SSL connections support 🔒
    • +
    +
  • +
  • impressive query builder 🔧 +
      +
    • allows passing sub-queries and raw expressions practically everywhere, to column names, values, and to every SQL clause as select, where, joins, group by, having, order by 🔥
    • +
    • a logical grouping that offers to wrap logical groups in parenthesis
    • +
    • chunked results for lower memory footprint ✨
    • +
    • raw methods for all SQL clauses
    • +
    • all join types (left, right, cross, inner) and also join where clause support 🫤
    • +
    • aggregate methods min, max, sum, increment, decrement, ...
    • +
    • whereExists and exists methods for an existence queries
    • +
    • transactions and pessimistic locking 🔒
    • +
    • of course, insert, update, and delete SQL clauses support
    • +
    • correct QDateTime time zone using the qt_timezone connection configuration option 📅 (returned QDateTime instances will have the correct time zone, and also works for an ORM) +
        +
      • this feature allows you to set up the database server time zone to the UTC and all returned QDateTime instances will have the correct UTC time zone
      • +
      +
    • +
    +
  • +
  • clever ORM with all relation types support 🎉 +
      +
    • one-to-one, one-to-many, and many-to-many relation types (also inverse relationships) 🧨
    • +
    • eager and lazy loading with custom select and constraints 🚀
    • +
    • fluent ModelsCollection that expose a variety of map / reduce operations that may be chained using an intuitive interface ✨
    • +
    • all query builder methods are proxied from the model instances and also from the relation instances back to the query builder 🤯 (everything that can be called on the query builder can also be called on the model and relation instances)
    • +
    • clean active record pattern
    • +
    • advanced features like timestamps, touching parent timestamps, soft deleting, default models, default model attributes, and attribute casting 🤓
    • +
    • querying relationships existence/absence using the has, whereHas, and hasNested methods (using dot notation for selecting nested relationships users.posts.comments)
    • +
    • serializing models and collection of models including all nested relations to JSON and converting to vectors and maps 🪡 +
        +
      • supports controlling a custom date format during serialization
      • +
      • supports hiding and appending attributes
      • +
      +
    • +
    +
  • +
  • compiled database migrations and seeders 🕺 +
      +
    • create, update, drop, and rename database tables
    • +
    • create, drop, and rename table columns
    • +
    • extensive schema builder that allows creating of all possible column types
    • +
    • terser syntax for creating foreign keys and foreign key constraints
    • +
    • supports creating, and dropping column indexes (primary, unique, fulltext, spatial)
    • +
    +
  • +
  • the tom console application with tab completion for all shells (pwsh, bash, zsh) 🥳 +
      +
    • scaffolding of models, migrations, and seeders
    • +
    • impressive models scaffolding, every feature that is supported by models can be generated using the tom make:model cli command
    • +
    +
  • +
  • a huge amount of code is unit tested, currently 3366 unit tests 🤯
  • +
  • C++20 only, with all the latest features used like concepts/constraints, ranges, smart pointers (no new keyword in the whole code 😎), folding expressions
  • +
  • qmake and CMake build systems support +
      +
    • CMake FetchContent module support 🤙
    • +
    +
  • +
  • vcpkg support (also the vcpkg port, currently not committed to the vcpkg repository ☹️)
  • +
  • it's really fast, you can run 1000 complex queries in 500ms (heavily DB dependant, the PostgreSQL is by far the fastest) ⌚
  • +
  • extensive documentation 📃
  • +
  • ...
  • +
+
info

See the TinyDrivers Features summary.

+

Showcase Images

+
Tom console application
+TinyORM - Tom console application - Showcase +
Passed all unit tests 🥳
+TinyORM - Passed all unit tests - Showcase +

TinyOrmPlayground

+

The TinyOrmPlayground project is my personal project where I have tested all the TinyORM database queries in the early development phases, currently, it executes ~1600 database queries across the whole TinyORM framework. Every query has a nice title header, is logged to the console, and is counted and measured (elapsed time). Every query also runs on all supported databases.

+

The TinyOrmPlayground project can be compiled in a single-threaded or multi-threaded mode. In the multi-threaded mode, every database connection runs in its own thread. At the end of every database connection is logged a connection summary and before an exit is logged the application summary. Whole TinyOrmPlayground application is configurable through the src/configuration.hpp class.

+
TinyOrmPlayground single-threaded
+TinyORM - Invoked TinyOrmPlayground single-threaded - Showcase +
TinyOrmPlayground multi-threaded
+TinyORM - Invoked TinyOrmPlayground multi-threaded - Showcase
\ No newline at end of file diff --git a/index.html b/index.html index 53d92385b..ed24d1550 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,9 @@ - + - -Prologue - TinyORM + +Prologue - TinyORM @@ -13,14 +13,58 @@ - - - + + + -
-

Prologue

TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries.

The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests. Almost all the query builder methods are unit tested. The TinyORM's query builder code and the code which is responsible for obtaining relationships, is tested by functional tests against all supported databases. The code coverage is good enough to guarantee API and behavior compatibility.

tip

For a quick look at what's inside, check out the Features Summary.

info

If you don't want to use full ORM, then you can use only the Query Builder, which is outstanding. 🔥 This way you can avoid writing raw SQL queries and your code will run on all supported databases.

Documentation Sitemap
Current versions
  • TinyORM v0.37.3
  • tom v0.9.1
  • TinyDrivers v0.1.1
  • TinyMySql v0.1.1
- - +

Prologue

+

TinyORM is a modern C++ ORM library that makes interacting with a database extremely simple. It depends on the QtCore and QtSql libraries.

+

The code is written in the modern C++20 way and is heavily tested with 3366 unit and functional tests. Almost all the query builder methods are unit tested. The TinyORM's query builder code and the code which is responsible for obtaining relationships, is tested by functional tests against all supported databases. The code coverage is good enough to guarantee API and behavior compatibility.

+
tip

For a quick look at what's inside, check out the Features Summary.

+
info

If you don't want to use full ORM, then you can use only the Query Builder, which is outstanding. 🔥 This way you can avoid writing raw SQL queries and your code will run on all supported databases.

+
Documentation Sitemap
+ +
Current versions
+
    +
  • TinyORM v0.37.3
  • +
  • tom v0.9.1
  • +
  • TinyDrivers v0.1.1
  • +
  • TinyMySql v0.1.1
  • +
\ No newline at end of file diff --git a/search.html b/search.html index d93e98b21..097861a61 100644 --- a/search.html +++ b/search.html @@ -2,8 +2,8 @@ - -Search the documentation - TinyORM + +Search the documentation - TinyORM @@ -13,14 +13,11 @@ - - - + + + -
-

Search the documentation

- - +

Search the documentation

\ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 8d559e7fa..ec3e035d0 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1 +1 @@ -https://www.tinyorm.org/searchweekly0.5https://www.tinyorm.org/weekly0.5https://www.tinyorm.org/building/hello-worldweekly0.5https://www.tinyorm.org/building/migrationsweekly0.5https://www.tinyorm.org/building/tinyormweekly0.5https://www.tinyorm.org/database/getting-startedweekly0.5https://www.tinyorm.org/database/migrationsweekly0.5https://www.tinyorm.org/database/query-builderweekly0.5https://www.tinyorm.org/database/seedingweekly0.5https://www.tinyorm.org/dependenciesweekly0.5https://www.tinyorm.org/features-summaryweekly0.5https://www.tinyorm.org/sponsorsweekly0.5https://www.tinyorm.org/supported-compilersweekly0.5https://www.tinyorm.org/tinydrivers/getting-startedweekly0.5https://www.tinyorm.org/tinyorm/castsweekly0.5https://www.tinyorm.org/tinyorm/collectionsweekly0.5https://www.tinyorm.org/tinyorm/getting-startedweekly0.5https://www.tinyorm.org/tinyorm/relationshipsweekly0.5https://www.tinyorm.org/tinyorm/serializationweekly0.5 \ No newline at end of file +https://www.tinyorm.org/searchweekly0.5https://www.tinyorm.org/building/hello-worldweekly0.5https://www.tinyorm.org/building/migrationsweekly0.5https://www.tinyorm.org/building/tinyormweekly0.5https://www.tinyorm.org/database/getting-startedweekly0.5https://www.tinyorm.org/database/migrationsweekly0.5https://www.tinyorm.org/database/query-builderweekly0.5https://www.tinyorm.org/database/seedingweekly0.5https://www.tinyorm.org/dependenciesweekly0.5https://www.tinyorm.org/features-summaryweekly0.5https://www.tinyorm.org/sponsorsweekly0.5https://www.tinyorm.org/supported-compilersweekly0.5https://www.tinyorm.org/tinydrivers/getting-startedweekly0.5https://www.tinyorm.org/tinyorm/castsweekly0.5https://www.tinyorm.org/tinyorm/collectionsweekly0.5https://www.tinyorm.org/tinyorm/getting-startedweekly0.5https://www.tinyorm.org/tinyorm/relationshipsweekly0.5https://www.tinyorm.org/tinyorm/serializationweekly0.5https://www.tinyorm.org/weekly0.5 \ No newline at end of file diff --git a/sponsors.html b/sponsors.html index 1cc6d0ece..11935f3a5 100644 --- a/sponsors.html +++ b/sponsors.html @@ -1,9 +1,9 @@ - + - -Sponsors - TinyORM + +Sponsors - TinyORM @@ -13,14 +13,14 @@ - - - + + + -
-

Sponsors

I have spent ~2 years every day 10 hours of coding (excluding weekends and sick days) to make this project real. Everything was funded from my personal resources, I had no problem with it to be honest, it was really fun 🎉, but I had to move to the new apartment a few months ago and I'm out of money now. ☹️

I would like to continue developing and enhancing this project and I will as long as I can. But the future is unclear now.

ServiceAddress
Bitcoin address1NiF2cTvYxUj8FTZJnGn1ycN4yisWfo1vJ
PayPalhttps://paypal.me/silverzachara
- - +

Sponsors

+

I have spent ~2 years every day 10 hours of coding (excluding weekends and sick days) to make this project real. Everything was funded from my personal resources, I had no problem with it to be honest, it was really fun 🎉, but I had to move to the new apartment a few months ago and I'm out of money now. ☹️

+

I would like to continue developing and enhancing this project and I will as long as I can. But the future is unclear now.

+
ServiceAddress
Bitcoin address1NiF2cTvYxUj8FTZJnGn1ycN4yisWfo1vJ
PayPalhttps://paypal.me/silverzachara
\ No newline at end of file diff --git a/supported-compilers.html b/supported-compilers.html index 8e0feed4c..f58542950 100644 --- a/supported-compilers.html +++ b/supported-compilers.html @@ -1,9 +1,9 @@ - + - -Supported Compilers - TinyORM + +Supported Compilers - TinyORM @@ -13,14 +13,42 @@ - - - + + + -
-

Supported Compilers

Following compilers are backed up by the GitHub Action workflows (CI pipelines), these workflows also include more then 3366 unit tests 😮💥.

Windows >=10

  • MSVC 2019 >=16.9
  • MSVC 2022 >=17
  • MSYS2 UCRT64 GCC 10.2 - 13.2
  • MSYS2 UCRT64 Clang >=15
  • clang-cl >=15 with MSVC 2019/2022

Linux

  • GCC 10.2 - 13.2
  • Clang >=15 (libstdc++ only)
tip

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.

caution

The macOS and Clang with libc++ are not supported.

Supported build systems

  • CMake >=3.22 (policies <= CMP0128 default to NEW)
  • qmake distributed by the Qt Framework
Make tools
  • jom - highly recommended with the qmake build system on Windows (replacement for nmake)
  • ninja - recommended for CMake as the make file generator
Parallel building

You can control parallel building using the following environment variables.

  • CMake - CMAKE_BUILD_PARALLEL_LEVEL eg. to 10
  • jom - JOMFLAGS eg. to j11
  • make - MAKEFLAGS eg. to -j10
  • vcpkg - VCPKG_MAX_CONCURRENCY eg. to 10
- - +

Supported Compilers

+

Following compilers are backed up by the GitHub Action workflows (CI pipelines), these workflows also include more then 3366 unit tests 😮💥.

+

Windows >=10

    +
  • MSVC 2019 >=16.9
  • +
  • MSVC 2022 >=17
  • +
  • MSYS2 UCRT64 GCC 10.2 - 13.2
  • +
  • MSYS2 UCRT64 Clang >=15
  • +
  • clang-cl >=15 with MSVC 2019/2022
  • +

Linux

    +
  • GCC 10.2 - 13.2
  • +
  • Clang >=15 (libstdc++ only)
  • +
+
tip

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.

+
warning

The macOS and Clang with libc++ are not supported.

+

Supported build systems

+
    +
  • CMake >=3.22 (policies <= CMP0128 default to NEW)
  • +
  • qmake distributed by the Qt Framework
  • +
+
Make tools
+
    +
  • jom - highly recommended with the qmake build system on Windows (replacement for nmake)
  • +
  • ninja - recommended for CMake as the make file generator
  • +
+
Parallel building
+

You can control parallel building using the following environment variables.

+
    +
  • CMake - CMAKE_BUILD_PARALLEL_LEVEL eg. to 10
  • +
  • jom - JOMFLAGS eg. to j11
  • +
  • make - MAKEFLAGS eg. to -j10
  • +
  • vcpkg - VCPKG_MAX_CONCURRENCY eg. to 10
  • +
\ No newline at end of file diff --git a/tinydrivers/getting-started.html b/tinydrivers/getting-started.html index 06a6dae50..27cd5cb77 100644 --- a/tinydrivers/getting-started.html +++ b/tinydrivers/getting-started.html @@ -1,9 +1,9 @@ - + - -TinyDrivers: Getting Started - TinyORM + +TinyDrivers: Getting Started - TinyORM @@ -13,14 +13,89 @@ - - - + + + -
-

TinyDrivers: Getting Started

Introduction

The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. 😮 Swapping is controlled by the qmake and CMake build system options.

It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.

Features summary
  • both, normal and prepared statements are supported
  • TLS/SSL connections using MYSQL_OPT_SSL_MODE (verify_ca, verify_identity) 🔥
  • setting many other connection options (see mysqldriver_p.cpp)
  • building and linking against the MariaDB Connector/C
  • transactions
  • re-using the current SqlQuery instance to re-execute the same or another query
  • detaching from the result set (associated to release memory)
  • query size, number of affected rows, last inserted ID, testing isNull(), ...
  • all 3366 unit tests passed 😮
info

Currently, only the MySQL database driver is supported and finished.

info

TinyDrivers can only be built with Qt v6, Qt v5.15 isn't supported.

note

TinyDrivers library supports both build systems qmake and also CMake.

Differences from QtSql

TinyDrivers doesn't return errors the the same way as the QtSql module, which means return a bool and if it's the result false then obtain the SqlError instance using the lastError() method from SqlDatabase or SqlQuery instances. Instead, it throws exceptions, and methods returning a bool type to report an error state always return true.

Naming conventions
  • QtSql module -> TinyDrivers library
  • QMYSQL driver -> TinyMySql driver
MySQL driver

The following describes the differences between QMYSQL and TinyMySql drivers.

The QMYSQL driver doesn't support setting MySQL non-flag connection options like MYSQL_OPT_RECONNECT without the value, it needs to be defined with value like =1 or =TRUE (case-sensitive), only real flag options like CLIENT_INTERACTIVE can be set without the value and = character.

On the other hand, the TinyMySql driver allows setting non-flag connection options options without the value and = character, which are considered enabled (ON or TRUE).

Removed features

Simulation of prepared statements while calling SqlQuery::exec(QString), this functionality is useless because you can call regular prepared statements using SqlQuery::prepare(QString) and then SqlQuery::exec().

Missing features

Fetching multiple result sets using SqlQuery::nextResult(). Multiple statement queries are supported they will be executed correctly (they can return multiple result sets), but only the first result set can be fetched currently. However, destroying multiple result sets is handled correctly.

Build system

Another difference is that you can build the TinyDrivers and its SQL drivers (TinyMySql) in 3 different ways; Shared, Static, and as a Loadable library at runtime using LoadLibrary() on Windows or dlopen() on Linux.

The Shared library build

It builds two shared libraries, the TinyDrivers shared library that contains the core/common code and the TinyMySql shared library that contains MySQL implementation. The TinyOrm links only against the TinyDrivers shared library and TinyMySql is a private implementation.

The Static build

It builds one TinyDrivers static archive that contains the core/common code and SQL drivers (TinyMySql). This static library is linked or merged into the TinyOrm shared or static library (both variants are supported).

The Loadable SQL drivers build

It builds two shared libraries, the TinyDrivers shared library that contains the core/common code and TinyMySql shared library (module) that contains MySQL implementation that is loaded at runtime using LoadLibrary() on Windows or dlopen() on Linux. The SQL driver library loader throws an exception if it cannot find this library at runtime.

info

The TinyMySql links directly against the MySQL C connector (libmysql or mysqlclient library).

CMake/qmake build options

For CMake

See CMake build options, related CMake build options are:
BUILD_DRIVERS, BUILD_MYSQL_DRIVER, and DRIVERS_TYPE

To control shared and static build use BUILD_SHARED_LIBS CMake configuration option.

For qmake

See qmake build options, related qmake configuration options are:
build_loadable_drivers, build_mysql_driver, build_shared_drivers, and build_static_drivers

To control shared and static build use static qmake configuration option.

Performance

Performance is several milliseconds faster compared to QtSql with the QMYSQL driver. It was tuned using the KCacheGrind to be so. It's ~40ms faster on TinyOrmPlayground project with 620 database queries compiled using GCC v13.2.1 Debug build on Linux. Similar results can be expected on other platforms but it's not guaranteed.

This means performance is very similar to QtSql. There is not much to speed up because TinyDrivers code is swift and 90% of the time is spent inside the MySQL C API because we always have to wait for the database server, especially when creating database connections using eg. mysql_real_connect() (this function is king among the slowest functions 😎, which is understandable of course).

Internals

TinyDrivers internal design can be divided into 3 different layers:

  • Driver layer
  • SQL API layer
  • Public API layer

The Driver layer is eg. TinyMySql library which is responsible for communicating with the underlying database driver (eg. MySQL C API).

The SQL API layer is a semi-layer that glues everything up and sits between the Public interface API and the Driver layer.

The Public interface API layer are the end classes like SqlDatabase and SqlQuery which are exposed to the end user.

SqlDatabase

One more thing worth mentioning is the SqlDatabase API. It's one class that has two responsibilities! All static methods act as the database connection manager and an instance of the SqlDatabase represents a physical database connection. It's not a good design because it breaks the Single Responsibility principle, but it's what it is.

Namespaces

TinyDrivers classes are defined in the Orm::Drivers namespace and TinyMySql classes in the Orm::Drivers::MySql namespace.

Documentation

For all other APIs you can follow the QtSql documentation as the API is 1:1. The exception is of course the build system, TinyOrm has its own build system that doesn't follow the QtSql module.

- - +

TinyDrivers: Getting Started

+ +

Introduction

+

The TinyDrivers library is an underlying SQL database layer for TinyORM. It can be used instead of the QtSql module, can be swapped at compile time, and has 1:1 API as the QtSql module. 😮 Swapping is controlled by the qmake and CMake build system options.

+

It was designed to drop the QtSql dependency while maintaining backward compatibility and without the need for any code changes after the swap.

+
Features summary
+
    +
  • both, normal and prepared statements are supported
  • +
  • TLS/SSL connections using MYSQL_OPT_SSL_MODE (verify_ca, verify_identity) 🔥
  • +
  • setting many other connection options (see mysqldriver_p.cpp)
  • +
  • building and linking against the MariaDB Connector/C
  • +
  • transactions
  • +
  • re-using the current SqlQuery instance to re-execute the same or another query
  • +
  • detaching from the result set (associated to release memory)
  • +
  • query size, number of affected rows, last inserted ID, testing isNull(), ...
  • +
  • all 3366 unit tests passed 😮
  • +
+
info

Currently, only the MySQL database driver is supported and finished.

+
info

TinyDrivers can only be built with Qt v6, Qt v5.15 isn't supported.

+
note

TinyDrivers library supports both build systems qmake and also CMake.

+

Differences from QtSql

+

TinyDrivers doesn't return errors the the same way as the QtSql module, which means return a bool and if it's the result false then obtain the SqlError instance using the lastError() method from SqlDatabase or SqlQuery instances. Instead, it throws exceptions, and methods returning a bool type to report an error state always return true.

+
Naming conventions
+
    +
  • QtSql module -> TinyDrivers library
  • +
  • QMYSQL driver -> TinyMySql driver
  • +
+
MySQL driver
+

The following describes the differences between QMYSQL and TinyMySql drivers.

+

The QMYSQL driver doesn't support setting MySQL non-flag connection options like MYSQL_OPT_RECONNECT without the value, it needs to be defined with value like =1 or =TRUE (case-sensitive), only real flag options like CLIENT_INTERACTIVE can be set without the value and = character.

+

On the other hand, the TinyMySql driver allows setting non-flag connection options options without the value and = character, which are considered enabled (ON or TRUE).

+
Removed features
+

Simulation of prepared statements while calling SqlQuery::exec(QString), this functionality is useless because you can call regular prepared statements using SqlQuery::prepare(QString) and then SqlQuery::exec().

+
Missing features
+

Fetching multiple result sets using SqlQuery::nextResult(). Multiple statement queries are supported they will be executed correctly (they can return multiple result sets), but only the first result set can be fetched currently. However, destroying multiple result sets is handled correctly.

+

Build system

+

Another difference is that you can build the TinyDrivers and its SQL drivers (TinyMySql) in 3 different ways; Shared, Static, and as a Loadable library at runtime using LoadLibrary() on Windows or dlopen() on Linux.

+
The Shared library build
+

It builds two shared libraries, the TinyDrivers shared library that contains the core/common code and the TinyMySql shared library that contains MySQL implementation. The TinyOrm links only against the TinyDrivers shared library and TinyMySql is a private implementation.

+
The Static build
+

It builds one TinyDrivers static archive that contains the core/common code and SQL drivers (TinyMySql). This static library is linked or merged into the TinyOrm shared or static library (both variants are supported).

+
The Loadable SQL drivers build
+

It builds two shared libraries, the TinyDrivers shared library that contains the core/common code and TinyMySql shared library (module) that contains MySQL implementation that is loaded at runtime using LoadLibrary() on Windows or dlopen() on Linux. The SQL driver library loader throws an exception if it cannot find this library at runtime.

+
info

The TinyMySql links directly against the MySQL C connector (libmysql or mysqlclient library).

+

CMake/qmake build options

+
For CMake
+

See CMake build options, related CMake build options are:
BUILD_DRIVERS, BUILD_MYSQL_DRIVER, and DRIVERS_TYPE

+

To control shared and static build use BUILD_SHARED_LIBS CMake configuration option.

+
For qmake
+

See qmake build options, related qmake configuration options are:
build_loadable_drivers, build_mysql_driver, build_shared_drivers, and build_static_drivers

+

To control shared and static build use static qmake configuration option.

+

Performance

+

Performance is several milliseconds faster compared to QtSql with the QMYSQL driver. It was tuned using the KCacheGrind to be so. It's ~40ms faster on TinyOrmPlayground project with 620 database queries compiled using GCC v13.2.1 Debug build on Linux. Similar results can be expected on other platforms but it's not guaranteed.

+

This means performance is very similar to QtSql. There is not much to speed up because TinyDrivers code is swift and 90% of the time is spent inside the MySQL C API because we always have to wait for the database server, especially when creating database connections using eg. mysql_real_connect() (this function is king among the slowest functions 😎, which is understandable of course).

+

Internals

+

TinyDrivers internal design can be divided into 3 different layers:

+
    +
  • Driver layer
  • +
  • SQL API layer
  • +
  • Public API layer
  • +
+

The Driver layer is eg. TinyMySql library which is responsible for communicating with the underlying database driver (eg. MySQL C API).

+

The SQL API layer is a semi-layer that glues everything up and sits between the Public interface API and the Driver layer.

+

The Public interface API layer are the end classes like SqlDatabase and SqlQuery which are exposed to the end user.

+
SqlDatabase
+

One more thing worth mentioning is the SqlDatabase API. It's one class that has two responsibilities! All static methods act as the database connection manager and an instance of the SqlDatabase represents a physical database connection. It's not a good design because it breaks the Single Responsibility principle, but it's what it is.

+
Namespaces
+

TinyDrivers classes are defined in the Orm::Drivers namespace and TinyMySql classes in the Orm::Drivers::MySql namespace.

+
Documentation
+

For all other APIs you can follow the QtSql documentation as the API is 1:1. The exception is of course the build system, TinyOrm has its own build system that doesn't follow the QtSql module.

\ No newline at end of file diff --git a/tinyorm/casts.html b/tinyorm/casts.html index 2ee9e3476..4be0e1654 100644 --- a/tinyorm/casts.html +++ b/tinyorm/casts.html @@ -1,9 +1,9 @@ - + - -TinyORM: Casting - TinyORM + +TinyORM: Casting - TinyORM @@ -13,15 +13,103 @@ - - - + + + -
-

TinyORM: Casting

Introduction

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. Or, you may want to convert a tinyint number that is stored in the database to the bool when you access it on the TinyORM model.

Accessors

caution

Accessors are currently only used during the serialization by the Appending Values feature. They are not used during the getAttribute or getAttributeValue methods calls.

Defining An Accessor

An accessor transforms a TinyORM attribute value when it is accessed (currently during serialization only by the 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.

In this example, we'll define an accessor for the first_name attribute. The accessor will automatically be called by TinyORM during serialization if the first_name attribute is defined in the u_appends data member set. All attribute accessor methods must return the Orm::Tiny::Casts::Attribute:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

protected:
/*! Get the user's first name (accessor). */
Attribute firstName() const noexcept
{
return Attribute::make(/* get */ [this]() -> QVariant
{
auto firstName = getAttribute<QString>("first_name");

if (!firstName.isEmpty())
firstName[0] = firstName.at(0).toUpper();

return firstName;
});
}

private:
/*! Map of mutator names to methods. */
inline static const QHash<QString, MutatorFunction> u_mutators {
{"first_name", &User::firstName},
};
};

All accessor methods return an Attribute instance which defines how the attribute will be accessed. To do so, we supply the get argument to the Attribute class constructor or Attribute::make factory method.

As you can see, the current model is captured by-reference using the [this] capture, allowing you to obtain a value by the getAttribute method inside the lambda expression, manipulate it and return a new value.

You can also use the second overload that allows you to pass the ModelAttributes unordered map to the lambda expression:

protected:
/*! Get the user's first name (accessor). */
Attribute firstName() const noexcept
{
return Attribute::make(
/* get */ [](const ModelAttributes &attributes) -> QVariant
{
auto firstName = attributes.at<QString>("first_name");

if (!firstName.isEmpty())
firstName[0] = firstName.at(0).toUpper();

return firstName;
});
}

The ModelAttributes container extends the std::unordered_map<QString, QVariant> and adds the at<T> method that allows you to cast the underlying QVariant value.

Special note should be given to the u_mutators static data member map, which maps accessors' attribute names to its methods. This data member is required because C++ does not currently support reflection.

info

If you would like these computed values to be added to the vector, map, or JSON representations of your model, you will need to append them.

danger

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.

Building Value From Multiple Attributes

Sometimes your accessor may need to transform multiple model attributes into a single value. You can use both methods described above to accomplish this:

using Orm::Constants::SPACE_IN;

protected:
/*! Get the user's full name (accessor). */
Attribute fullName() const noexcept
{
return Attribute::make(/* get */ [this]() -> QVariant
{
return SPACE_IN.arg(getAttribute<QString>("first_name"),
getAttribute<QString>("last_name"));
});
}

Or you can use the ModelAttributes overload:

/*! Get the user's full name (accessor). */
Attribute fullName() const noexcept
{
return Attribute::make(
/* get */ [](const ModelAttributes &attributes) -> QVariant
{
return SPACE_IN.arg(attributes.at<QString>("first_name"),
attributes.at<QString>("last_name"));
});
}

Accessor Caching

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 shouldCache method when defining your accessor:

using Orm::Constants::SPACE_IN;

protected:
/*! Get the user's full name (accessor). */
Attribute fullName() const noexcept
{
return Attribute::make(/* get */ [this]() -> QVariant
{
return SPACE_IN.arg(getAttribute<QString>("first_name"),
getAttribute<QString>("last_name"));
}).shouldCache();
}

Attribute Casting

Attribute casting provides functionality that allows converting model attributes to the appropriate QVariant metatype when it is accessed via your TinyORM model. The core of this functionality is a model's u_casts static data member that provides a convenient method of converting attributes' QVariant internal types to the defined cast types.

The u_casts static data member should be the std::unordered_map<QString, Orm::CastItem> 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:

  • CastType::QString
  • CastType::Boolean / CastType::Bool
  • CastType::Integer / CastType::Int
  • CastType::UInteger / CastType::UInt
  • CastType::LongLong
  • CastType::ULongLong
  • CastType::Short
  • CastType::UShort
  • CastType::QDate
  • CastType::QDateTime
  • CastType::Timestamp
  • CastType::Real
  • CastType::Float
  • CastType::Double
  • CastType::Decimal:<precision>
  • CastType::QByteArray
info

The primary key name defined by the u_primaryKey model's data member is automatically cast to the CastType::ULongLong for all database drivers if the u_incrementing is set to true (its default value).

To demonstrate attribute casting, let's cast the is_admin attribute, which is stored in our database as an integer (0 or 1) to a QVariant(bool) value:

#pragma once

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! The attributes that should be cast. */
inline static std::unordered_map<QString, CastItem> u_casts {
{"is_admin", CastType::Boolean},
};
};

After defining the cast, the is_admin attribute will always be cast to a QVariant(bool) when you access it, even if the underlying value is stored in the database as an integer:

using Orm::Utils::Helpers;

auto isAdmin = User::find(1)->getAttribute("is_admin");

// Proof of the QVariant type
Q_ASSERT(Helpers::qVariantTypeId(isAdmin) == QMetaType::Bool);

if (isAdmin.value<bool>()) {
//
}

If you need to add a new, temporary cast at runtime, you may use the mergeCasts method. These cast definitions will be added to any of the casts already defined on the model:

user->mergeCasts({
{"is_paid", CastType::Boolean},
{"income", {CastType::Decimal, 2}},
});
caution

You should never define a cast (or an attribute) that has the same name as a relationship.

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 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.

You may customize the default serialization format for all of your model's dates or datetimes by defining a serializeDate or serializeDateTime methods on your model. These methods do not affect how your dates are formatted for storage in the database:

/*! 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).

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

By default, the CastType::CustomQDate and CastType::CustomQDateTime casts will serialize dates to a UTC ISO-8601 date string (yyyy-MM-ddTHH:mm:ss.zzzZ), regardless of the timezone specified in your database connection's 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 qt_timezone configuration option from its default 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.

If a custom format is applied to the CastType::CustomQDate or CastType::CustomQDateTime cast types, such as {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 qt_timezone configuration option.

Query Time Casting

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:

using Models::Post;
using Models::User;

auto users = User::select("users.*")
->addSelect(
Post::selectRaw("MAX(created_at)")
->whereColumnEq("user_id", "users.id")
.toBase(),
"last_posted_at"
).get();

The last_posted_at attribute on the results of this query will be a simple string. It would be wonderful if we could apply a CastType::QDateTime cast to this attribute when executing the query. Thankfully, we may accomplish this using the withCasts or withCast methods:

auto users = User::select("users.*")
->addSelect(Post::selectRaw("MAX(created_at)")
->whereColumnEq("user_id", "users.id")
.toBase(),
"last_posted_at")
.withCast({"last_posted_at", CastType::QDateTime})
.get();
- - +

TinyORM: Casting

+ +

Introduction

+

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. Or, you may want to convert a tinyint number that is stored in the database to the bool when you access it on the TinyORM model.

+

Accessors

+
warning

Accessors are currently only used during the serialization by the Appending Values feature. They are not used during the getAttribute or getAttributeValue methods calls.

+

Defining An Accessor

+

An accessor transforms a TinyORM attribute value when it is accessed (currently during serialization only by the 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.

+

In this example, we'll define an accessor for the first_name attribute. The accessor will automatically be called by TinyORM during serialization if the first_name attribute is defined in the u_appends data member set. All attribute accessor methods must return the Orm::Tiny::Casts::Attribute:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

protected:
/*! Get the user's first name (accessor). */
Attribute firstName() const noexcept
{
return Attribute::make(/* get */ [this]() -> QVariant
{
auto firstName = getAttribute<QString>("first_name");

if (!firstName.isEmpty())
firstName[0] = firstName.at(0).toUpper();

return firstName;
});
}

private:
/*! Map of mutator names to methods. */
inline static const QHash<QString, MutatorFunction> u_mutators {
{"first_name", &User::firstName},
};
};
+

All accessor methods return an Attribute instance which defines how the attribute will be accessed. To do so, we supply the get argument to the Attribute class constructor or Attribute::make factory method.

+

As you can see, the current model is captured by-reference using the [this] capture, allowing you to obtain a value by the getAttribute method inside the lambda expression, manipulate it and return a new value.

+

You can also use the second overload that allows you to pass the ModelAttributes unordered map to the lambda expression:

+
protected:
/*! Get the user's first name (accessor). */
Attribute firstName() const noexcept
{
return Attribute::make(
/* get */ [](const ModelAttributes &attributes) -> QVariant
{
auto firstName = attributes.at<QString>("first_name");

if (!firstName.isEmpty())
firstName[0] = firstName.at(0).toUpper();

return firstName;
});
}
+

The ModelAttributes container extends the std::unordered_map<QString, QVariant> and adds the at<T> method that allows you to cast the underlying QVariant value.

+

Special note should be given to the u_mutators static data member map, which maps accessors' attribute names to its methods. This data member is required because C++ does not currently support reflection.

+
info

If you would like these computed values to be added to the vector, map, or JSON representations of your model, you will need to append them.

+
danger

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.

+

Building Value From Multiple Attributes

+

Sometimes your accessor may need to transform multiple model attributes into a single value. You can use both methods described above to accomplish this:

+
using Orm::Constants::SPACE_IN;

protected:
/*! Get the user's full name (accessor). */
Attribute fullName() const noexcept
{
return Attribute::make(/* get */ [this]() -> QVariant
{
return SPACE_IN.arg(getAttribute<QString>("first_name"),
getAttribute<QString>("last_name"));
});
}
+

Or you can use the ModelAttributes overload:

+
/*! Get the user's full name (accessor). */
Attribute fullName() const noexcept
{
return Attribute::make(
/* get */ [](const ModelAttributes &attributes) -> QVariant
{
return SPACE_IN.arg(attributes.at<QString>("first_name"),
attributes.at<QString>("last_name"));
});
}
+

Accessor Caching

+

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 shouldCache method when defining your accessor:

+
using Orm::Constants::SPACE_IN;

protected:
/*! Get the user's full name (accessor). */
Attribute fullName() const noexcept
{
return Attribute::make(/* get */ [this]() -> QVariant
{
return SPACE_IN.arg(getAttribute<QString>("first_name"),
getAttribute<QString>("last_name"));
}).shouldCache();
}
+

Attribute Casting

+

Attribute casting provides functionality that allows converting model attributes to the appropriate QVariant metatype when it is accessed via your TinyORM model. The core of this functionality is a model's u_casts static data member that provides a convenient method of converting attributes' QVariant internal types to the defined cast types.

+

The u_casts static data member should be the std::unordered_map<QString, Orm::CastItem> 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:

+
    +
  • CastType::QString
  • +
  • CastType::Boolean / CastType::Bool
  • +
  • CastType::Integer / CastType::Int
  • +
  • CastType::UInteger / CastType::UInt
  • +
  • CastType::LongLong
  • +
  • CastType::ULongLong
  • +
  • CastType::Short
  • +
  • CastType::UShort
  • +
  • CastType::QDate
  • +
  • CastType::QDateTime
  • +
  • CastType::Timestamp
  • +
  • CastType::Real
  • +
  • CastType::Float
  • +
  • CastType::Double
  • +
  • +CastType::Decimal:<precision> +
  • +
  • CastType::QByteArray
  • +
+
info

The primary key name defined by the u_primaryKey model's data member is automatically cast to the CastType::ULongLong for all database drivers if the u_incrementing is set to true (its default value).

+

To demonstrate attribute casting, let's cast the is_admin attribute, which is stored in our database as an integer (0 or 1) to a QVariant(bool) value:

+
#pragma once

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! The attributes that should be cast. */
inline static std::unordered_map<QString, CastItem> u_casts {
{"is_admin", CastType::Boolean},
};
};
+

After defining the cast, the is_admin attribute will always be cast to a QVariant(bool) when you access it, even if the underlying value is stored in the database as an integer:

+
using Orm::Utils::Helpers;

auto isAdmin = User::find(1)->getAttribute("is_admin");

// Proof of the QVariant type
Q_ASSERT(Helpers::qVariantTypeId(isAdmin) == QMetaType::Bool);

if (isAdmin.value<bool>()) {
//
}
+

If you need to add a new, temporary cast at runtime, you may use the mergeCasts method. These cast definitions will be added to any of the casts already defined on the model:

+
user->mergeCasts({
{"is_paid", CastType::Boolean},
{"income", {CastType::Decimal, 2}},
});
+
warning

You should never define a cast (or an attribute) that has the same name as a relationship.

+
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 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.

+

You may customize the default serialization format for all of your model's dates or datetimes by defining a serializeDate or serializeDateTime methods on your model. These methods do not affect how your dates are formatted for storage in the database:

+
/*! 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).

+

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

+

By default, the CastType::CustomQDate and CastType::CustomQDateTime casts will serialize dates to a UTC ISO-8601 date string (yyyy-MM-ddTHH:mm:ss.zzzZ), regardless of the timezone specified in your database connection's 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 qt_timezone configuration option from its default 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.

+

If a custom format is applied to the CastType::CustomQDate or CastType::CustomQDateTime cast types, such as {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 qt_timezone configuration option.

+

Query Time Casting

+

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:

+
using Models::Post;
using Models::User;

auto users = User::select("users.*")
->addSelect(
Post::selectRaw("MAX(created_at)")
->whereColumnEq("user_id", "users.id")
.toBase(),
"last_posted_at"
).get();
+

The last_posted_at attribute on the results of this query will be a simple string. It would be wonderful if we could apply a CastType::QDateTime cast to this attribute when executing the query. Thankfully, we may accomplish this using the withCasts or withCast methods:

+
auto users = User::select("users.*")
->addSelect(Post::selectRaw("MAX(created_at)")
->whereColumnEq("user_id", "users.id")
.toBase(),
"last_posted_at")
.withCast({"last_posted_at", CastType::QDateTime})
.get();
\ No newline at end of file diff --git a/tinyorm/collections.html b/tinyorm/collections.html index 79a91747b..f9f062975 100644 --- a/tinyorm/collections.html +++ b/tinyorm/collections.html @@ -1,9 +1,9 @@ - + - -TinyORM: Collections - TinyORM + +TinyORM: Collections - TinyORM @@ -13,13 +13,47 @@ - - - + + + -
-

TinyORM: Collections

Introduction

The Orm::Tiny::Types::ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. All TinyORM methods that return more than one model result, will return instances of the ModelsCollection class, including results retrieved via the get method or methods that return relationships like the getRelation and getRelationValue.

The ModelsCollection class extends QVector<Model>, so it naturally inherits dozens of methods used to work with the underlying vector of TinyORM models. Be sure to review the QList documentation to learn all about these helpful methods!

info

The ModelsCollection template parameter can be declared only with the model type or a model type pointer, it also can't be const and can't be a reference. It's constrained using the DerivedCollectionModel concept.

You can iterate over the ModelsCollection the same way as over the QVector:

using Models::User;

ModelsCollection<User> users = User::whereEq("active", true)->get();

for (const auto &user : users)
qDebug() << user.getAttribute<QString>("name");

However, as previously mentioned, collections are much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, we may remove all active users and then gather the first name of each remaining user:

auto names = User::all().reject([](User *const user)
{
return user->getAttribute<bool>("active");
})
.pluck("name");

As you can see, the ModelsCollection class allows you to chain its methods to perform fluent mapping and reducing of the underlying vector. In general, collections are immutable, meaning every ModelsCollection method returns an entirely new ModelsCollection instance.

info

The ModelsCollection<Model> is returning from the Models' methods like get, all, findMany, chunk; the ModelsCollection<Model *> is returning from the relationship-related methods as getRelation and getRelationValue.

Collection Conversion

While most TinyORM collection methods return a new instance of ModelsCollection, the modelKeys, mapWithKeys, and pluck methods return a base QVector or std unordered/map instances. Likewise, one of the map methods overload returns the QVector<T>.

Creating Collections

Creating a ModelsCollection is as simple as:

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

You can also create a collection of pointers, eg. ModelsCollection<User *>:

ModelsCollection<User *> userPointers {
&users[0], &users[1],
};

The ModelsCollection<Model> is implicitly convertible and assignable from the QVector<Model>:

QVector<User> usersVector {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
};

ModelsCollection<User> users(usersVector);
users = usersVector;

Alternatively, you can use the Orm::collect<Model> helper function to create a ModelsCollection from the given attributes:

ModelsCollection<User> users = Orm::collect<User>({
{{"name", "Kate"}, {"added_on", QDateTime::currentDateTimeUtc()}},
{{"name", "John"}, {"added_on", QDateTime({2023, 6, 1}, {13, 46, 15}, Qt::UTC)}},
});
caution

The Orm::collect<Model> function is mandatory if your attributes contain the QDateTime instance, you can read more about this problem here.

note

The results of TinyORM queries are always returned as ModelsCollection instances.

Available Methods

For the majority of the remaining collection documentation, we'll discuss each method available on the ModelsCollection class. Remember, all of these methods may be chained to fluently manipulate the underlying vector.

Furthermore, almost every method returns a new ModelsCollection instance, allowing you to preserve the original copy of the collection when necessary:

all +

TinyORM: Collections

+ +

Introduction

+

The Orm::Tiny::Types::ModelsCollection is specialized container which provides a fluent, convenient wrapper for working with vector of models. All TinyORM methods that return more than one model result, will return instances of the ModelsCollection class, including results retrieved via the get method or methods that return relationships like the getRelation and getRelationValue.

+

The ModelsCollection class extends QVector<Model>, so it naturally inherits dozens of methods used to work with the underlying vector of TinyORM models. Be sure to review the QList documentation to learn all about these helpful methods!

+
info

The ModelsCollection template parameter can be declared only with the model type or a model type pointer, it also can't be const and can't be a reference. It's constrained using the DerivedCollectionModel concept.

+

You can iterate over the ModelsCollection the same way as over the QVector:

+
using Models::User;

ModelsCollection<User> users = User::whereEq("active", true)->get();

for (const auto &user : users)
qDebug() << user.getAttribute<QString>("name");
+

However, as previously mentioned, collections are much more powerful than vectors and expose a variety of map / reduce operations that may be chained using an intuitive interface. For example, we may remove all active users and then gather the first name of each remaining user:

+
auto names = User::all().reject([](User *const user)
{
return user->getAttribute<bool>("active");
})
.pluck("name");
+

As you can see, the ModelsCollection class allows you to chain its methods to perform fluent mapping and reducing of the underlying vector. In general, collections are immutable, meaning every ModelsCollection method returns an entirely new ModelsCollection instance.

+
info

The ModelsCollection<Model> is returning from the Models' methods like get, all, findMany, chunk; the ModelsCollection<Model *> is returning from the relationship-related methods as getRelation and getRelationValue.

+

Collection Conversion

+

While most TinyORM collection methods return a new instance of ModelsCollection, the modelKeys, mapWithKeys, and pluck methods return a base QVector or std unordered/map instances. Likewise, one of the map methods overload returns the QVector<T>.

+

Creating Collections

+

Creating a ModelsCollection is as simple as:

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

You can also create a collection of pointers, eg. ModelsCollection<User *>:

+
ModelsCollection<User *> userPointers {
&users[0], &users[1],
};
+

The ModelsCollection<Model> is implicitly convertible and assignable from the QVector<Model>:

+
QVector<User> usersVector {
{{"name", "Kate"}, {"votes", 150}},
{{"name", "John"}, {"votes", 200}},
};

ModelsCollection<User> users(usersVector);
users = usersVector;
+

Alternatively, you can use the Orm::collect<Model> helper function to create a ModelsCollection from the given attributes:

+
ModelsCollection<User> users = Orm::collect<User>({
{{"name", "Kate"}, {"added_on", QDateTime::currentDateTimeUtc()}},
{{"name", "John"}, {"added_on", QDateTime({2023, 6, 1}, {13, 46, 15}, Qt::UTC)}},
});
+
caution

The Orm::collect<Model> function is mandatory if your attributes contain the QDateTime instance, you can read more about this problem here.

+
note

The results of TinyORM queries are always returned as ModelsCollection instances.

+

Available Methods

+

For the majority of the remaining collection documentation, we'll discuss each method available on the ModelsCollection class. Remember, all of these methods may be chained to fluently manipulate the underlying vector.

+

Furthermore, almost every method returns a new ModelsCollection instance, allowing you to preserve the original copy of the collection when necessary:

+
note

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

all()

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

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

The toBase is an alias to the all method.

contains()

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

users.contains(1);

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

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

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

For the inverse of contains, see the doesntContain method.

doesntContain()

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

users.doesntContain(1);

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

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

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

For the inverse of doesntContain, see the contains method.

each()

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

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

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

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

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

// Some logic

return true;
});

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

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

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

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

except()

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

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

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

The order of models in the collection is preserved.

For the inverse of except, see the only method.

filter()

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

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

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

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

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

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

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

// {1, 2}

For the inverse of filter, see the reject method.

find()

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

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

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

User *user = users.find(anotherUser);

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

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

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

This overload internally calls the only method.

first()

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

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

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

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

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

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

firstWhere()

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

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

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

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

fresh()

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

auto usersFresh = users.fresh();

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

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

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

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

implode()

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

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

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

// {Desk, Chair}

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

isEmpty()

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

ModelsCollection<User>().isEmpty();

// true

isNotEmpty()

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

ModelsCollection<User>().isNotEmpty();

// false

last()

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

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

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

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

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

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

load()

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

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

users.load("comments.author");

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

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

map()

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

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

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

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

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

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

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

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

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

// {201, 400}

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

caution

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

info

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

mapWithKeys()

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

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

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

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

You can also map IDs to the model pointers:

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

mapWithModelKeys()

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

auto usersMap = users.mapWithModelKeys();

modelKeys()

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

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

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

// {1, 2, 3, 5}

only()

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

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

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

The order of models in the collection is preserved.

For the inverse of only, see the except method.

pluck()

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

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

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

// {Desk, Chair}

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

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

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

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

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

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

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

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

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

reject()

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

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

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

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

sort()

The sort method sorts the models collection by primary keys:

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

auto sorted = users.sort();

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

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

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

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

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

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

return leftValue < rightValue;
});

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

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

info

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

sortBy()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

sortByDesc()

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

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

sortDesc()

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

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

auto sorted = users.sortDesc();

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

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

stableSort()

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

stableSortBy()

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

stableSortByDesc()

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

stableSortDesc()

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

tap()

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

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

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

// 1

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

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

toBase()

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

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

The toBase is an alias to the all method.

toJson()

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

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

info

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

toJsonArray()

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

toJsonDocument()

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

toMap()

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

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

toMapVariantList()

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

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

note

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

toQuery()

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

using Models::User;

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

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

toVector()

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

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

toVectorVariantList()

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

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

note

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

unique()

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

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

auto unique = users.unique();

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

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

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

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

uniqueBy()

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

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

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

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

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

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

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

uniqueRelaxed()

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

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

auto unique = users.uniqueRelaxed();

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

uniqueRelaxedBy()

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

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

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

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

value()

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

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

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

// 200

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

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

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

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

// 0

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

where()

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

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

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

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

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

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

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

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

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

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

whereBetween()

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

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

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

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

whereIn()

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

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

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

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

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

The order of models in the collection is preserved.

whereNotBetween()

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

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

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

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

whereNotIn()

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

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

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

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

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

The order of models in the collection is preserved.

whereNotNull()

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

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

whereNull()

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

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

- - +whereNull

+
note

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

+

all()

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

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

The toBase is an alias to the all method.

contains()

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

users.contains(1);

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

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

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

For the inverse of contains, see the doesntContain method.

doesntContain()

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

users.doesntContain(1);

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

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

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

For the inverse of doesntContain, see the contains method.

each()

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

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

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

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

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

// Some logic

return true;
});

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

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

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

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

except()

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

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

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

The order of models in the collection is preserved.

For the inverse of except, see the only method.

filter()

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

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

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

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

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

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

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

// {1, 2}

For the inverse of filter, see the reject method.

find()

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

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

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

User *user = users.find(anotherUser);

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

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

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

This overload internally calls the only method.

first()

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

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

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

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

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

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

firstWhere()

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

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

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

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

fresh()

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

auto usersFresh = users.fresh();

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

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

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

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

implode()

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

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

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

// {Desk, Chair}

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

isEmpty()

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

ModelsCollection<User>().isEmpty();

// true

isNotEmpty()

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

ModelsCollection<User>().isNotEmpty();

// false

last()

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

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

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

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

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

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

load()

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

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

users.load("comments.author");

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

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

map()

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

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

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

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

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

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

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

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

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

// {201, 400}

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

caution

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

info

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

mapWithKeys()

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

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

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

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

You can also map IDs to the model pointers:

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

mapWithModelKeys()

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

auto usersMap = users.mapWithModelKeys();

modelKeys()

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

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

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

// {1, 2, 3, 5}

only()

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

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

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

The order of models in the collection is preserved.

For the inverse of only, see the except method.

pluck()

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

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

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

// {Desk, Chair}

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

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

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

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

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

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

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

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

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

reject()

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

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

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

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

sort()

The sort method sorts the models collection by primary keys:

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

auto sorted = users.sort();

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

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

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

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

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

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

return leftValue < rightValue;
});

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

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

info

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

sortBy()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

sortByDesc()

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

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

sortDesc()

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

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

auto sorted = users.sortDesc();

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

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

stableSort()

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

stableSortBy()

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

stableSortByDesc()

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

stableSortDesc()

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

tap()

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

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

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

// 1

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

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

toBase()

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

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

The toBase is an alias to the all method.

toJson()

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

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

info

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

toJsonArray()

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

toJsonDocument()

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

toMap()

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

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

toMapVariantList()

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

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

note

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

toQuery()

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

using Models::User;

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

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

toVector()

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

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

toVectorVariantList()

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

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

note

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

unique()

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

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

auto unique = users.unique();

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

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

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

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

uniqueBy()

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

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

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

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

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

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

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

uniqueRelaxed()

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

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

auto unique = users.uniqueRelaxed();

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

uniqueRelaxedBy()

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

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

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

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

value()

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

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

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

// 200

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

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

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

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

// 0

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

where()

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

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

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

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

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

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

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

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

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

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

whereBetween()

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

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

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

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

whereIn()

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

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

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

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

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

The order of models in the collection is preserved.

whereNotBetween()

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

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

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

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

whereNotIn()

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

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

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

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

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

The order of models in the collection is preserved.

whereNotNull()

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

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

whereNull()

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

#include <orm/utils/nullvariant.hpp>

using NullVariant = Orm::Utils::NullVariant;

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

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

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

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

\ No newline at end of file diff --git a/tinyorm/getting-started.html b/tinyorm/getting-started.html index 7cf005eb7..482d70326 100644 --- a/tinyorm/getting-started.html +++ b/tinyorm/getting-started.html @@ -1,9 +1,9 @@ - + - -TinyORM: Getting Started - TinyORM + +TinyORM: Getting Started - TinyORM @@ -13,14 +13,284 @@ - - - + + + -
-

TinyORM: Getting Started

Introduction

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.

note

Before getting started, be sure to configure a database connection in your application. For more information on configuring your database, check out the database configuration documentation.

tip

If you want to see a model in which are used all possible TinyORM features you can look at the torrent.hpp in the TinyORM's tests, this Models::Torrent class serves also as a showcase, so all possible features are defined in it.

Generating Model Classes

To get started, let's create the simplest TinyORM model. Models typically live in the database\models directory and extend the Orm::Tiny::Model class. You may use the make:model command to generate a new model:

tom make:model User

If you would like to generate a database migration or seeder when you generate the model, you may use the --migration/-m or --seeder/-s options:

tom make:model User --migration --seeder

The --force option forces overwriting of existing files:

tom make:model User --migration --seeder --force

The make:model is king 👑 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 make:model help command:

tom make:model --help

Few examples:

# Setting some model attributes
tom make:model User --table=users --fillable=name,email,banned_at `
--guarded=password --dates=banned_at

# Generate relationship methods
tom make:model User --one-to-one=Passport `
--one-to-many=Post --foreign-key=post_id `
--one-to-many=Car

# Generate a basic many-to-many relationship
tom make:model User --belongs-to-many=Tag --with-timestamps

# Generate a many-to-many relationship
tom make:model User --belongs-to-many=Tag --foreign-key=tag_id `
--pivot-table=user_tag --as=tagged `
--with-pivot=active,soft --with-timestamps `
--pivot=Tagged

# Generate a pivot model
tom make:model Tagged --pivot-model
tom make:model Tagged --pivot-model --incrementing
tip

Writing a make:model commands is superb with the tab completion.

note

The --path and --realpath options work the same as for the make:migration command.

TinyORM Model Conventions

Let's examine a basic model class and discuss some of TinyORM's key conventions:

#pragma once
#ifndef FLIGHT_HPP
#define FLIGHT_HPP

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;

using Model::Model;
};

#endif // FLIGHT_HPP
tip

The TinyORM source tree contains the 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.

Table Names

After glancing at the example above, you may have noticed that we did not tell TinyORM which database table corresponds to our 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 Flight model stores records in the flights table, while an AirTrafficController model would store records in an air_traffic_controllers table.

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 u_table data member on the model:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The table associated with the model. */
QString u_table {"flights"};
};

Primary Keys

TinyORM will also assume that each model's corresponding database table has a primary key column named id. If necessary, you may define a private u_primaryKey data member on your model to specify a different column that serves as your model's primary key:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The primary key associated with the table. */
QString u_primaryKey {"id"};
};

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 u_incrementing data member on your model that is set to false:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! Indicates if the model's ID is auto-incrementing. */
bool u_incrementing = false;
};
caution

Non-numeric primary keys are not currently implemented, u_incrementing code logic is fully implemented, but it is only one part to make it fully work.

"Composite" Primary Keys

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.

Timestamps

By default, TinyORM expects created_at and 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 u_timestamps data member on your model with a value of false:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! Indicates if the model should be timestamped. */
bool u_timestamps = false;
};

The u_dates static data member controls the casting of timestamp attributes. The created_at and updated_at columns are automatically added to the u_dates string list when the u_timestamps is true. Also, the Soft Deleting feature adds the deleted_at column to the u_dates.

You may add additional columns to the u_dates list. After that, these columns will be automatically formatted using the format in the u_dateFormat data member during the setAttribute method call:

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The attributes that should be mutated to dates. */
inline static const QStringList u_dates {"departure_at"};
};

If you need to customize the format of your model's timestamps, set the private 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 QDateTime documentation:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The storage format of the model's date columns. */
QString u_dateFormat {"yyyy-MM-dd HH:mm:ss"};
};

If you need to customize the format of your model's time columns, set the private 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 QTime documentation. The default value for u_timeFormat is HH:mm:ss:

/*! 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:

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:

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:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The name of the "created at" column. */
static QString CREATED_AT() { return QStringLiteral("creation_date"); }
/*! The name of the "updated at" column. */
static QString UPDATED_AT() { return QStringLiteral("updated_date"); }
};

Touching timestamps

You can explicitly touch timestamps using the touch method defined on the Model:

auto flight = Flight::find(1);

flight->touch();
flight->touch("added_on"); // Custom column name

You can also touch multiple rows at once using the touch method defined on the TinyBuilder:

auto [affected, query] = Flight::whereEq("status", "new")->touch();

The touch method may also be called when building a relationship query:

flight->history()->touch();
flight->history()->whereEq("status", "new").touch();

Database Connections

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 u_connection private data member on the model:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The database connection that should be used by the model. */
QString u_connection {"sqlite"};
};

In special cases, when you want to query the database through a different connection, you can use Model::on method, which takes the connection name as the first argument:

auto user = User::on("sqlite")->find(1);

Default Attribute Values

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 u_attributes data member on your model, it has to be static and can be const:

#include <QDateTime>

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The model's default values for attributes. */
inline static const QVector<AttributeItem> u_attributes {
{"delayed", false},
{"progress", 0},
{"added_on", QDateTime::currentDateTimeUtc()},
};
};
caution

Use the Model::instance or Model::instanceHeap related methods to instantiate a model that contains a QDateTime in Default Attribute Values, or if attributes you want to pass to the model's constructor contain a QDateTime instance (problem is described below).

QDateTime and connection name problem

If your Default Attribute Values or attributes that you can pass to the Model constructor contain the QDateTime instance, then TinyORM throws an exception. You have to use the Model::instance related methods to create such a Model.

Virtually everything important is covered in the thrown exception, but let me summarize it. The problem is that the QDateTime instance is converted to a string based on the Model::u_dateFormat, or if not defined, the date format from Orm::Query::Grammars::Grammar will be used. This QueryGrammar is obtained from Orm::DatabaseConnection and because of that TinyORM needs to know the connection name and that's the crux of this problem. You can define your connection name using the Model::u_connection in your derived model class, but this derived model is not yet initialized, so the Model::u_connection is also not initialized.

So if the Model::u_connection is not yet initialized, TinyORM can't obtain the Orm::DatabaseConnection -> QueryGrammar -> dateFormat.

Retrieving Models

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 query builder allowing you to fluently query the database table associated with the model. The model's all method will retrieve all of the records from the model's associated database table:

#include <QDebug>

#include "models/flight.hpp"

for (const auto &flight : Flight::all())
qDebug() << flight["name"].toString();

Building Queries

The TinyORM all method will return all of the results in the model's table. However, since each TinyORM model serves as a query builder, you may add additional constraints to queries and then invoke the get method to retrieve the results:

auto flights = Flight::whereEq("active", 1)
->orderBy("name")
.take(10)
.get();
tip

Since TinyORM models are query builders, you should review all of the methods provided by TinyORM's query builder. You may use any of these methods when writing your TinyORM queries.

note

All the static methods defined on the Orm::Tiny::Model<Derived, AllRelations...> class, which start building queries like where, latest, oldest, with, ... return std::unique_ptr<TinyBuilder<Model>>, TinyBuilder = Orm::Tiny::Builder and Model template argument is queried model class.

Refreshing Models

If you already have an instance of the TinyORM model that was retrieved from the database, you can "refresh" the model using the fresh and refresh methods. The fresh method will re-retrieve the model from the database. The existing model instance will not be affected:

auto flight = Flight::whereEq("number", "FR 900")->first();

auto freshFlight = flight->fresh();

The 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:

auto flight = Flight::whereEq("number", "FR 900")->first();

flight->setAttribute("number", "FR 456");

flight->refresh();

flight->getAttribute("number"); // "FR 900"

Containers

As we have seen, TinyORM methods like all and get retrieve multiple records from the database. Since these methods return a QVector<Model>, you can iterate it like any other container with the Range-based for loop, STL-Style Iterators, Java-Style Iterators or Ranges.

#include <QDebug>

#include "models/flight.hpp"

for (const auto &flight : Flight::all())
qDebug() << flight["name"].toString();
note

An all method is defined on the Orm::Tiny::Model<Derived, AllRelations...> class and get method is defined on the Orm::Tiny::Builder, may be also referred as TinyBuilder, and on the Orm::Query::Builder alias QueryBuilder.

Chunking Results

Your application may run out of memory if you attempt to load tens of thousands of TinyORM records via the all or get methods. Instead of using these methods, the chunk method may be used to process large numbers of models more efficiently.

The 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 chunk method will provide significantly reduced memory usage when working with a large number of models:

Flight::chunk(200, [](QVector<Flight> &&flights, const int /*unused*/)
{
for (auto &&flight : flights) {
//
}

return true;
});

The first argument passed to the 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.

If you are filtering the results of the chunk method based on a column that you will also be updating while iterating over the results, you should use the chunkById method. Using the chunk method in these scenarios could lead to unexpected and inconsistent results. Internally, the chunkById method will always retrieve models with an id column greater than the last model in the previous chunk:

Flight::whereEq("departed", true)
->chunkById(200, [](QVector<Flight> &&flights, const int /*unused*/)
{
for (auto &&flight : flights)
flight.update({{"departed", false}});

return true;
});

Advanced Subqueries

Subquery Selects

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 destinations and a table of flights to destinations. The flights table contains an arrived_at column which indicates when the flight arrived at the destination.

Using the subquery functionality available to the query builder's select and addSelect methods, we can select all of the destinations and the name of the flight that most recently arrived at that destination using a single query:

#include "models/destination.hpp"
#include "models/flight.hpp"

return Destination::addSelect(
Flight::select("name")
->whereColumnEq("destination_id", "destinations.id")
.orderByDesc("arrived_at")
.limit(1)
.toBase(),
"last_flight")
->get();

Subquery Ordering

In addition, the query builder's 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:

return Destination::orderByDesc(
Flight::select("arrived_at")
->whereColumnEq("destination_id", "destinations.id")
.orderByDesc("arrived_at")
.limit(1)
.toBase())
->get();

Retrieving Single Models / Aggregates

In addition to retrieving all of the records matching a given query, you may also retrieve single records using the find, first, firstWhere, or firstWhereEq methods. Instead of returning a vector of models, these methods return a single model instance:

#include "models/flight.hpp"

// Retrieve a model by its primary key...
auto flight = Flight::find(1);

// Retrieve the first model matching the query constraints...
auto flight = Flight::whereEq("active", 1)->first();

// Alternative to retrieving the first model matching the query constraints...
auto flight = Flight::firstWhere("active", "=", 1);

// Alternative firstWhere method syntax
auto flight = Flight::firstWhereEq("active", 1);

Sometimes you may wish to perform some other action if no results are found. The 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:

auto flight = Flight::findOr(1, [] {
// ...
});

auto flight = Flight::findOr<int>(1, [] {
// ...
return 10;
});

auto flight = Flight::findOr<std::optional<Flight>>(1, [] {
// ...
return Flight::find(10);
});

To obtain only a subset of the model's attributes you may use the Model::only method, it returns the QVector<AttributeItem>:

#include "models/flight.hpp"

using Orm::Constants::ID;
using Orm::Constants::NAME;

auto flight = Flight::find(1);

auto attributes = flight->only({ID, NAME});

Not Found Exceptions

Sometimes you may wish to throw an exception if a model is not found. The findOrFail and firstOrFail methods will retrieve the first result of the query; however, if no result is found, an Orm::Tiny::ModelNotFoundError will be thrown:

auto flight = Flight::findOrFail(1);

auto flight = Flight::where("legs", ">", 3)->firstOrFail();

Retrieving Or Creating Models

The 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 QVector<Orm::WhereItem> argument with the optional second QVector<Orm::AttributeItem> argument:

The firstOrNew method, like 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 firstOrNew has not yet been persisted to the database. You will need to manually call the save method to persist it:

#include "models/flight.hpp"

// Retrieve flight by name or create it if it doesn't exist...
auto flight = Flight::firstOrCreate({
{"name", "London to Paris"}
});

// Retrieve flight by name or create it with the name, delayed, and arrival_time attributes...
auto flight = Flight::firstOrCreate(
{{"name", "London to Paris"}},
{{"delayed", 1}, {"arrival_time", "11:30"}}
);

// Retrieve flight by name or instantiate a new Flight instance...
auto flight = Flight::firstOrNew({
{"name", "London to Paris"}
});

// Retrieve flight by name or instantiate with the name, delayed, and arrival_time attributes...
auto flight = Flight::firstOrNew(
{{"name", "Tokyo to Sydney"}},
{{"delayed", 1}, {"arrival_time", "11:30"}}
);

Retrieving Aggregates

When interacting with TinyORM models, you may also use the count, sum, max, and other aggregate methods provided by the query builder. As you might expect, these methods return a scalar value instead of a TinyORM model instance:

auto count = Flight::whereEq("active", 1)->count();

auto max = Flight::whereEq("active", 1)->max("price");

Inserting & Updating Models

Inserts

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 save method on the model instance:

#include "models/flight.hpp"

// Store a new flight in the database
Flight flight;
flight.setAttribute("name", "Slovakia to Czech");
flight.save();

In this example, we assign the name attribute of the Flight model instance. When we call the save method, a record will be inserted into the database. The model's created_at and updated_at timestamps will automatically be set when the save method is called, so there is no need to set them manually.

Alternatively, you may use the create method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the create method:

#include "models/flight.hpp"

auto flight = Flight::create({
{"name", "London to Paris"},
});

However, before using the create method, you will need to specify either a u_fillable or 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 mass assignment documentation.

Updates

The 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 save method. Again, the updated_at timestamp will automatically be updated, so there is no need to manually set its value:

#include "models/flight.hpp"

auto flight = Flight::find(1);

flight->setAttribute("name", "Paris to London");

flight->save();

Mass Updates

Updates can also be performed against models that match a given query. In this example, all flights that are active and have a destination of San Diego will be marked as delayed:

Flight::whereEq("active", 1)
->whereEq("destination", "San Diego")
.update({{"delayed", 1}});

The update method expects the QVector<Orm::UpdateItem> of column and value pairs representing the columns that should be updated.

Examining Attribute Changes

TinyORM provides the isDirty, isClean, and wasChanged methods to examine the internal state of your model and determine how its attributes have changed from when the model was originally retrieved.

The 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 isDirty method to determine if a particular attribute is dirty. The isClean will determine if an attribute has remained unchanged since the model was retrieved. This method also accepts an optional attribute argument:

#include "models/user.hpp"

auto user = User::create({
{"first_name", "Silver"},
{"last_name", "Zachara"},
{"title", "Developer"},
});

user.setAttribute("title", "Painter");

user.isDirty(); // true
user.isDirty("title"); // true
user.isDirty("first_name"); // false

user.isClean(); // false
user.isClean("title"); // false
user.isClean("first_name"); // true

user.save();

user.isDirty(); // false
user.isClean(); // true

The 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:

auto user = User::create({
{"first_name", "Silver"},
{"last_name", "Zachara"},
{"title", "Developer"},
});

user.setAttribute("title", "Painter");

user.wasChanged(); // false

user.save();

user.wasChanged(); // true
user.wasChanged("title"); // true
user.wasChanged("first_name"); // false

Mass Assignment

You may use the create method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the method:

#include "models/flight.hpp"

auto flight = Flight::create({
{"name", "London to Paris"},
});

However, before using the create method, you will need to specify either a u_fillable or 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.

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 is_admin parameter through an HTTP request, which is then passed to your model's create method, allowing the user to escalate themselves to an administrator.

So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the u_fillable static data member on the model. For example, let's make the name attribute of our Flight model mass assignable:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;

using Model::Model;

/*! The attributes that are mass assignable. */
inline static QStringList u_fillable {
"name",
};
};

Once you have specified which attributes are mass assignable, you may use the create method to insert a new record in the database. The create method returns the newly created model instance:

auto flight = Flight::create({{"name", "London to Paris"}});

If you already have a model instance, you may use the fill method to populate it with the vector of attributes:

flight.fill({{"name", "Amsterdam to Frankfurt"}});

Allowing Mass Assignment

If you would like to make all of your attributes mass assignable, you may define your model's 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 fill, create, and update methods:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;

using Model::Model;

/*! The attributes that aren't mass assignable. */
inline static QStringList u_guarded {};
};

Upserts

Occasionally, you may need to update an existing model or create a new model if no matching model exists.

In the example below, if a flight exists with a departure location of Oakland and a destination location of San Diego, its price and 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:

auto flight = Flight::updateOrCreate(
{{"departure", "Oakland"}, {"destination", "San Diego"}},
{{"price", 99}, {"discounted", 1}}
);
note

The firstOrCreate and updateOrCreate methods persist the model, so there's no need to manually call the save method.

If you would like to perform multiple "upserts" in a single query, then you should use the 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 upsert method will automatically set the created_at and updated_at timestamps if timestamps are enabled on the model:

Flight::upsert(
{{{"departure", "Oakland"}, {"destination", "San Diego"}, {"price", 99}},
{{"departure", "Chicago"}, {"destination", "New York"}, {"price", 150}}},
{"departure", "destination"},
{"price"}
);
caution

All databases except SQL Server require the columns in the second argument of the upsert method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the upsert method and always uses the "primary" and "unique" indexes of the table to detect existing records.

info

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 documentation. The MySQL server version is auto-detected and can be overridden in the configuration.

Deleting Models

To delete a model, you may call the remove, or an alias deleteRow method on the model instance:

#include "models/flight.hpp"

auto flight = Flight::find(1);

flight->remove();

Deleting An Existing Model By Its Primary Key

In the example above, we are retrieving the model from the database before calling the remove method. However, if you know the primary key of the model, you may delete the model without explicitly retrieving it by calling the destroy method. In addition to accepting the single primary key, the destroy method can accept multiple primary keys:

Flight::destroy(1);

Flight::destroy({1, 2, 3});
note

The destroy method loads models from the database and calls the remove method on each model individually, the reason for this is future compatibility with events.

Deleting Models Using Queries

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:

auto deletedRows = Flight::whereEq("active", 0)->remove();

Soft Deleting

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 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 Orm::Tiny::SoftDeletes base class to the model:

#include <orm/tiny/model.hpp>
#include <orm/tiny/softdeletes.hpp>

using Orm::Tiny::Model;
using Orm::Tiny::SoftDeletes;

class Flight final : public Model<Flight>,
public SoftDeletes<Flight>
{
friend Model;
using Model::Model;

private:
/*! The table associated with the model. */
QString u_table {"flights"};
};
info

The SoftDeletes base class will automatically cast the deleted_at attribute to the QDateTime instance for you (it adds the deleted_at column to the model's u_dates list).

You should also add the deleted_at column to your database table. The TinyORM schema builder contains a helper method to create this column:

Schema::table("flights", [](Blueprint &table)
{
table.softDeletes();
});

Schema::table("flights", [](Blueprint &table)
{
table.dropSoftDeletes();
});

Now, when you call the remove or deleteModel method on the model, the 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.

To determine if a given model instance has been soft deleted, you may use the trashed method:

if (flight->trashed()) {
//
}

Restoring Soft Deleted Models

Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model, you may call the restore method on a model instance. The restore method will set the model's deleted_at column to null:

flight->restore();

You may also use the restore method in a query to restore multiple models:

Flight::withTrashed()
->whereEq("airline_id", 1)
.restore();

The restore method may also be used when building relationship queries:

flight->history()->restore();

Permanently Deleting Models

Sometimes you may need to truly remove a model from your database. You may use the forceDelete method (or it's alias forceRemove) to permanently remove a soft deleted model from the database table:

flight->forceDelete();

You may also use the forceDelete method when building TinyORM relationship queries:

flight->history()->forceDelete();

Querying Soft Deleted Models

Including Soft Deleted Models

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 withTrashed method on the query:

auto flights = Flight::withTrashed()
->whereEq("account_id", 1)
.get();

The withTrashed method may also be called when building a relationship query:

flight->history()->withTrashed().get();

Retrieving Only Soft Deleted Models

The onlyTrashed method will retrieve only soft deleted models:

auto flights = Flight::onlyTrashed()
->whereEq("airline_id", 1)
.get();

The onlyTrashed method may also be called when building a relationship query:

flight->history()->onlyTrashed().get();

Excluding Soft Deleted Models

As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be excluded in a query's results by calling the withoutTrashed method on the query:

auto flights = Flight::withoutTrashed()
->whereEq("account_id", 1)
.get();

The withoutTrashed method may also be called when building a relationship query:

flight->history()->withoutTrashed().get();

Truncate Table

You may call the truncate method to delete all of the model's associated database records. The truncate operation will also reset any auto-incrementing IDs on the model's associated table:

Flight::truncate();

Replicating Models

You may create an unsaved copy of an existing model instance using the replicate method. This method is particularly useful when you have model instances that share many of the same attributes:

auto shipping = Address::create({
{"type", "shipping"},
{"line_1", "123 Example Street"},
{"city", "Victorville"},
{"state", "CA"},
{"postcode", "90001"},
});

auto billing = shipping.replicate();

billing.fill({
{"type", "billing"},
});

billing.save();

To exclude one or more attributes from being replicated to the new model, you may pass an unordered_set to the replicate method:

auto flight = Flight::create({
{"destination", "LAX"},
{"origin", "LHR"},
{"last_flown", "2020-03-04 11:00:00"},
{"last_pilot_id", 747},
});

flight = flight.replicate({
"last_flown",
"last_pilot_id",
});

Comparing Models

Sometimes you may need to determine if two models are the "same" or not. The is and isNot methods may be used to quickly verify two models have the same primary key, table, and database connection or not:

if (post->is(anotherPost)) {
//
}

if (post->isNot(anotherPost)) {
//
}

The is and isNot methods are also available when using the belongsTo and hasOne relationships. This method is particularly helpful when you would like to compare a related model without issuing a query to retrieve that model:

if (post->author()->is(user)) {
//
}
Equality comparison

The base Model class also defines the 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 model1 == model2 expression guarantees that these two models are exactly the same.

It would be appropriate to mention that this comparison also includes relations, which means it will also compare all models (including their data members) these relations contain.

- - +

TinyORM: Getting Started

+ +

Introduction

+

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.

+
note

Before getting started, be sure to configure a database connection in your application. For more information on configuring your database, check out the database configuration documentation.

+
tip

If you want to see a model in which are used all possible TinyORM features you can look at the torrent.hpp in the TinyORM's tests, this Models::Torrent class serves also as a showcase, so all possible features are defined in it.

+

Generating Model Classes

+

To get started, let's create the simplest TinyORM model. Models typically live in the database\models directory and extend the Orm::Tiny::Model class. You may use the make:model command to generate a new model:

+
tom make:model User
+

If you would like to generate a database migration or seeder when you generate the model, you may use the --migration/-m or --seeder/-s options:

+
tom make:model User --migration --seeder
+

The --force option forces overwriting of existing files:

+
tom make:model User --migration --seeder --force
+

The make:model is king 👑 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 make:model help command:

+
tom make:model --help
+

Few examples:

+
# Setting some model attributes
tom make:model User --table=users --fillable=name,email,banned_at `
--guarded=password --dates=banned_at

# Generate relationship methods
tom make:model User --one-to-one=Passport `
--one-to-many=Post --foreign-key=post_id `
--one-to-many=Car

# Generate a basic many-to-many relationship
tom make:model User --belongs-to-many=Tag --with-timestamps

# Generate a many-to-many relationship
tom make:model User --belongs-to-many=Tag --foreign-key=tag_id `
--pivot-table=user_tag --as=tagged `
--with-pivot=active,soft --with-timestamps `
--pivot=Tagged

# Generate a pivot model
tom make:model Tagged --pivot-model
tom make:model Tagged --pivot-model --incrementing
+
tip

Writing a make:model commands is superb with the tab completion.

+
note

The --path and --realpath options work the same as for the make:migration command.

+

TinyORM Model Conventions

+

Let's examine a basic model class and discuss some of TinyORM's key conventions:

+
#pragma once
#ifndef FLIGHT_HPP
#define FLIGHT_HPP

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;

using Model::Model;
};

#endif // FLIGHT_HPP
+
tip

The TinyORM source tree contains the 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.

+

Table Names

+

After glancing at the example above, you may have noticed that we did not tell TinyORM which database table corresponds to our 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 Flight model stores records in the flights table, while an AirTrafficController model would store records in an air_traffic_controllers table.

+

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 u_table data member on the model:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The table associated with the model. */
QString u_table {"flights"};
};
+

Primary Keys

+

TinyORM will also assume that each model's corresponding database table has a primary key column named id. If necessary, you may define a private u_primaryKey data member on your model to specify a different column that serves as your model's primary key:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The primary key associated with the table. */
QString u_primaryKey {"id"};
};
+

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 u_incrementing data member on your model that is set to false:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! Indicates if the model's ID is auto-incrementing. */
bool u_incrementing = false;
};
+
caution

Non-numeric primary keys are not currently implemented, u_incrementing code logic is fully implemented, but it is only one part to make it fully work.

+

"Composite" Primary Keys

+

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.

+

Timestamps

+

By default, TinyORM expects created_at and 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 u_timestamps data member on your model with a value of false:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! Indicates if the model should be timestamped. */
bool u_timestamps = false;
};
+ +

The u_dates static data member controls the casting of timestamp attributes. The created_at and updated_at columns are automatically added to the u_dates string list when the u_timestamps is true. Also, the Soft Deleting feature adds the deleted_at column to the u_dates.

+

You may add additional columns to the u_dates list. After that, these columns will be automatically formatted using the format in the u_dateFormat data member during the setAttribute method call:

+
class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The attributes that should be mutated to dates. */
inline static const QStringList u_dates {"departure_at"};
};
+

If you need to customize the format of your model's timestamps, set the private 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 QDateTime documentation:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The storage format of the model's date columns. */
QString u_dateFormat {"yyyy-MM-dd HH:mm:ss"};
};
+

If you need to customize the format of your model's time columns, set the private 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 QTime documentation. The default value for u_timeFormat is HH:mm:ss:

+
/*! 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:

+
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:

+
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:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The name of the "created at" column. */
static QString CREATED_AT() { return QStringLiteral("creation_date"); }
/*! The name of the "updated at" column. */
static QString UPDATED_AT() { return QStringLiteral("updated_date"); }
};
+

Touching timestamps

+

You can explicitly touch timestamps using the touch method defined on the Model:

+
auto flight = Flight::find(1);

flight->touch();
flight->touch("added_on"); // Custom column name
+

You can also touch multiple rows at once using the touch method defined on the TinyBuilder:

+
auto [affected, query] = Flight::whereEq("status", "new")->touch();
+

The touch method may also be called when building a relationship query:

+
flight->history()->touch();
flight->history()->whereEq("status", "new").touch();
+

Database Connections

+

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 u_connection private data member on the model:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The database connection that should be used by the model. */
QString u_connection {"sqlite"};
};
+

In special cases, when you want to query the database through a different connection, you can use Model::on method, which takes the connection name as the first argument:

+
auto user = User::on("sqlite")->find(1);
+

Default Attribute Values

+

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 u_attributes data member on your model, it has to be static and can be const:

+
#include <QDateTime>

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;
using Model::Model;

private:
/*! The model's default values for attributes. */
inline static const QVector<AttributeItem> u_attributes {
{"delayed", false},
{"progress", 0},
{"added_on", QDateTime::currentDateTimeUtc()},
};
};
+
caution

Use the Model::instance or Model::instanceHeap related methods to instantiate a model that contains a QDateTime in Default Attribute Values, or if attributes you want to pass to the model's constructor contain a QDateTime instance (problem is described below).

+
QDateTime and connection name problem
+

If your Default Attribute Values or attributes that you can pass to the Model constructor contain the QDateTime instance, then TinyORM throws an exception. You have to use the Model::instance related methods to create such a Model.

+

Virtually everything important is covered in the thrown exception, but let me summarize it. The problem is that the QDateTime instance is converted to a string based on the Model::u_dateFormat, or if not defined, the date format from Orm::Query::Grammars::Grammar will be used. This QueryGrammar is obtained from Orm::DatabaseConnection and because of that TinyORM needs to know the connection name and that's the crux of this problem. You can define your connection name using the Model::u_connection in your derived model class, but this derived model is not yet initialized, so the Model::u_connection is also not initialized.

+

So if the Model::u_connection is not yet initialized, TinyORM can't obtain the Orm::DatabaseConnection -> QueryGrammar -> dateFormat.

+

Retrieving Models

+

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 query builder allowing you to fluently query the database table associated with the model. The model's all method will retrieve all of the records from the model's associated database table:

+
#include <QDebug>

#include "models/flight.hpp"

for (const auto &flight : Flight::all())
qDebug() << flight["name"].toString();
+

Building Queries

+

The TinyORM all method will return all of the results in the model's table. However, since each TinyORM model serves as a query builder, you may add additional constraints to queries and then invoke the get method to retrieve the results:

+
auto flights = Flight::whereEq("active", 1)
->orderBy("name")
.take(10)
.get();
+
tip

Since TinyORM models are query builders, you should review all of the methods provided by TinyORM's query builder. You may use any of these methods when writing your TinyORM queries.

+
note

All the static methods defined on the Orm::Tiny::Model<Derived, AllRelations...> class, which start building queries like where, latest, oldest, with, ... return std::unique_ptr<TinyBuilder<Model>>, TinyBuilder = Orm::Tiny::Builder and Model template argument is queried model class.

+

Refreshing Models

+

If you already have an instance of the TinyORM model that was retrieved from the database, you can "refresh" the model using the fresh and refresh methods. The fresh method will re-retrieve the model from the database. The existing model instance will not be affected:

+
auto flight = Flight::whereEq("number", "FR 900")->first();

auto freshFlight = flight->fresh();
+

The 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:

+
auto flight = Flight::whereEq("number", "FR 900")->first();

flight->setAttribute("number", "FR 456");

flight->refresh();

flight->getAttribute("number"); // "FR 900"
+

Containers

+

As we have seen, TinyORM methods like all and get retrieve multiple records from the database. Since these methods return a QVector<Model>, you can iterate it like any other container with the Range-based for loop, STL-Style Iterators, Java-Style Iterators or Ranges.

+
#include <QDebug>

#include "models/flight.hpp"

for (const auto &flight : Flight::all())
qDebug() << flight["name"].toString();
+
note

An all method is defined on the Orm::Tiny::Model<Derived, AllRelations...> class and get method is defined on the Orm::Tiny::Builder, may be also referred as TinyBuilder, and on the Orm::Query::Builder alias QueryBuilder.

+

Chunking Results

+

Your application may run out of memory if you attempt to load tens of thousands of TinyORM records via the all or get methods. Instead of using these methods, the chunk method may be used to process large numbers of models more efficiently.

+

The 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 chunk method will provide significantly reduced memory usage when working with a large number of models:

+
Flight::chunk(200, [](QVector<Flight> &&flights, const int /*unused*/)
{
for (auto &&flight : flights) {
//
}

return true;
});
+

The first argument passed to the 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.

+

If you are filtering the results of the chunk method based on a column that you will also be updating while iterating over the results, you should use the chunkById method. Using the chunk method in these scenarios could lead to unexpected and inconsistent results. Internally, the chunkById method will always retrieve models with an id column greater than the last model in the previous chunk:

+
Flight::whereEq("departed", true)
->chunkById(200, [](QVector<Flight> &&flights, const int /*unused*/)
{
for (auto &&flight : flights)
flight.update({{"departed", false}});

return true;
});
+

Advanced Subqueries

+

Subquery Selects

+

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 destinations and a table of flights to destinations. The flights table contains an arrived_at column which indicates when the flight arrived at the destination.

+

Using the subquery functionality available to the query builder's select and addSelect methods, we can select all of the destinations and the name of the flight that most recently arrived at that destination using a single query:

+
#include "models/destination.hpp"
#include "models/flight.hpp"

return Destination::addSelect(
Flight::select("name")
->whereColumnEq("destination_id", "destinations.id")
.orderByDesc("arrived_at")
.limit(1)
.toBase(),
"last_flight")
->get();
+

Subquery Ordering

+

In addition, the query builder's 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:

+
return Destination::orderByDesc(
Flight::select("arrived_at")
->whereColumnEq("destination_id", "destinations.id")
.orderByDesc("arrived_at")
.limit(1)
.toBase())
->get();
+

Retrieving Single Models / Aggregates

+

In addition to retrieving all of the records matching a given query, you may also retrieve single records using the find, first, firstWhere, or firstWhereEq methods. Instead of returning a vector of models, these methods return a single model instance:

+
#include "models/flight.hpp"

// Retrieve a model by its primary key...
auto flight = Flight::find(1);

// Retrieve the first model matching the query constraints...
auto flight = Flight::whereEq("active", 1)->first();

// Alternative to retrieving the first model matching the query constraints...
auto flight = Flight::firstWhere("active", "=", 1);

// Alternative firstWhere method syntax
auto flight = Flight::firstWhereEq("active", 1);
+

Sometimes you may wish to perform some other action if no results are found. The 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:

+
auto flight = Flight::findOr(1, [] {
// ...
});

auto flight = Flight::findOr<int>(1, [] {
// ...
return 10;
});

auto flight = Flight::findOr<std::optional<Flight>>(1, [] {
// ...
return Flight::find(10);
});
+

To obtain only a subset of the model's attributes you may use the Model::only method, it returns the QVector<AttributeItem>:

+
#include "models/flight.hpp"

using Orm::Constants::ID;
using Orm::Constants::NAME;

auto flight = Flight::find(1);

auto attributes = flight->only({ID, NAME});
+

Not Found Exceptions

+

Sometimes you may wish to throw an exception if a model is not found. The findOrFail and firstOrFail methods will retrieve the first result of the query; however, if no result is found, an Orm::Tiny::ModelNotFoundError will be thrown:

+
auto flight = Flight::findOrFail(1);

auto flight = Flight::where("legs", ">", 3)->firstOrFail();
+

Retrieving Or Creating Models

+

The 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 QVector<Orm::WhereItem> argument with the optional second QVector<Orm::AttributeItem> argument:

+

The firstOrNew method, like 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 firstOrNew has not yet been persisted to the database. You will need to manually call the save method to persist it:

+
#include "models/flight.hpp"

// Retrieve flight by name or create it if it doesn't exist...
auto flight = Flight::firstOrCreate({
{"name", "London to Paris"}
});

// Retrieve flight by name or create it with the name, delayed, and arrival_time attributes...
auto flight = Flight::firstOrCreate(
{{"name", "London to Paris"}},
{{"delayed", 1}, {"arrival_time", "11:30"}}
);

// Retrieve flight by name or instantiate a new Flight instance...
auto flight = Flight::firstOrNew({
{"name", "London to Paris"}
});

// Retrieve flight by name or instantiate with the name, delayed, and arrival_time attributes...
auto flight = Flight::firstOrNew(
{{"name", "Tokyo to Sydney"}},
{{"delayed", 1}, {"arrival_time", "11:30"}}
);
+

Retrieving Aggregates

+

When interacting with TinyORM models, you may also use the count, sum, max, and other aggregate methods provided by the query builder. As you might expect, these methods return a scalar value instead of a TinyORM model instance:

+
auto count = Flight::whereEq("active", 1)->count();

auto max = Flight::whereEq("active", 1)->max("price");
+

Inserting & Updating Models

+

Inserts

+

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 save method on the model instance:

+
#include "models/flight.hpp"

// Store a new flight in the database
Flight flight;
flight.setAttribute("name", "Slovakia to Czech");
flight.save();
+

In this example, we assign the name attribute of the Flight model instance. When we call the save method, a record will be inserted into the database. The model's created_at and updated_at timestamps will automatically be set when the save method is called, so there is no need to set them manually.

+

Alternatively, you may use the create method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the create method:

+
#include "models/flight.hpp"

auto flight = Flight::create({
{"name", "London to Paris"},
});
+

However, before using the create method, you will need to specify either a u_fillable or 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 mass assignment documentation.

+

Updates

+

The 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 save method. Again, the updated_at timestamp will automatically be updated, so there is no need to manually set its value:

+
#include "models/flight.hpp"

auto flight = Flight::find(1);

flight->setAttribute("name", "Paris to London");

flight->save();
+

Mass Updates

+

Updates can also be performed against models that match a given query. In this example, all flights that are active and have a destination of San Diego will be marked as delayed:

+
Flight::whereEq("active", 1)
->whereEq("destination", "San Diego")
.update({{"delayed", 1}});
+

The update method expects the QVector<Orm::UpdateItem> of column and value pairs representing the columns that should be updated.

+

Examining Attribute Changes

+

TinyORM provides the isDirty, isClean, and wasChanged methods to examine the internal state of your model and determine how its attributes have changed from when the model was originally retrieved.

+

The 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 isDirty method to determine if a particular attribute is dirty. The isClean will determine if an attribute has remained unchanged since the model was retrieved. This method also accepts an optional attribute argument:

+
#include "models/user.hpp"

auto user = User::create({
{"first_name", "Silver"},
{"last_name", "Zachara"},
{"title", "Developer"},
});

user.setAttribute("title", "Painter");

user.isDirty(); // true
user.isDirty("title"); // true
user.isDirty("first_name"); // false

user.isClean(); // false
user.isClean("title"); // false
user.isClean("first_name"); // true

user.save();

user.isDirty(); // false
user.isClean(); // true
+

The 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:

+
auto user = User::create({
{"first_name", "Silver"},
{"last_name", "Zachara"},
{"title", "Developer"},
});

user.setAttribute("title", "Painter");

user.wasChanged(); // false

user.save();

user.wasChanged(); // true
user.wasChanged("title"); // true
user.wasChanged("first_name"); // false
+

Mass Assignment

+

You may use the create method to "save" a new model using a single C++ statement. The inserted model instance will be returned to you by the method:

+
#include "models/flight.hpp"

auto flight = Flight::create({
{"name", "London to Paris"},
});
+

However, before using the create method, you will need to specify either a u_fillable or 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.

+

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 is_admin parameter through an HTTP request, which is then passed to your model's create method, allowing the user to escalate themselves to an administrator.

+

So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the u_fillable static data member on the model. For example, let's make the name attribute of our Flight model mass assignable:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;

using Model::Model;

/*! The attributes that are mass assignable. */
inline static QStringList u_fillable {
"name",
};
};
+

Once you have specified which attributes are mass assignable, you may use the create method to insert a new record in the database. The create method returns the newly created model instance:

+
auto flight = Flight::create({{"name", "London to Paris"}});
+

If you already have a model instance, you may use the fill method to populate it with the vector of attributes:

+
flight.fill({{"name", "Amsterdam to Frankfurt"}});
+

Allowing Mass Assignment

+

If you would like to make all of your attributes mass assignable, you may define your model's 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 fill, create, and update methods:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Flight final : public Model<Flight>
{
friend Model;

using Model::Model;

/*! The attributes that aren't mass assignable. */
inline static QStringList u_guarded {};
};
+

Upserts

+

Occasionally, you may need to update an existing model or create a new model if no matching model exists.

+

In the example below, if a flight exists with a departure location of Oakland and a destination location of San Diego, its price and 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:

+
auto flight = Flight::updateOrCreate(
{{"departure", "Oakland"}, {"destination", "San Diego"}},
{{"price", 99}, {"discounted", 1}}
);
+
note

The firstOrCreate and updateOrCreate methods persist the model, so there's no need to manually call the save method.

+

If you would like to perform multiple "upserts" in a single query, then you should use the 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 upsert method will automatically set the created_at and updated_at timestamps if timestamps are enabled on the model:

+
Flight::upsert(
{{{"departure", "Oakland"}, {"destination", "San Diego"}, {"price", 99}},
{{"departure", "Chicago"}, {"destination", "New York"}, {"price", 150}}},
{"departure", "destination"},
{"price"}
);
+
caution

All databases except SQL Server require the columns in the second argument of the upsert method to have a "primary" or "unique" index. In addition, the MySQL database driver ignores the second argument of the upsert method and always uses the "primary" and "unique" indexes of the table to detect existing records.

+
info

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 documentation. The MySQL server version is auto-detected and can be overridden in the configuration.

+

Deleting Models

+

To delete a model, you may call the remove, or an alias deleteRow method on the model instance:

+
#include "models/flight.hpp"

auto flight = Flight::find(1);

flight->remove();
+

Deleting An Existing Model By Its Primary Key

+

In the example above, we are retrieving the model from the database before calling the remove method. However, if you know the primary key of the model, you may delete the model without explicitly retrieving it by calling the destroy method. In addition to accepting the single primary key, the destroy method can accept multiple primary keys:

+
Flight::destroy(1);

Flight::destroy({1, 2, 3});
+
note

The destroy method loads models from the database and calls the remove method on each model individually, the reason for this is future compatibility with events.

+

Deleting Models Using Queries

+

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:

+
auto deletedRows = Flight::whereEq("active", 0)->remove();
+

Soft Deleting

+

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 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 Orm::Tiny::SoftDeletes base class to the model:

+
#include <orm/tiny/model.hpp>
#include <orm/tiny/softdeletes.hpp>

using Orm::Tiny::Model;
using Orm::Tiny::SoftDeletes;

class Flight final : public Model<Flight>,
public SoftDeletes<Flight>
{
friend Model;
using Model::Model;

private:
/*! The table associated with the model. */
QString u_table {"flights"};
};
+
info

The SoftDeletes base class will automatically cast the deleted_at attribute to the QDateTime instance for you (it adds the deleted_at column to the model's u_dates list).

+

You should also add the deleted_at column to your database table. The TinyORM schema builder contains a helper method to create this column:

+
Schema::table("flights", [](Blueprint &table)
{
table.softDeletes();
});

Schema::table("flights", [](Blueprint &table)
{
table.dropSoftDeletes();
});
+

Now, when you call the remove or deleteModel method on the model, the 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.

+

To determine if a given model instance has been soft deleted, you may use the trashed method:

+
if (flight->trashed()) {
//
}
+

Restoring Soft Deleted Models

+

Sometimes you may wish to "un-delete" a soft deleted model. To restore a soft deleted model, you may call the restore method on a model instance. The restore method will set the model's deleted_at column to null:

+
flight->restore();
+

You may also use the restore method in a query to restore multiple models:

+
Flight::withTrashed()
->whereEq("airline_id", 1)
.restore();
+

The restore method may also be used when building relationship queries:

+
flight->history()->restore();
+

Permanently Deleting Models

+

Sometimes you may need to truly remove a model from your database. You may use the forceDelete method (or it's alias forceRemove) to permanently remove a soft deleted model from the database table:

+
flight->forceDelete();
+

You may also use the forceDelete method when building TinyORM relationship queries:

+
flight->history()->forceDelete();
+

Querying Soft Deleted Models

+

Including Soft Deleted Models

+

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 withTrashed method on the query:

+
auto flights = Flight::withTrashed()
->whereEq("account_id", 1)
.get();
+

The withTrashed method may also be called when building a relationship query:

+
flight->history()->withTrashed().get();
+

Retrieving Only Soft Deleted Models

+

The onlyTrashed method will retrieve only soft deleted models:

+
auto flights = Flight::onlyTrashed()
->whereEq("airline_id", 1)
.get();
+

The onlyTrashed method may also be called when building a relationship query:

+
flight->history()->onlyTrashed().get();
+

Excluding Soft Deleted Models

+

As noted above, soft deleted models will automatically be excluded from query results. However, you may force soft deleted models to be excluded in a query's results by calling the withoutTrashed method on the query:

+
auto flights = Flight::withoutTrashed()
->whereEq("account_id", 1)
.get();
+

The withoutTrashed method may also be called when building a relationship query:

+
flight->history()->withoutTrashed().get();
+

Truncate Table

+

You may call the truncate method to delete all of the model's associated database records. The truncate operation will also reset any auto-incrementing IDs on the model's associated table:

+
Flight::truncate();
+

Replicating Models

+

You may create an unsaved copy of an existing model instance using the replicate method. This method is particularly useful when you have model instances that share many of the same attributes:

+
auto shipping = Address::create({
{"type", "shipping"},
{"line_1", "123 Example Street"},
{"city", "Victorville"},
{"state", "CA"},
{"postcode", "90001"},
});

auto billing = shipping.replicate();

billing.fill({
{"type", "billing"},
});

billing.save();
+

To exclude one or more attributes from being replicated to the new model, you may pass an unordered_set to the replicate method:

+
auto flight = Flight::create({
{"destination", "LAX"},
{"origin", "LHR"},
{"last_flown", "2020-03-04 11:00:00"},
{"last_pilot_id", 747},
});

flight = flight.replicate({
"last_flown",
"last_pilot_id",
});
+

Comparing Models

+

Sometimes you may need to determine if two models are the "same" or not. The is and isNot methods may be used to quickly verify two models have the same primary key, table, and database connection or not:

+
if (post->is(anotherPost)) {
//
}

if (post->isNot(anotherPost)) {
//
}
+

The is and isNot methods are also available when using the belongsTo and hasOne relationships. This method is particularly helpful when you would like to compare a related model without issuing a query to retrieve that model:

+
if (post->author()->is(user)) {
//
}
+
Equality comparison
+

The base Model class also defines the 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 model1 == model2 expression guarantees that these two models are exactly the same.

+

It would be appropriate to mention that this comparison also includes relations, which means it will also compare all models (including their data members) these relations contain.

\ No newline at end of file diff --git a/tinyorm/relationships.html b/tinyorm/relationships.html index cf500f75e..f010d80cf 100644 --- a/tinyorm/relationships.html +++ b/tinyorm/relationships.html @@ -1,9 +1,9 @@ - + - -TinyORM: Relationships - TinyORM + +TinyORM: Relationships - TinyORM @@ -13,14 +13,339 @@ - - - + + + -
-

TinyORM: Relationships

Introduction

Database tables are often related to one another. For example, a blog post may have many comments or an order could be related to the user who placed it. TinyORM makes managing and working with these relationships easy, and supports basic relationships:

Defining Relationships

TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities. For example, we may chain additional query constraints on this posts relationship:

user->posts()->whereEq("active", 1).get();

But, before diving too deep into using relationships, let's learn how to define each type of relationship supported by TinyORM.

Common Rules

Before you start defining relationship methods, you have to declare a model class, let's examine following model class with a "one" type relation:

#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/model.hpp>

#include "models/phone.hpp"

using Orm::Tiny::Model;

class User final : public Model<User, Phone>
{
friend Model;
using Model::Model;

public:
/*! Get the phone associated with the user. */
std::unique_ptr<HasOne<User, Phone>>
phone()
{
return hasOne<Phone>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"phone", &User::phone); }},
};
};

#endif // USER_HPP

First, you have to extend the Model<Derived, AllRelations...>, it is a common class for all models, the first template parameter is the type-id of the defined model itself, this pattern is called a Curiously recurring template pattern pattern.

However, the second parameter is more interesting, here you have to provide a type-id of all related models. The TinyORM needs these types to store relationships in the hash.

Next, you have to define the u_relations hash, which maps relation names to relationship methods. 🔥🚀🙌

tip

You may omit the friend Model declaration and define all the private data and function members as public.

One To One

A one-to-one relationship is a very basic type of database relationship. For example, a User model might be associated with one Phone model. To define this relationship, we will place a phone method on the User model. The phone method should call the hasOne method and return its result. The hasOne<Related> method is available to your model via the model's Orm::Tiny::Model<Derived, AllRelations...> base class:

#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/model.hpp>

#include "models/phone.hpp"

using Orm::Tiny::Model;

class User final : public Model<User, Phone>
{
friend Model;
using Model::Model;

public:
/*! Get the phone associated with the user. */
std::unique_ptr<HasOne<User, Phone>>
phone()
{
return hasOne<Phone>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"phone", [](auto &v) { v(&User::phone); }},
};
};

#endif // USER_HPP

The Related template argument provided to the hasOne<Related> method is the type-id of the related model class. Once the relationship is defined, we may retrieve the related record using Model's getRelationValue<Related, Tag> method:

auto phone = User::find(1)->getRelationValue<Phone, Orm::One>("phone");

TinyORM determines the foreign key of the relationship based on the parent model name. In this case, the Phone model is automatically assumed to have a user_id foreign key. If you wish to override this convention, you may pass a first argument to the hasOne method:

return hasOne<Phone>("foreign_key");

Additionally, TinyORM assumes that the foreign key should have a value matching the primary key column of the parent. In other words, TinyORM will look for the value of the user's id column in the user_id column of the Phone record. If you would like the relationship to use a primary key value other than id or your model's u_primaryKey data member, you may pass a second argument to the hasOne method:

return hasOne<Phone>("foreign_key", "local_key");

Defining The Inverse Of The Relationship

So, we can access the Phone model from our User model. Next, let's define a relationship on the Phone model that will let us access the user that owns the phone. We can define the inverse of a hasOne relationship using the belongsTo<Related> method:

#pragma once
#ifndef PHONE_HPP
#define PHONE_HPP

#include <orm/tiny/model.hpp>

#include "models/user.hpp"

using Orm::Tiny::Model;

class Phone final : public Model<Phone, User>
{
friend Model;
using Model::Model;

public:
/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
user()
{
return belongsTo<User>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"user", [](auto &v) { v(&Phone::user); }},
};
};

#endif // PHONE_HPP

When invoking the user method, TinyORM will attempt to find a User model that has an id which matches the user_id column on the Phone model.

TinyORM determines the foreign key name by examining the type-name of the Related template parameter and suffixing the type-name with _id. So, in this case, TinyORM assumes that the Phone model has a user_id column.

However, if the foreign key on the Phone model is not user_id, you may pass a custom key name as the first argument to the belongsTo method:

/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
user()
{
return belongsTo<User>("foreign_key");
}

If the parent model does not use id as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the belongsTo method specifying the parent table's custom key:

/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
user()
{
return belongsTo<User>("foreign_key", "owner_key");
}

The third belongsTo parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snakecase" this relation name and suffix it with a `followed by the name of the parent model's primary key column to generate foreign key, thefuncpredefined identifier is ideal for this. The relation name is also used in BelongsTo'sassociateanddisassociate` methods:

/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
someUser()
{
return belongsTo<User>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_user_id
}

The relation name will be guessed from the type-id of the Related template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be user.

One To Many

A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models. For example, a blog post may have an infinite number of comments. Like all other TinyORM relationships, one-to-many relationships are defined by defining a hasMany<Related> method on your TinyORM model:

#pragma once
#ifndef POST_HPP
#define POST_HPP

#include <orm/tiny/model.hpp>

#include "models/comment.hpp"

using Orm::Tiny::Model;

class Post final : public Model<Post, Comment>
{
friend Model;
using Model::Model;

public:
/*! Get the comments for the blog post. */
std::unique_ptr<HasMany<Post, Comment>>
comments()
{
return hasMany<Comment>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"comments", [](auto &v) { v(&Post::comments); }},
};
};

#endif // POST_HPP

Remember, TinyORM will automatically determine the proper foreign key column for the Comment model. By convention, TinyORM will take the "snake_case" name of the parent model and suffix it with _id. So, in this example, TinyORM will assume the foreign key column on the Comment model is post_id.

Once the relationship method has been defined, we can access the QVector<Related *> of related comments by Model's getRelationValue<Related, Container = QVector> method:

#include "models/post.hpp"

auto comments = Post::find(1)->getRelationValue<Comment>("comments");

for (auto *comment : comments) {
//
}

Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the comments method and continuing to chain conditions onto the query, all the TinyBuilder methods which are related to building queries are proxied:

auto comment = Post::find(1)->comments()
->whereEq("title", "foo")
.first();

Like the hasOne method, you may also override the foreign and local keys by passing additional arguments to the hasMany method:

return hasMany<Comment>("foreign_key");

return hasMany<Comment>("foreign_key", "local_key");

One To Many (Inverse) / Belongs To

Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship method on the child model which calls the belongsTo method:

#pragma once
#ifndef COMMENT_HPP
#define COMMENT_HPP

#include <orm/tiny/model.hpp>

#include "models/post.hpp"

using Orm::Tiny::Model;

class Comment final : public Model<Comment, Post>
{
friend Model;
using Model::Model;

public:
/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"post", [](auto &v) { v(&Comment::post); }},
};
};

#endif // COMMENT_HPP

Once the relationship has been defined, we can retrieve a comment's parent post by Model's getRelationValue<Related, Tag> method:

#include "models/comment.hpp"

auto comment = Comment::find(1);

return comment->getRelationValue<Post, Orm::One>("post")->getAttribute<QString>("title");

In the example above, TinyORM will attempt to find a Post model that has an id which matches the post_id column on the Comment model.

TinyORM determines the foreign key name by examining the type-name of the Related template parameter and suffixing the type-name with a _ followed by the name of the parent model's primary key column. So, in this case, TinyORM assumes that the Post model's foreign key on the comments table is post_id.

However, if the foreign key for your relationship does not follow these conventions, you may pass a custom foreign key name as the first argument to the belongsTo method:

/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>("foreign_key");
}

If your parent model does not use id as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the belongsTo method specifying your parent table's custom key:

/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>("foreign_key", "owner_key");
}

The third belongsTo parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snakecase" this relation name and suffix it with a `followed by the name of the parent model's primary key column to generate foreign key, thefuncpredefined identifier is ideal for this. The relation name is also used in BelongsTo'sassociateanddisassociate` methods:

/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
somePost()
{
return belongsTo<Post>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_post_id
}

The relation name will be guessed from the type-id of the Related template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be user.

Default Models

The belongsTo, and hasOne relationships allow you to define a default model that will be returned if the given relationship is null. This pattern is often referred to as the Null Object pattern and can help remove conditional checks in your code. In the following example, the user relation will return an empty User model if no user is attached to the Post model:

/*! Get the author of the post. */
std::unique_ptr<BelongsTo<Post, User>>
user()
{
// Ownership of a unique_ptr()
auto relation = belongsTo<User>();

relation->withDefault();

return relation;
}

To populate the default model with attributes, you may pass the vector of attributes to the withDefault method:

/*! Get the author of the post. */
std::unique_ptr<BelongsTo<Post, User>>
user()
{
// Ownership of a unique_ptr()
auto relation = belongsTo<User>();

relation->withDefault({{"name", "Guest Author"},
{"is_active", false}});

return relation;
}

Many To Many Relationships

Many-to-many relations are slightly more complicated than hasOne and hasMany relationships. An example of a many-to-many relationship is a user that has many roles and those roles are also shared by other users in the application. For example, a user may be assigned the role of "Author" and "Editor"; however, those roles may also be assigned to other users as well. So, a user has many roles and a role has many users.

Table Structure

To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names and contains user_id and role_id columns. This table is used as an intermediate table linking the users and roles.

Remember, since a role can belong to many users, we cannot simply place a user_id column on the roles table. This would mean that a role could only belong to a single user. In order to provide support for roles being assigned to multiple users, the role_user table is needed. We can summarize the relationship's table structure like so:

users
id - integer
name - string

roles
id - integer
name - string

role_user
user_id - integer
role_id - integer

Model Structure

Many-to-many relationships are defined by writing a method that returns the result of the belongsToMany method. The belongsToMany method is provided by the Orm::Tiny::Model<Derived, AllRelations...> base class that is used by all of your application's TinyORM models. For example, let's define a roles method on our User model. The first argument passed to this method is the name of the related model class:

#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/relations/pivot.hpp>

#include "models/role.hpp"

using Orm::Tiny::Model;
using Orm::Tiny::Relations::Pivot;

class User final : public Model<User, Role, Pivot>
{
friend Model;
using Model::Model;

public:
/*! The roles that belong to the user. */
std::unique_ptr<BelongsToMany<User, Role>>
roles()
{
return belongsToMany<Role>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"roles", [](auto &v) { v(&User::roles); }},
};
};

#endif // USER_HPP

Once the relationship is defined, you may access the user's roles as the QVector<Related *> by Model's getRelationValue<Related, Container = QVector> method:

#include <QDebug>

#include "models/user.hpp"

auto user = User::find(1);

for (auto *role : user->getRelationValue<Role>("roles"))
qDebug() << role->getAttribute<quint64>("id");

Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the roles method and continuing to chain conditions onto the query:

auto roles = User::find(1)->roles()->orderBy("name").get();

To determine the table name of the relationship's intermediate table, TinyORM will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a first argument to the belongsToMany method:

return belongsToMany<Role>("role_user");

In addition to customizing the name of the intermediate table, you may also customize the column names of the keys on the table by passing additional arguments to the belongsToMany method. The second argument is the foreign key name of the model on which you are defining the relationship, while the third argument is the foreign key name of the model that you are joining to:

return belongsToMany<Role>("role_user", "user_id", "role_id");

The fourth and fifth arguments are primary key names on models in the many-to-many relation and the sixth argument is the relation name.

The relation name is used during Touching Parent Timestamps and will be guessed from the type-id of the Related template parameter, TinyORM takes this name, changes the first character to lower case, and appends s character. So in the example above, the relation name will be roles.

Defining The Inverse Of The Relationship

To define the "inverse" of a many-to-many relationship, you should define a method on the related model which also returns the result of the belongsToMany method. To complete our user / role example, let's define the users method on the Role model:

#pragma once
#ifndef ROLE_HPP
#define ROLE_HPP

#include <orm/tiny/relations/pivot.hpp>

using Orm::Tiny::Model;
using Orm::Tiny::Relations::Pivot;

class User; // Forward declaration to avoid cyclic dependency

class Role final : public Model<Role, User, Pivot>
{
friend Model;
using Model::Model;

public:
/*! The users that belong to the role. */
std::unique_ptr<BelongsToMany<Role, User>>
users()
{
return belongsToMany<User>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"users", [](auto &v) { v(&Role::users); }},
};
};

#endif // ROLE_HPP

As you can see, the relationship is defined exactly the same as its User model counterpart with the exception of referencing the User model. Since we're reusing the belongsToMany method, all of the usual table and key customization options are available when defining the "inverse" of many-to-many relationships.

Retrieving Intermediate Table Columns

As you have already learned, working with many-to-many relations requires the presence of an intermediate table. TinyORM provides some very helpful ways of interacting with this table. For example, let's assume our User model has many Role models that it is related to. After accessing this relationship, we may access the intermediate table using the pivot attribute on the models:

#include <QDebug>

#include "models/user.hpp"

using Orm::Tiny::Relations::Pivot;

auto user = User::find(1);

for (auto *role : user->getRelationValue<Role>("roles"))
qDebug() << role->getRelation<Pivot, Orm::One>("pivot")
->getAttribute("created_at");

Notice that each Role model we retrieve has automatically assigned a pivot relationship. This relation contains a model representing the intermediate table and it is an instance of the Orm::Tiny::Relations::Pivot model class.

By default, only the model keys will be present on the pivot model. If your intermediate table contains extra attributes, you must specify them when defining the relationship:

// Ownership of a unique_ptr()
auto relation = belongsToMany<Role>();

relation->withPivot({"active", "created_by"});

return relation;

If you would like your intermediate table to have created_at and updated_at timestamps that are automatically maintained by TinyORM, call the withTimestamps method when defining the relationship:

// Ownership of a unique_ptr()
auto relation = belongsToMany<Role>();

relation->withTimestamps();

return relation;
caution

Intermediate tables that utilize TinyORM's automatically maintained timestamps are required to have both created_at and updated_at timestamp columns.

Customizing The pivot Relation Name

As noted previously, attributes from the intermediate table may be accessed on models via the pivot relation name. However, you are free to customize the name of this relation to better reflect its purpose within your application.

For example, if your application contains users that may subscribe to podcasts, you likely have a many-to-many relationship between users and podcasts. If this is the case, you may wish to rename your intermediate table relation name to subscription instead of pivot. This can be done using the as method when defining the relationship:

// Ownership of a unique_ptr()
auto relation = belongsToMany<Podcast>();

relation->as("subscription")
.withTimestamps();

return relation;

Once the custom intermediate table relation name has been specified, you may access the intermediate table data using the customized name:

#include <QDebug>

#include "models/user.hpp"

using Orm::Tiny::Relations::Pivot;

auto users = User::with("podcasts")->get();

for (auto &user : users)
for (auto *podcast : user.getRelation<Podcast>("podcasts"))
qDebug() << podcast->getRelation<Pivot, Orm::One>("subscription")
->getAttribute("created_at");

Defining Custom Intermediate Table Models

If you would like to define a custom model to represent the intermediate table of your many-to-many relationship, you may pass the custom pivot type as a second template argument to the belongsToMany<Related, PivotType = Pivot> method when defining the relationship. Custom pivot models give you the opportunity to define additional methods on the pivot model.

Custom many-to-many pivot models should extend the Orm::Tiny::Relations::BasePivot<PivotModel> class. For example, we may define a User model which uses a custom RoleUser pivot model:

#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/relations/pivot.hpp>

#include "models/role.hpp"

using Orm::Tiny::Model;
using Orm::Tiny::Relations::Pivot;

class User final : public Model<User, Role, Pivot>
{
friend Model;
using Model::Model;

public:
/*! The roles that belong to the user. */
std::unique_ptr<BelongsToMany<User, Role, RoleUser>>
roles()
{
return belongsToMany<Role, RoleUser>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"roles", [](auto &v) { v(&User::roles); }},
};
};

#endif // USER_HPP

When defining the RoleUser model, you should extend the Orm::Tiny::Relations::BasePivot<PivotModel> class:

#pragma once
#ifndef ROLEUSER_HPP
#define ROLEUSER_HPP

#include <orm/tiny/relations/basepivot.hpp>

using Orm::Tiny::Relations::BasePivot;

class RoleUser final : public BasePivot<RoleUser>
{
friend Model;
friend BasePivot;

using BasePivot::BasePivot;
};

#endif // ROLEUSER_HPP

You have to pass a custom pivot type to the AllRelations template parameter pack on Model<Derived, AllRelations...> so that the Model knows how to generate a std::variant, which holds all the relations and also you have to add a new mapping from the relation name to the custom pivot model type-id, this is described in more detail in the Common Rules:

#pragma once
#ifndef ROLE_HPP
#define ROLE_HPP

#include <orm/tiny/model.hpp>

#include "models/roleuser.hpp"

using Orm::Tiny::Model;

class User; // Forward declaration to avoid cyclic dependency

class Role final : public Model<Role, User, RoleUser>
{
friend Model;
using Model::Model;

public:
/*! The users that belong to the role. */
std::unique_ptr<BelongsToMany<Role, User>>
users()
{
return belongsToMany<User>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"users", [](auto &v) { v(&Role::users); }},
};
};

#endif // ROLE_HPP

Once the custom pivot model RoleUser has been defined, getRelation or getRelationValue method returns proper pivot type:

#include <QDebug>

#include "models/user.hpp"

auto users = User::with("roles")->get();

for (auto &user : users)
for (auto *role : user.getRelation<Role>("roles"))
qDebug() << role->getRelation<RoleUser, Orm::One>("pivot")
->getAttribute("created_at");
caution

Custom Pivot models may not use the SoftDeletes base class. If you need to soft delete pivot records consider converting your pivot model to an actual TinyORM model.

Custom Pivot Models And Incrementing IDs

If you have defined a many-to-many relationship that uses a custom pivot model, and that pivot model has an auto-incrementing primary key, you should ensure your custom pivot model class defines an u_incrementing data member that is set to true.

/*! Indicates if the IDs are auto-incrementing. */
bool u_incrementing = true;

Closer Look At Defining Custom Intermediate Table Models

I can tell that defining a custom intermediate table models is the most confusing part of the TinyORM framework, let's look closer at it.

If you are defining a custom RoleUser intermediate table for the Role model like in the example above then you have to pass the RoleUser pivot type as the second template argument to the User::roles() belongsToMany relationship method and you have to pass the RoleUser pivot type to the AllRelations template parameter pack on the Role model!

Do you see the confusing part? In short, if defining the User::roles() relation with the custom UserRole pivot model then add the UserRole type to the AllRelations template parameter pack on the Role model.

The same is true for the basic Pivot model, if you are using a basic pivot model and not a custom pivot model you still need to add the Pivot type to the AllRelations template parameter pack on the Model class!

The reason for all of this is that the Model knows how to generate and work with the std::variant that holds the pivot model in the Model::m_relations data member map, then you can get the pivot model using the Model::getRelationValue or Model::getRelation methods.

User Data Members on Custom Intermediate Table Models

This is another nonstandard part of the custom pivot models. The u_connection and u_timestamps user data members and the CREATED_AT() and UPDATED_AT() static getter methods are ignored when obtaining pivot records from the database during the lazy or eager loading.

Let's describe how these data members are resolved:

  • u_connection - inferred from the parent model
  • u_timestamps - true if obtained pivot attributes contain both the CREATED_AT and UPDATED_AT attributes
  • CREATED_AT, UPDATED_AT - inferred from the parent model, can be overridden using the withTimestamps() method

All these data members are taken into account normally when you call the create, save, update, ... on the Custom Pivot models!

Querying Relations

Since all TinyORM relationships are defined via methods, you may call those methods to obtain an instance of the relationship without actually executing a query to load the related models. In addition, all types of TinyORM relationships also serve as query builders, allowing you to continue to chain constraints onto the relationship query before finally executing the SQL query against your database.

For example, imagine a blog application in which a User model has many associated Post models:

#include "models/post.hpp"

using Orm::Tiny::Model;

class User final : public Model<User, Post>
{
friend Model;
using Model::Model;

public:
/*! Get all of the posts for the user. */
std::unique_ptr<HasMany<User, Post>>
posts()
{
return hasMany<Post>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"posts", [](auto &v) { v(&User::posts); }},
};
};

You may query the posts relationship and add additional constraints to the relationship like so:

#include "models/user.hpp"

auto user = User::find(1);

user->posts()->whereEq("active", 1).get();

You are able to use any of the TinyORM query builder's methods on the relationship, so be sure to explore the query builder documentation to learn about all of the methods that are available to you.

note

All the TinyBuilder methods which are related to building queries are proxied on the Relation base class.

Chaining orWhere Clauses After Relationships

As demonstrated in the example above, you are free to add additional constraints to relationships when querying them. However, be careful when chaining orWhere clauses onto a relationship, as the orWhere clauses will be logically grouped at the same level as the relationship constraint:

user->posts()
->whereEq("active", 1)
.orWhere("votes", ">=", 100)
.get();

The example above will generate the following SQL. As you can see, the or clause instructs the query to return any user with greater than 100 votes. The query is no longer constrained to a specific user:

select *
from posts
where user_id = ? and active = 1 or votes >= 100

In most situations, you should use logical groups to group the conditional checks between parentheses:

user->posts()
->where([](auto &query)
{
query.whereEq("active", 1)
.orWhere("votes", ">=", 100);
})
.get();

The example above will produce the following SQL. Note that the logical grouping has properly grouped the constraints and the query remains constrained to a specific user:

select *
from posts
where user_id = ? and (active = 1 or votes >= 100)

Relationship Methods

If you do not need to add additional constraints to the TinyORM relationship query, you may access the relationship directly. For example, continuing to use our User and Post example models, we may access all of a user's posts like so:

#include "models/user.hpp"

auto user = User::find(1);

for (auto *post : user->getRelationValue<Post>("posts")) {
//
}

The getRelationValue<Related> method performs "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use eager loading to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations.

To access eager loaded relationship use Model's getRelation<Related> method:

auto user = User::find(1);

for (auto *post : user->getRelation<Post>("posts")) {
//
}

As described above TinyORM offers two methods to access relationships; getRelation and getRelationValue.

The getRelation method is for "eager loaded" relations, when the relationship is not loaded, it throws the exception RelationNotLoadedError. The getRelationValue is for "lazy loading", when the relationship is not loaded, it will load it.

Both methods have two overloads, the getRelation<Related, Container = QVector> overload is for obtaining many type relationships:

auto posts = User::find(1)->getRelation<Post>("posts");

The getRelation<Related, Tag> overload is for obtaining "one" type relationships:

auto user = Post::find(1)->getRelation<User, Orm::One>("user");

The same is true for the getRelationValue method.

Querying Relationship Existence

When retrieving model records, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the has and orHas methods:

#include "models/post.hpp"

// Retrieve all posts that have at least one comment...
auto posts = Post::has("comments")->get();

You may also specify an operator and count value to further customize the query:

// Retrieve all posts that have three or more comments...
auto posts = Post::has("comments", ">=", 3)->get();

Nested has statements may be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment that has at least one image:

// Retrieve posts that have at least one comment with images...
auto posts = Post::has<Image>("comments.images")->get();

If you need even more power, you may use the whereHas and orWhereHas methods to define additional query constraints on your has queries, such as inspecting the content of a comment:

// Retrieve posts with at least one comment containing words like code%...
auto posts = Post::whereHas("comments", [](auto &query)
{
query.where("content", LIKE, "code%");
})->get();

// Retrieve posts with at least ten comments containing words like code%...
auto posts = Post::whereHas("comments", [](auto &query)
{
query.where("content", LIKE, "code%");
}, ">=", 10)->get();
note

TinyORM does not currently support querying for relationship existence across databases. The relationships must exist within the same database.

All the has-related methods are templated by the Related template parameter, it looks something like the following has<Related>(..., const std::function<void(CallbackType<Related> &)> &callback = nullptr), you can pass a query callback to this methods and on the base of the Related template argument will be decided whether the Orm::QueryBuilder or Orm::TinyBuilder<Related> will be passed to the callback. As you can see this Related parameter exists because the Orm::TinyBuilder<Related> needs it.

The rule of thumbs are:

  • if you don't pass the Related template parameter or you pass void then the Orm::QueryBuilder & will be passed to the callback
  • if you pass it, then the Orm::TinyBuilder<Related> & will be passed to the callback
  • Related has to be of the same type as a relation name passed to the has-related method (a real type of the relation eg. type of the posts relation name is Post)
  • you have to always pass the Related template parameter for nested relations, you can not use nested relations with Related = void
  • in nested relations, where you can pass more relation names using "dot" notation, Related has to be of the same type as the last relation name passed to the has-related method like you can see in the nested example above or below

Querying Relationship Absence

When retrieving model records, you may wish to limit your results based on the absence of a relationship. For example, imagine you want to retrieve all blog posts that don't have any comments. To do so, you may pass the name of the relationship to the doesntHave and orDoesntHave methods:

#include "models/post.hpp"

auto posts = Post::doesntHave("comments")->get();

If you need even more power, you may use the whereDoesntHave and orWhereDoesntHave methods to add additional query constraints to your doesntHave queries, such as inspecting the content of a comment:

auto posts = Post::whereDoesntHave("comments", [](auto &query)
{
query.where("content", LIKE, "code%");
})->get();

You may use "dot" notation to execute a query against a nested relationship. For example, the following query will retrieve all posts that have comments from authors that are not banned:

auto posts = Post::whereDoesntHave<Author>("comments.author",
[](auto &query)
{
query.where("banned", false);
})->get();

Eager Loading

When accessing TinyORM relationships by Model's getRelationValue method, the related models are "lazy loaded". This means the relationship data is not actually loaded until you first access them. However, TinyORM can "eager load" relationships at the time you query the parent model. Eager loading alleviates the "N + 1" query problem. To illustrate the N + 1 query problem, consider a Book model that "belongs to" to an Author model:

using Orm::Tiny::Model;

class Book final : public Model<Book, Author>
{
friend Model;
using Model::Model;

public:
/*! Get the author that wrote the book. */
std::unique_ptr<BelongsTo<Book, Author>>
author()
{
return belongsTo<Author>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"author", [](auto &v) { v(&Book::author); }},
};
};

Now, let's retrieve all books and their authors:

#include <QDebug>

#include "models/book.hpp"

auto books = Book::all();

for (auto &book : books)
qDebug() << book.getRelationValue<Author, Orm::One>("author")
->getAttribute<QString>("name");

This loop will execute one query to retrieve all of the books within the database table, then another query for each book in order to retrieve the book's author. So, if we have 25 books, the code above would run 26 queries: one for the original book, and 25 additional queries to retrieve the author of each book.

Thankfully, we can use eager loading to reduce this operation to just two queries. When building a query, you may specify which relationships should be eager loaded using the with method:

auto books = Book::with("author")->get();

for (auto &book : books)
qDebug() << book.getRelation<Author, Orm::One>("author")
->getAttribute<QString>("name");

For this operation, only two queries will be executed - one query to retrieve all of the books and one query to retrieve all of the authors for all of the books:

select * from books

select * from authors where id in (1, 2, 3, 4, 5, ...)

Eager Loading Multiple Relationships

Sometimes you may need to eager load several different relationships. To do so, just pass a QVector<Orm::WithItem> of relationships to the with method:

auto books = Book::with({"author", "publisher"})->get();

Nested Eager Loading

To eager a relationship's relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts:

auto books = Book::with("author.contacts")->get();

Eager Loading Specific Columns

You may not always need every column from the relationships you are retrieving. For this reason, TinyORM allows you to specify which columns of the relationship you would like to retrieve:

auto books = Book::with("author:id,name,book_id")->get();
caution

When using this feature, you should always include the id column and any relevant foreign key columns in the list of columns you wish to retrieve, otherwise relations will not be loaded correctly.

Eager Loading By Default

Sometimes you might want to always load some relationships when retrieving a model. To accomplish this, you may define a u_with data member on the model:

using Orm::Tiny::Model;

class Book final : public Model<Book, Author>
{
friend Model;
using Model::Model;

public:
/*! Get the author that wrote the book. */
std::unique_ptr<BelongsTo<Book, Author>>
author()
{
return belongsTo<Author>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"author", [](auto &v) { v(&Book::author); }},
};

/*! The relationships that should always be loaded. */
QVector<QString> u_with {
"author",
};
};

If you would like to remove an item from the u_with data member for a single query, you may use the without method:

auto books = Book::without("author")->get();

If you would like to override all items within the u_with data member for a single query, you may use the withOnly method:

auto books = Book::withOnly("genre")->get();

Constraining Eager Loads

Sometimes you may wish to eager load a relationship but also specify additional query conditions for the eager loading query. You can accomplish this by passing a QVector<Orm::WithItem> of relationships to the with method where the name data member of Orm::WithItem struct is a relationship name and the constraints data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the constraints lambda expression is an underlying Orm::QueryBuilder for a related model:

#include "models/user.hpp"

auto users = User::with({{"posts", [](auto &query)
{
query.where("title", "like", "%code%");
}}})->get();

In this example, TinyORM will only eager load posts where the post's title column contains the word code. You may call other query builder methods to further customize the eager loading operation:

auto users = User::with({{"posts", [](auto &query)
{
query.orderBy("created_at", "desc");
}}})->get();
note

The limit and take query builder methods may not be used when constraining eager loads.

Lazy Eager Loading

Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models:

#include "models/book.hpp"

auto book = Book::find(1);

if (someCondition)
book->load("author");

You may load more relationships at once, to do so, just pass a QVector<Orm::WithItem> of relationships to the load method:

Book::find(1)->load({"author", "publisher"});
note

So far, this only works on models, not on containers returned from Model's get or all methods.

If you need to set additional query constraints on the eager loading query, you may pass a QVector<Orm::WithItem> of relationships to the load method where the name data member of Orm::WithItem struct is a relationship name and the constraints data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the constraints lambda expression is an underlying Orm::QueryBuilder for a related model:

author->load({{"books", [](auto &query)
{
query.orderBy("published_date", "asc");
}}});
tip

You can also use eager constraining in the Model's fresh method.

The save Method

TinyORM provides convenient methods for adding new models to relationships. For example, perhaps you need to add a new comment to a post. Instead of manually setting the post_id attribute on the Comment model you may insert the comment using the relationship's save method:

#include "models/comment.hpp"
#include "models/post.hpp"

Comment comment({{"message", "A new comment."}});

auto post = Post::find(1);

post->comments()->save(comment);

Note that we did not access the comments relationship with the getRelation or getRelationValue method. Instead, we called the comments method to obtain an instance of the relationship. The save method will automatically add the appropriate post_id value to the new Comment model.

If you need to save multiple related models, you may use the saveMany method:

auto post = Post::find(1);

post->comments()->saveMany({
{{"message", "A new comment."}},
{{'message", "Another new comment."}},
});

The save and saveMany methods will not add the new models to any in-memory relationships that are already loaded onto the parent model. If you plan on accessing the relationship after using the save or saveMany methods, you may wish to use the refresh method to reload the model and its relationships:

post->comments()->save(comment);

post->refresh();

// All comments, including the newly saved comment...
post->getRelation<Comment>("comments");

The many-to-many relationship also supports the save and saveMany methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:

auto user = User::find(2);

Role role {{"name", "admin"}};

user->roles()->save(role, {{"active", true}});

Role role1 {{"name", "edit"}};
Role role2 {{"name", "view"}};

user->roles()->saveMany({role1, role2}, {{{"active", true}},
{{"active", false}}});

// No pivot attributes for role1
user->roles()->saveMany({role1, role2}, {{}, {{"active", false}}});

Recursively Saving Models & Relationships

If you would like to save your model and all of its associated relationships, you may use the push method. In this example, the Post model will be saved as well as its comments and the comment's authors:

auto post = Post::find(1);

post->getRelationValue<Comment>("comments").at(0)->setAttribute("message", "Message");

post->getRelationValue<Comment>("comments").first()
->getRelationValue<User, Orm::One>("author")->setAttribute("name", "Author Name");

post->push();

The create Method

In addition to the save and saveMany methods, you may also use the create method, which accepts a vector of attributes, creates a model, and inserts it into the database. The difference between save and create is that save accepts a full TinyORM model instance while create accepts a QVector<Orm::AttributeItem>. The newly created model will be returned by the create method:

#include "models/post.hpp"

auto post = Post::find(1);

auto comment = post->comments()->create({
{"message", "A new comment."},
});

You may use the createMany method to create multiple related models:

auto post = Post::find(1);

auto comments = post->comments()->createMany({
{{"message", "A new comment."}, {"is_published", true}},
{{"message", "Another new comment."}, {"is_published", false}},
});

The many-to-many relationship also supports the create and createMany methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:

auto user = User::find(2);

user->roles()->create({{"name", "admin"}}, {{"active", true}});

user->roles()->createMany({
{{"name", "edit"}},
{{"name", "view"}},
}, {
{{"active", true}},
{{"active", false}},
});

// No pivot attributes for the first role
user->roles()->createMany({
{{"name", "edit"}},
{{"name", "view"}},
}, {
{},
{{"active", false}},
});

You may also use the findOrNew, firstOrNew, firstOrCreate, and updateOrCreate methods to create and update models on relationships.

tip

Before using the create method, be sure to review the mass assignment documentation.

Belongs To Relationships

If you would like to assign a child model to a new parent model, you may use the associate method. In this example, the User model defines a belongsTo relationship to the Account model. The associate method will set the foreign key on the child model:

#include "models/user.hpp"

User user {{"name", "Mike"}};

auto account = Account::find(10);

user.account()->associate(*account);

user.save();

To remove a parent model from a child model, you may use the dissociate method. This method will set the relationship's foreign key to null:

user.account()->dissociate();

user.save();

Many To Many Relationships

Attaching / Detaching

TinyORM also provides methods to make working with many-to-many relationships more convenient. For example, let's imagine a user can have many roles and a role can have many users. You may use the attach method to attach a role to a user by inserting a record in the relationship's intermediate table:

#include "models/user.hpp"

auto user = User::find(1);

user->roles()->attach(roleId);

When attaching a relationship to a model, you may also pass a vector of additional data to be inserted into the intermediate table:

const auto expires = true;

user->roles()->attach(roleId, {{"expires", expires}});

Sometimes it may be necessary to remove a role from a user. To remove a many-to-many relationship record, use the detach method. The detach method will delete the appropriate record out of the intermediate table; however, both models will remain in the database:

// Detach a single role from the user...
user->roles()->detach(roleId);

// Detach all roles from the user...
user->roles()->detachAll();

For convenience, attach and detach also accept vectors of IDs or Model instances as input:

auto user = User::find(1);

user->roles()->detach({1, 2, 3});

Role role1({{"name", "Role 1"}});
role1.save();
Role role2({{"name", "Role 2"}});
role2.save();

user->roles()->attach({{role1}, {role2}});

The attach method also accepts std::map as input, so you can pass different attributes for each model you are attaching:

user->roles()->attach({
{1, {{"expires", true}, {"is_active", false}}},
{2, {{"expires", false}, {"is_active", true}}},
});

Syncing Associations

You may also use the sync method to construct many-to-many associations. The sync method accepts a vector of IDs to place on the intermediate table. Any IDs that are not in the given vector will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given vector will exist in the intermediate table:

user->roles()->sync({1, 2, 3});

You may also pass additional intermediate table values with the IDs:

user->roles()->sync({
{1, {{"expires", true}}},
{2, {}},
{3, {}},
});

If you do not want to detach existing IDs that are missing from the given vector, you may use the syncWithoutDetaching method:

user->roles()->syncWithoutDetaching({1, 2, 3});

Updating A Record On The Intermediate Table

If you need to update an existing row in your relationship's intermediate table, you may use the updateExistingPivot method. This method accepts the intermediate record foreign key and the vector of attributes to update:

auto user = User::find(1);

user->roles()->updateExistingPivot(roleId, {
{"active", false},
});

Touching Parent Timestamps

When a model defines a belongsTo relationship to another model, such as a Comment which belongs to a Post, it is sometimes helpful to update the parent's timestamp when the child model is updated.

For example, when a Comment model is updated, you may want to automatically "touch" the updated_at timestamp of the owning Post so that it is set to the current date and time. To accomplish this, you may add a u_touches data member to your child model containing the names of the relationships that should have their updated_at timestamps updated when the child model is updated:

using Orm::Tiny::Model;

class Comment final : public Model<Comment, Post>
{
friend Model;
using Model::Model;

public:
/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"post", [](auto &v) { v(&Comment::post); }},
};

/*! All of the relationships to be touched. */
QStringList u_touches {"post"};
};
note

Parent model timestamps will only be updated if the child model is updated using TinyORM's save, push, or remove method.

- - +

TinyORM: Relationships

+ +

Introduction

+

Database tables are often related to one another. For example, a blog post may have many comments or an order could be related to the user who placed it. TinyORM makes managing and working with these relationships easy, and supports basic relationships:

+ +

Defining Relationships

+

TinyORM relationships are defined as methods on your TinyORM model classes. Since relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities. For example, we may chain additional query constraints on this posts relationship:

+
user->posts()->whereEq("active", 1).get();
+

But, before diving too deep into using relationships, let's learn how to define each type of relationship supported by TinyORM.

+

Common Rules

+

Before you start defining relationship methods, you have to declare a model class, let's examine following model class with a "one" type relation:

+
#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/model.hpp>

#include "models/phone.hpp"

using Orm::Tiny::Model;

class User final : public Model<User, Phone>
{
friend Model;
using Model::Model;

public:
/*! Get the phone associated with the user. */
std::unique_ptr<HasOne<User, Phone>>
phone()
{
return hasOne<Phone>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"phone", &User::phone); }},
};
};

#endif // USER_HPP
+

First, you have to extend the Model<Derived, AllRelations...>, it is a common class for all models, the first template parameter is the type-id of the defined model itself, this pattern is called a Curiously recurring template pattern pattern.

+

However, the second parameter is more interesting, here you have to provide a type-id of all related models. The TinyORM needs these types to store relationships in the hash.

+

Next, you have to define the u_relations hash, which maps relation names to relationship methods. 🔥🚀🙌

+
tip

You may omit the friend Model declaration and define all the private data and function members as public.

+

One To One

+

A one-to-one relationship is a very basic type of database relationship. For example, a User model might be associated with one Phone model. To define this relationship, we will place a phone method on the User model. The phone method should call the hasOne method and return its result. The hasOne<Related> method is available to your model via the model's Orm::Tiny::Model<Derived, AllRelations...> base class:

+
#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/model.hpp>

#include "models/phone.hpp"

using Orm::Tiny::Model;

class User final : public Model<User, Phone>
{
friend Model;
using Model::Model;

public:
/*! Get the phone associated with the user. */
std::unique_ptr<HasOne<User, Phone>>
phone()
{
return hasOne<Phone>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"phone", [](auto &v) { v(&User::phone); }},
};
};

#endif // USER_HPP
+

The Related template argument provided to the hasOne<Related> method is the type-id of the related model class. Once the relationship is defined, we may retrieve the related record using Model's getRelationValue<Related, Tag> method:

+
auto phone = User::find(1)->getRelationValue<Phone, Orm::One>("phone");
+

TinyORM determines the foreign key of the relationship based on the parent model name. In this case, the Phone model is automatically assumed to have a user_id foreign key. If you wish to override this convention, you may pass a first argument to the hasOne method:

+
return hasOne<Phone>("foreign_key");
+

Additionally, TinyORM assumes that the foreign key should have a value matching the primary key column of the parent. In other words, TinyORM will look for the value of the user's id column in the user_id column of the Phone record. If you would like the relationship to use a primary key value other than id or your model's u_primaryKey data member, you may pass a second argument to the hasOne method:

+
return hasOne<Phone>("foreign_key", "local_key");
+

Defining The Inverse Of The Relationship

+

So, we can access the Phone model from our User model. Next, let's define a relationship on the Phone model that will let us access the user that owns the phone. We can define the inverse of a hasOne relationship using the belongsTo<Related> method:

+
#pragma once
#ifndef PHONE_HPP
#define PHONE_HPP

#include <orm/tiny/model.hpp>

#include "models/user.hpp"

using Orm::Tiny::Model;

class Phone final : public Model<Phone, User>
{
friend Model;
using Model::Model;

public:
/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
user()
{
return belongsTo<User>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"user", [](auto &v) { v(&Phone::user); }},
};
};

#endif // PHONE_HPP
+

When invoking the user method, TinyORM will attempt to find a User model that has an id which matches the user_id column on the Phone model.

+

TinyORM determines the foreign key name by examining the type-name of the Related template parameter and suffixing the type-name with _id. So, in this case, TinyORM assumes that the Phone model has a user_id column.

+

However, if the foreign key on the Phone model is not user_id, you may pass a custom key name as the first argument to the belongsTo method:

+
/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
user()
{
return belongsTo<User>("foreign_key");
}
+

If the parent model does not use id as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the belongsTo method specifying the parent table's custom key:

+
/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
user()
{
return belongsTo<User>("foreign_key", "owner_key");
}
+

The third belongsTo parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snake_case" this relation name and suffix it with a _ followed by the name of the parent model's primary key column to generate foreign key, the __func__ predefined identifier is ideal for this. The relation name is also used in BelongsTo's associate and disassociate methods:

+
/*! Get the user that owns the phone. */
std::unique_ptr<BelongsTo<Phone, User>>
someUser()
{
return belongsTo<User>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_user_id
}
+

The relation name will be guessed from the type-id of the Related template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be user.

+

One To Many

+

A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models. For example, a blog post may have an infinite number of comments. Like all other TinyORM relationships, one-to-many relationships are defined by defining a hasMany<Related> method on your TinyORM model:

+
#pragma once
#ifndef POST_HPP
#define POST_HPP

#include <orm/tiny/model.hpp>

#include "models/comment.hpp"

using Orm::Tiny::Model;

class Post final : public Model<Post, Comment>
{
friend Model;
using Model::Model;

public:
/*! Get the comments for the blog post. */
std::unique_ptr<HasMany<Post, Comment>>
comments()
{
return hasMany<Comment>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"comments", [](auto &v) { v(&Post::comments); }},
};
};

#endif // POST_HPP
+

Remember, TinyORM will automatically determine the proper foreign key column for the Comment model. By convention, TinyORM will take the "snake_case" name of the parent model and suffix it with _id. So, in this example, TinyORM will assume the foreign key column on the Comment model is post_id.

+

Once the relationship method has been defined, we can access the QVector<Related *> of related comments by Model's getRelationValue<Related, Container = QVector> method:

+
#include "models/post.hpp"

auto comments = Post::find(1)->getRelationValue<Comment>("comments");

for (auto *comment : comments) {
//
}
+

Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the comments method and continuing to chain conditions onto the query, all the TinyBuilder methods which are related to building queries are proxied:

+
auto comment = Post::find(1)->comments()
->whereEq("title", "foo")
.first();
+

Like the hasOne method, you may also override the foreign and local keys by passing additional arguments to the hasMany method:

+
return hasMany<Comment>("foreign_key");

return hasMany<Comment>("foreign_key", "local_key");
+

One To Many (Inverse) / Belongs To

+

Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship method on the child model which calls the belongsTo method:

+
#pragma once
#ifndef COMMENT_HPP
#define COMMENT_HPP

#include <orm/tiny/model.hpp>

#include "models/post.hpp"

using Orm::Tiny::Model;

class Comment final : public Model<Comment, Post>
{
friend Model;
using Model::Model;

public:
/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"post", [](auto &v) { v(&Comment::post); }},
};
};

#endif // COMMENT_HPP
+

Once the relationship has been defined, we can retrieve a comment's parent post by Model's getRelationValue<Related, Tag> method:

+
#include "models/comment.hpp"

auto comment = Comment::find(1);

return comment->getRelationValue<Post, Orm::One>("post")->getAttribute<QString>("title");
+

In the example above, TinyORM will attempt to find a Post model that has an id which matches the post_id column on the Comment model.

+

TinyORM determines the foreign key name by examining the type-name of the Related template parameter and suffixing the type-name with a _ followed by the name of the parent model's primary key column. So, in this case, TinyORM assumes that the Post model's foreign key on the comments table is post_id.

+

However, if the foreign key for your relationship does not follow these conventions, you may pass a custom foreign key name as the first argument to the belongsTo method:

+
/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>("foreign_key");
}
+

If your parent model does not use id as its primary key, or you wish to find the associated model using a different column, you may pass a second argument to the belongsTo method specifying your parent table's custom key:

+
/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>("foreign_key", "owner_key");
}
+

The third belongsTo parameter is the relation name, if you pass it, the foreign key name will be determined from it. By convention, TinyORM will "snake_case" this relation name and suffix it with a _ followed by the name of the parent model's primary key column to generate foreign key, the __func__ predefined identifier is ideal for this. The relation name is also used in BelongsTo's associate and disassociate methods:

+
/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
somePost()
{
return belongsTo<Post>({}, {}, QString::fromUtf8(__func__)); // the foreign key will be some_post_id
}
+

The relation name will be guessed from the type-id of the Related template parameter, TinyORM takes this name and changes the first character to lower case, so in the example above, the relation name will be user.

+

Default Models

+

The belongsTo, and hasOne relationships allow you to define a default model that will be returned if the given relationship is null. This pattern is often referred to as the Null Object pattern and can help remove conditional checks in your code. In the following example, the user relation will return an empty User model if no user is attached to the Post model:

+
/*! Get the author of the post. */
std::unique_ptr<BelongsTo<Post, User>>
user()
{
// Ownership of a unique_ptr()
auto relation = belongsTo<User>();

relation->withDefault();

return relation;
}
+

To populate the default model with attributes, you may pass the vector of attributes to the withDefault method:

+
/*! Get the author of the post. */
std::unique_ptr<BelongsTo<Post, User>>
user()
{
// Ownership of a unique_ptr()
auto relation = belongsTo<User>();

relation->withDefault({{"name", "Guest Author"},
{"is_active", false}});

return relation;
}
+

Many To Many Relationships

+

Many-to-many relations are slightly more complicated than hasOne and hasMany relationships. An example of a many-to-many relationship is a user that has many roles and those roles are also shared by other users in the application. For example, a user may be assigned the role of "Author" and "Editor"; however, those roles may also be assigned to other users as well. So, a user has many roles and a role has many users.

+

Table Structure

+

To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names and contains user_id and role_id columns. This table is used as an intermediate table linking the users and roles.

+

Remember, since a role can belong to many users, we cannot simply place a user_id column on the roles table. This would mean that a role could only belong to a single user. In order to provide support for roles being assigned to multiple users, the role_user table is needed. We can summarize the relationship's table structure like so:

+
users
id - integer
name - string

roles
id - integer
name - string

role_user
user_id - integer
role_id - integer
+

Model Structure

+

Many-to-many relationships are defined by writing a method that returns the result of the belongsToMany method. The belongsToMany method is provided by the Orm::Tiny::Model<Derived, AllRelations...> base class that is used by all of your application's TinyORM models. For example, let's define a roles method on our User model. The first argument passed to this method is the name of the related model class:

+
#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/relations/pivot.hpp>

#include "models/role.hpp"

using Orm::Tiny::Model;
using Orm::Tiny::Relations::Pivot;

class User final : public Model<User, Role, Pivot>
{
friend Model;
using Model::Model;

public:
/*! The roles that belong to the user. */
std::unique_ptr<BelongsToMany<User, Role>>
roles()
{
return belongsToMany<Role>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"roles", [](auto &v) { v(&User::roles); }},
};
};

#endif // USER_HPP
+

Once the relationship is defined, you may access the user's roles as the QVector<Related *> by Model's getRelationValue<Related, Container = QVector> method:

+
#include <QDebug>

#include "models/user.hpp"

auto user = User::find(1);

for (auto *role : user->getRelationValue<Role>("roles"))
qDebug() << role->getAttribute<quint64>("id");
+

Since all relationships also serve as query builders, you may add further constraints to the relationship query by calling the roles method and continuing to chain conditions onto the query:

+
auto roles = User::find(1)->roles()->orderBy("name").get();
+

To determine the table name of the relationship's intermediate table, TinyORM will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a first argument to the belongsToMany method:

+
return belongsToMany<Role>("role_user");
+

In addition to customizing the name of the intermediate table, you may also customize the column names of the keys on the table by passing additional arguments to the belongsToMany method. The second argument is the foreign key name of the model on which you are defining the relationship, while the third argument is the foreign key name of the model that you are joining to:

+
return belongsToMany<Role>("role_user", "user_id", "role_id");
+

The fourth and fifth arguments are primary key names on models in the many-to-many relation and the sixth argument is the relation name.

+

The relation name is used during Touching Parent Timestamps and will be guessed from the type-id of the Related template parameter, TinyORM takes this name, changes the first character to lower case, and appends s character. So in the example above, the relation name will be roles.

+

Defining The Inverse Of The Relationship

+

To define the "inverse" of a many-to-many relationship, you should define a method on the related model which also returns the result of the belongsToMany method. To complete our user / role example, let's define the users method on the Role model:

+
#pragma once
#ifndef ROLE_HPP
#define ROLE_HPP

#include <orm/tiny/relations/pivot.hpp>

using Orm::Tiny::Model;
using Orm::Tiny::Relations::Pivot;

class User; // Forward declaration to avoid cyclic dependency

class Role final : public Model<Role, User, Pivot>
{
friend Model;
using Model::Model;

public:
/*! The users that belong to the role. */
std::unique_ptr<BelongsToMany<Role, User>>
users()
{
return belongsToMany<User>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"users", [](auto &v) { v(&Role::users); }},
};
};

#endif // ROLE_HPP
+

As you can see, the relationship is defined exactly the same as its User model counterpart with the exception of referencing the User model. Since we're reusing the belongsToMany method, all of the usual table and key customization options are available when defining the "inverse" of many-to-many relationships.

+

Retrieving Intermediate Table Columns

+

As you have already learned, working with many-to-many relations requires the presence of an intermediate table. TinyORM provides some very helpful ways of interacting with this table. For example, let's assume our User model has many Role models that it is related to. After accessing this relationship, we may access the intermediate table using the pivot attribute on the models:

+
#include <QDebug>

#include "models/user.hpp"

using Orm::Tiny::Relations::Pivot;

auto user = User::find(1);

for (auto *role : user->getRelationValue<Role>("roles"))
qDebug() << role->getRelation<Pivot, Orm::One>("pivot")
->getAttribute("created_at");
+

Notice that each Role model we retrieve has automatically assigned a pivot relationship. This relation contains a model representing the intermediate table and it is an instance of the Orm::Tiny::Relations::Pivot model class.

+

By default, only the model keys will be present on the pivot model. If your intermediate table contains extra attributes, you must specify them when defining the relationship:

+
// Ownership of a unique_ptr()
auto relation = belongsToMany<Role>();

relation->withPivot({"active", "created_by"});

return relation;
+

If you would like your intermediate table to have created_at and updated_at timestamps that are automatically maintained by TinyORM, call the withTimestamps method when defining the relationship:

+
// Ownership of a unique_ptr()
auto relation = belongsToMany<Role>();

relation->withTimestamps();

return relation;
+
warning

Intermediate tables that utilize TinyORM's automatically maintained timestamps are required to have both created_at and updated_at timestamp columns.

+

Customizing The pivot Relation Name

+

As noted previously, attributes from the intermediate table may be accessed on models via the pivot relation name. However, you are free to customize the name of this relation to better reflect its purpose within your application.

+

For example, if your application contains users that may subscribe to podcasts, you likely have a many-to-many relationship between users and podcasts. If this is the case, you may wish to rename your intermediate table relation name to subscription instead of pivot. This can be done using the as method when defining the relationship:

+
// Ownership of a unique_ptr()
auto relation = belongsToMany<Podcast>();

relation->as("subscription")
.withTimestamps();

return relation;
+

Once the custom intermediate table relation name has been specified, you may access the intermediate table data using the customized name:

+
#include <QDebug>

#include "models/user.hpp"

using Orm::Tiny::Relations::Pivot;

auto users = User::with("podcasts")->get();

for (auto &user : users)
for (auto *podcast : user.getRelation<Podcast>("podcasts"))
qDebug() << podcast->getRelation<Pivot, Orm::One>("subscription")
->getAttribute("created_at");
+

Defining Custom Intermediate Table Models

+

If you would like to define a custom model to represent the intermediate table of your many-to-many relationship, you may pass the custom pivot type as a second template argument to the belongsToMany<Related, PivotType = Pivot> method when defining the relationship. Custom pivot models give you the opportunity to define additional methods on the pivot model.

+

Custom many-to-many pivot models should extend the Orm::Tiny::Relations::BasePivot<PivotModel> class. For example, we may define a User model which uses a custom RoleUser pivot model:

+
#pragma once
#ifndef USER_HPP
#define USER_HPP

#include <orm/tiny/relations/pivot.hpp>

#include "models/role.hpp"

using Orm::Tiny::Model;
using Orm::Tiny::Relations::Pivot;

class User final : public Model<User, Role, Pivot>
{
friend Model;
using Model::Model;

public:
/*! The roles that belong to the user. */
std::unique_ptr<BelongsToMany<User, Role, RoleUser>>
roles()
{
return belongsToMany<Role, RoleUser>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"roles", [](auto &v) { v(&User::roles); }},
};
};

#endif // USER_HPP
+

When defining the RoleUser model, you should extend the Orm::Tiny::Relations::BasePivot<PivotModel> class:

+
#pragma once
#ifndef ROLEUSER_HPP
#define ROLEUSER_HPP

#include <orm/tiny/relations/basepivot.hpp>

using Orm::Tiny::Relations::BasePivot;

class RoleUser final : public BasePivot<RoleUser>
{
friend Model;
friend BasePivot;

using BasePivot::BasePivot;
};

#endif // ROLEUSER_HPP
+

You have to pass a custom pivot type to the AllRelations template parameter pack on Model<Derived, AllRelations...> so that the Model knows how to generate a std::variant, which holds all the relations and also you have to add a new mapping from the relation name to the custom pivot model type-id, this is described in more detail in the Common Rules:

+
#pragma once
#ifndef ROLE_HPP
#define ROLE_HPP

#include <orm/tiny/model.hpp>

#include "models/roleuser.hpp"

using Orm::Tiny::Model;

class User; // Forward declaration to avoid cyclic dependency

class Role final : public Model<Role, User, RoleUser>
{
friend Model;
using Model::Model;

public:
/*! The users that belong to the role. */
std::unique_ptr<BelongsToMany<Role, User>>
users()
{
return belongsToMany<User>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"users", [](auto &v) { v(&Role::users); }},
};
};

#endif // ROLE_HPP
+

Once the custom pivot model RoleUser has been defined, getRelation or getRelationValue method returns proper pivot type:

+
#include <QDebug>

#include "models/user.hpp"

auto users = User::with("roles")->get();

for (auto &user : users)
for (auto *role : user.getRelation<Role>("roles"))
qDebug() << role->getRelation<RoleUser, Orm::One>("pivot")
->getAttribute("created_at");
+
warning

Custom Pivot models may not use the SoftDeletes base class. If you need to soft delete pivot records consider converting your pivot model to an actual TinyORM model.

+

Custom Pivot Models And Incrementing IDs

+

If you have defined a many-to-many relationship that uses a custom pivot model, and that pivot model has an auto-incrementing primary key, you should ensure your custom pivot model class defines an u_incrementing data member that is set to true.

+
/*! Indicates if the IDs are auto-incrementing. */
bool u_incrementing = true;
+

Closer Look At Defining Custom Intermediate Table Models

+

I can tell that defining a custom intermediate table models is the most confusing part of the TinyORM framework, let's look closer at it.

+

If you are defining a custom RoleUser intermediate table for the Role model like in the example above then you have to pass the RoleUser pivot type as the second template argument to the User::roles() belongsToMany relationship method and you have to pass the RoleUser pivot type to the AllRelations template parameter pack on the Role model!

+

Do you see the confusing part? In short, if defining the User::roles() relation with the custom UserRole pivot model then add the UserRole type to the AllRelations template parameter pack on the Role model.

+

The same is true for the basic Pivot model, if you are using a basic pivot model and not a custom pivot model you still need to add the Pivot type to the AllRelations template parameter pack on the Model class!

+

The reason for all of this is that the Model knows how to generate and work with the std::variant that holds the pivot model in the Model::m_relations data member map, then you can get the pivot model using the Model::getRelationValue or Model::getRelation methods.

+
User Data Members on Custom Intermediate Table Models
+

This is another nonstandard part of the custom pivot models. The u_connection and u_timestamps user data members and the CREATED_AT() and UPDATED_AT() static getter methods are ignored when obtaining pivot records from the database during the lazy or eager loading.

+

Let's describe how these data members are resolved:

+
    +
  • u_connection - inferred from the parent model
  • +
  • u_timestamps - true if obtained pivot attributes contain both the CREATED_AT and UPDATED_AT attributes
  • +
  • CREATED_AT, UPDATED_AT - inferred from the parent model, can be overridden using the withTimestamps() method
  • +
+

All these data members are taken into account normally when you call the create, save, update, ... on the Custom Pivot models!

+

Querying Relations

+

Since all TinyORM relationships are defined via methods, you may call those methods to obtain an instance of the relationship without actually executing a query to load the related models. In addition, all types of TinyORM relationships also serve as query builders, allowing you to continue to chain constraints onto the relationship query before finally executing the SQL query against your database.

+

For example, imagine a blog application in which a User model has many associated Post models:

+
#include "models/post.hpp"

using Orm::Tiny::Model;

class User final : public Model<User, Post>
{
friend Model;
using Model::Model;

public:
/*! Get all of the posts for the user. */
std::unique_ptr<HasMany<User, Post>>
posts()
{
return hasMany<Post>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"posts", [](auto &v) { v(&User::posts); }},
};
};
+

You may query the posts relationship and add additional constraints to the relationship like so:

+
#include "models/user.hpp"

auto user = User::find(1);

user->posts()->whereEq("active", 1).get();
+

You are able to use any of the TinyORM query builder's methods on the relationship, so be sure to explore the query builder documentation to learn about all of the methods that are available to you.

+
note

All the TinyBuilder methods which are related to building queries are proxied on the Relation base class.

+

Chaining orWhere Clauses After Relationships

+

As demonstrated in the example above, you are free to add additional constraints to relationships when querying them. However, be careful when chaining orWhere clauses onto a relationship, as the orWhere clauses will be logically grouped at the same level as the relationship constraint:

+
user->posts()
->whereEq("active", 1)
.orWhere("votes", ">=", 100)
.get();
+

The example above will generate the following SQL. As you can see, the or clause instructs the query to return any user with greater than 100 votes. The query is no longer constrained to a specific user:

+
select *
from posts
where user_id = ? and active = 1 or votes >= 100
+

In most situations, you should use logical groups to group the conditional checks between parentheses:

+
user->posts()
->where([](auto &query)
{
query.whereEq("active", 1)
.orWhere("votes", ">=", 100);
})
.get();
+

The example above will produce the following SQL. Note that the logical grouping has properly grouped the constraints and the query remains constrained to a specific user:

+
select *
from posts
where user_id = ? and (active = 1 or votes >= 100)
+

Relationship Methods

+

If you do not need to add additional constraints to the TinyORM relationship query, you may access the relationship directly. For example, continuing to use our User and Post example models, we may access all of a user's posts like so:

+
#include "models/user.hpp"

auto user = User::find(1);

for (auto *post : user->getRelationValue<Post>("posts")) {
//
}
+

The getRelationValue<Related> method performs "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use eager loading to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations.

+

To access eager loaded relationship use Model's getRelation<Related> method:

+
auto user = User::find(1);

for (auto *post : user->getRelation<Post>("posts")) {
//
}
+

As described above TinyORM offers two methods to access relationships; getRelation and getRelationValue.

+

The getRelation method is for "eager loaded" relations, when the relationship is not loaded, it throws the exception RelationNotLoadedError. The getRelationValue is for "lazy loading", when the relationship is not loaded, it will load it.

+

Both methods have two overloads, the getRelation<Related, Container = QVector> overload is for obtaining many type relationships:

+
auto posts = User::find(1)->getRelation<Post>("posts");
+

The getRelation<Related, Tag> overload is for obtaining "one" type relationships:

+
auto user = Post::find(1)->getRelation<User, Orm::One>("user");
+

The same is true for the getRelationValue method.

+

Querying Relationship Existence

+

When retrieving model records, you may wish to limit your results based on the existence of a relationship. For example, imagine you want to retrieve all blog posts that have at least one comment. To do so, you may pass the name of the relationship to the has and orHas methods:

+
#include "models/post.hpp"

// Retrieve all posts that have at least one comment...
auto posts = Post::has("comments")->get();
+

You may also specify an operator and count value to further customize the query:

+
// Retrieve all posts that have three or more comments...
auto posts = Post::has("comments", ">=", 3)->get();
+

Nested has statements may be constructed using "dot" notation. For example, you may retrieve all posts that have at least one comment that has at least one image:

+
// Retrieve posts that have at least one comment with images...
auto posts = Post::has<Image>("comments.images")->get();
+

If you need even more power, you may use the whereHas and orWhereHas methods to define additional query constraints on your has queries, such as inspecting the content of a comment:

+
// Retrieve posts with at least one comment containing words like code%...
auto posts = Post::whereHas("comments", [](auto &query)
{
query.where("content", LIKE, "code%");
})->get();

// Retrieve posts with at least ten comments containing words like code%...
auto posts = Post::whereHas("comments", [](auto &query)
{
query.where("content", LIKE, "code%");
}, ">=", 10)->get();
+
note

TinyORM does not currently support querying for relationship existence across databases. The relationships must exist within the same database.

+ +

All the has-related methods are templated by the Related template parameter, it looks something like the following has<Related>(..., const std::function<void(CallbackType<Related> &)> &callback = nullptr), you can pass a query callback to this methods and on the base of the Related template argument will be decided whether the Orm::QueryBuilder or Orm::TinyBuilder<Related> will be passed to the callback. As you can see this Related parameter exists because the Orm::TinyBuilder<Related> needs it.

+

The rule of thumbs are:

+
    +
  • if you don't pass the Related template parameter or you pass void then the Orm::QueryBuilder & will be passed to the callback
  • +
  • if you pass it, then the Orm::TinyBuilder<Related> & will be passed to the callback
  • +
  • Related has to be of the same type as a relation name passed to the has-related method (a real type of the relation eg. type of the posts relation name is Post)
  • +
  • you have to always pass the Related template parameter for nested relations, you can not use nested relations with Related = void
  • +
  • in nested relations, where you can pass more relation names using "dot" notation, Related has to be of the same type as the last relation name passed to the has-related method like you can see in the nested example above or below
  • +
+

Querying Relationship Absence

+

When retrieving model records, you may wish to limit your results based on the absence of a relationship. For example, imagine you want to retrieve all blog posts that don't have any comments. To do so, you may pass the name of the relationship to the doesntHave and orDoesntHave methods:

+
#include "models/post.hpp"

auto posts = Post::doesntHave("comments")->get();
+

If you need even more power, you may use the whereDoesntHave and orWhereDoesntHave methods to add additional query constraints to your doesntHave queries, such as inspecting the content of a comment:

+
auto posts = Post::whereDoesntHave("comments", [](auto &query)
{
query.where("content", LIKE, "code%");
})->get();
+

You may use "dot" notation to execute a query against a nested relationship. For example, the following query will retrieve all posts that have comments from authors that are not banned:

+
auto posts = Post::whereDoesntHave<Author>("comments.author",
[](auto &query)
{
query.where("banned", false);
})->get();
+

Eager Loading

+

When accessing TinyORM relationships by Model's getRelationValue method, the related models are "lazy loaded". This means the relationship data is not actually loaded until you first access them. However, TinyORM can "eager load" relationships at the time you query the parent model. Eager loading alleviates the "N + 1" query problem. To illustrate the N + 1 query problem, consider a Book model that "belongs to" to an Author model:

+
using Orm::Tiny::Model;

class Book final : public Model<Book, Author>
{
friend Model;
using Model::Model;

public:
/*! Get the author that wrote the book. */
std::unique_ptr<BelongsTo<Book, Author>>
author()
{
return belongsTo<Author>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"author", [](auto &v) { v(&Book::author); }},
};
};
+

Now, let's retrieve all books and their authors:

+
#include <QDebug>

#include "models/book.hpp"

auto books = Book::all();

for (auto &book : books)
qDebug() << book.getRelationValue<Author, Orm::One>("author")
->getAttribute<QString>("name");
+

This loop will execute one query to retrieve all of the books within the database table, then another query for each book in order to retrieve the book's author. So, if we have 25 books, the code above would run 26 queries: one for the original book, and 25 additional queries to retrieve the author of each book.

+

Thankfully, we can use eager loading to reduce this operation to just two queries. When building a query, you may specify which relationships should be eager loaded using the with method:

+
auto books = Book::with("author")->get();

for (auto &book : books)
qDebug() << book.getRelation<Author, Orm::One>("author")
->getAttribute<QString>("name");
+

For this operation, only two queries will be executed - one query to retrieve all of the books and one query to retrieve all of the authors for all of the books:

+
select * from books

select * from authors where id in (1, 2, 3, 4, 5, ...)
+

Eager Loading Multiple Relationships

+

Sometimes you may need to eager load several different relationships. To do so, just pass a QVector<Orm::WithItem> of relationships to the with method:

+
auto books = Book::with({"author", "publisher"})->get();
+

Nested Eager Loading

+

To eager a relationship's relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts:

+
auto books = Book::with("author.contacts")->get();
+

Eager Loading Specific Columns

+

You may not always need every column from the relationships you are retrieving. For this reason, TinyORM allows you to specify which columns of the relationship you would like to retrieve:

+
auto books = Book::with("author:id,name,book_id")->get();
+
warning

When using this feature, you should always include the id column and any relevant foreign key columns in the list of columns you wish to retrieve, otherwise relations will not be loaded correctly.

+

Eager Loading By Default

+

Sometimes you might want to always load some relationships when retrieving a model. To accomplish this, you may define a u_with data member on the model:

+
using Orm::Tiny::Model;

class Book final : public Model<Book, Author>
{
friend Model;
using Model::Model;

public:
/*! Get the author that wrote the book. */
std::unique_ptr<BelongsTo<Book, Author>>
author()
{
return belongsTo<Author>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"author", [](auto &v) { v(&Book::author); }},
};

/*! The relationships that should always be loaded. */
QVector<QString> u_with {
"author",
};
};
+

If you would like to remove an item from the u_with data member for a single query, you may use the without method:

+
auto books = Book::without("author")->get();
+

If you would like to override all items within the u_with data member for a single query, you may use the withOnly method:

+
auto books = Book::withOnly("genre")->get();
+

Constraining Eager Loads

+

Sometimes you may wish to eager load a relationship but also specify additional query conditions for the eager loading query. You can accomplish this by passing a QVector<Orm::WithItem> of relationships to the with method where the name data member of Orm::WithItem struct is a relationship name and the constraints data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the constraints lambda expression is an underlying Orm::QueryBuilder for a related model:

+
#include "models/user.hpp"

auto users = User::with({{"posts", [](auto &query)
{
query.where("title", "like", "%code%");
}}})->get();
+

In this example, TinyORM will only eager load posts where the post's title column contains the word code. You may call other query builder methods to further customize the eager loading operation:

+
auto users = User::with({{"posts", [](auto &query)
{
query.orderBy("created_at", "desc");
}}})->get();
+
note

The limit and take query builder methods may not be used when constraining eager loads.

+

Lazy Eager Loading

+

Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models:

+
#include "models/book.hpp"

auto book = Book::find(1);

if (someCondition)
book->load("author");
+

You may load more relationships at once, to do so, just pass a QVector<Orm::WithItem> of relationships to the load method:

+
Book::find(1)->load({"author", "publisher"});
+
note

So far, this only works on models, not on containers returned from Model's get or all methods.

+

If you need to set additional query constraints on the eager loading query, you may pass a QVector<Orm::WithItem> of relationships to the load method where the name data member of Orm::WithItem struct is a relationship name and the constraints data member expects a lambda expression that adds additional constraints to the eager loading query. The first argument passed to the constraints lambda expression is an underlying Orm::QueryBuilder for a related model:

+
author->load({{"books", [](auto &query)
{
query.orderBy("published_date", "asc");
}}});
+
tip

You can also use eager constraining in the Model's fresh method.

+ +

The save Method

+

TinyORM provides convenient methods for adding new models to relationships. For example, perhaps you need to add a new comment to a post. Instead of manually setting the post_id attribute on the Comment model you may insert the comment using the relationship's save method:

+
#include "models/comment.hpp"
#include "models/post.hpp"

Comment comment({{"message", "A new comment."}});

auto post = Post::find(1);

post->comments()->save(comment);
+

Note that we did not access the comments relationship with the getRelation or getRelationValue method. Instead, we called the comments method to obtain an instance of the relationship. The save method will automatically add the appropriate post_id value to the new Comment model.

+

If you need to save multiple related models, you may use the saveMany method:

+
auto post = Post::find(1);

post->comments()->saveMany({
{{"message", "A new comment."}},
{{"message", "Another new comment."}},
});
+

The save and saveMany methods will not add the new models to any in-memory relationships that are already loaded onto the parent model. If you plan on accessing the relationship after using the save or saveMany methods, you may wish to use the refresh method to reload the model and its relationships:

+
post->comments()->save(comment);

post->refresh();

// All comments, including the newly saved comment...
post->getRelation<Comment>("comments");
+

The many-to-many relationship also supports the save and saveMany methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:

+
auto user = User::find(2);

Role role {{"name", "admin"}};

user->roles()->save(role, {{"active", true}});

Role role1 {{"name", "edit"}};
Role role2 {{"name", "view"}};

user->roles()->saveMany({role1, role2}, {{{"active", true}},
{{"active", false}}});

// No pivot attributes for role1
user->roles()->saveMany({role1, role2}, {{}, {{"active", false}}});
+

Recursively Saving Models & Relationships

+

If you would like to save your model and all of its associated relationships, you may use the push method. In this example, the Post model will be saved as well as its comments and the comment's authors:

+
auto post = Post::find(1);

post->getRelationValue<Comment>("comments").at(0)->setAttribute("message", "Message");

post->getRelationValue<Comment>("comments").first()
->getRelationValue<User, Orm::One>("author")->setAttribute("name", "Author Name");

post->push();
+

The create Method

+

In addition to the save and saveMany methods, you may also use the create method, which accepts a vector of attributes, creates a model, and inserts it into the database. The difference between save and create is that save accepts a full TinyORM model instance while create accepts a QVector<Orm::AttributeItem>. The newly created model will be returned by the create method:

+
#include "models/post.hpp"

auto post = Post::find(1);

auto comment = post->comments()->create({
{"message", "A new comment."},
});
+

You may use the createMany method to create multiple related models:

+
auto post = Post::find(1);

auto comments = post->comments()->createMany({
{{"message", "A new comment."}, {"is_published", true}},
{{"message", "Another new comment."}, {"is_published", false}},
});
+

The many-to-many relationship also supports the create and createMany methods. In addition, you may pass the pivot attributes as a second argument and select if you want to touch parent timestamps as a third argument:

+
auto user = User::find(2);

user->roles()->create({{"name", "admin"}}, {{"active", true}});

user->roles()->createMany({
{{"name", "edit"}},
{{"name", "view"}},
}, {
{{"active", true}},
{{"active", false}},
});

// No pivot attributes for the first role
user->roles()->createMany({
{{"name", "edit"}},
{{"name", "view"}},
}, {
{},
{{"active", false}},
});
+

You may also use the findOrNew, firstOrNew, firstOrCreate, and updateOrCreate methods to create and update models on relationships.

+
tip

Before using the create method, be sure to review the mass assignment documentation.

+

Belongs To Relationships

+

If you would like to assign a child model to a new parent model, you may use the associate method. In this example, the User model defines a belongsTo relationship to the Account model. The associate method will set the foreign key on the child model:

+
#include "models/user.hpp"

User user {{"name", "Mike"}};

auto account = Account::find(10);

user.account()->associate(*account);

user.save();
+

To remove a parent model from a child model, you may use the dissociate method. This method will set the relationship's foreign key to null:

+
user.account()->dissociate();

user.save();
+

Many To Many Relationships

+

Attaching / Detaching

+

TinyORM also provides methods to make working with many-to-many relationships more convenient. For example, let's imagine a user can have many roles and a role can have many users. You may use the attach method to attach a role to a user by inserting a record in the relationship's intermediate table:

+
#include "models/user.hpp"

auto user = User::find(1);

user->roles()->attach(roleId);
+

When attaching a relationship to a model, you may also pass a vector of additional data to be inserted into the intermediate table:

+
const auto expires = true;

user->roles()->attach(roleId, {{"expires", expires}});
+

Sometimes it may be necessary to remove a role from a user. To remove a many-to-many relationship record, use the detach method. The detach method will delete the appropriate record out of the intermediate table; however, both models will remain in the database:

+
// Detach a single role from the user...
user->roles()->detach(roleId);

// Detach all roles from the user...
user->roles()->detachAll();
+

For convenience, attach and detach also accept vectors of IDs or Model instances as input:

+
auto user = User::find(1);

user->roles()->detach({1, 2, 3});

Role role1({{"name", "Role 1"}});
role1.save();
Role role2({{"name", "Role 2"}});
role2.save();

user->roles()->attach({{role1}, {role2}});
+

The attach method also accepts std::map as input, so you can pass different attributes for each model you are attaching:

+
user->roles()->attach({
{1, {{"expires", true}, {"is_active", false}}},
{2, {{"expires", false}, {"is_active", true}}},
});
+

Syncing Associations

+

You may also use the sync method to construct many-to-many associations. The sync method accepts a vector of IDs to place on the intermediate table. Any IDs that are not in the given vector will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given vector will exist in the intermediate table:

+
user->roles()->sync({1, 2, 3});
+

You may also pass additional intermediate table values with the IDs:

+
user->roles()->sync({
{1, {{"expires", true}}},
{2, {}},
{3, {}},
});
+

If you do not want to detach existing IDs that are missing from the given vector, you may use the syncWithoutDetaching method:

+
user->roles()->syncWithoutDetaching({1, 2, 3});
+

Updating A Record On The Intermediate Table

+

If you need to update an existing row in your relationship's intermediate table, you may use the updateExistingPivot method. This method accepts the intermediate record foreign key and the vector of attributes to update:

+
auto user = User::find(1);

user->roles()->updateExistingPivot(roleId, {
{"active", false},
});
+

Touching Parent Timestamps

+

When a model defines a belongsTo relationship to another model, such as a Comment which belongs to a Post, it is sometimes helpful to update the parent's timestamp when the child model is updated.

+

For example, when a Comment model is updated, you may want to automatically "touch" the updated_at timestamp of the owning Post so that it is set to the current date and time. To accomplish this, you may add a u_touches data member to your child model containing the names of the relationships that should have their updated_at timestamps updated when the child model is updated:

+
using Orm::Tiny::Model;

class Comment final : public Model<Comment, Post>
{
friend Model;
using Model::Model;

public:
/*! Get the post that owns the comment. */
std::unique_ptr<BelongsTo<Comment, Post>>
post()
{
return belongsTo<Post>();
}

private:
/*! Map of relation names to methods. */
QHash<QString, RelationVisitor> u_relations {
{"post", [](auto &v) { v(&Comment::post); }},
};

/*! All of the relationships to be touched. */
QStringList u_touches {"post"};
};
+
note

Parent model timestamps will only be updated if the child model is updated using TinyORM's save, push, or remove method.

\ No newline at end of file diff --git a/tinyorm/serialization.html b/tinyorm/serialization.html index 3e1b64b22..76b688325 100644 --- a/tinyorm/serialization.html +++ b/tinyorm/serialization.html @@ -1,9 +1,9 @@ - + - -TinyORM: Serialization - TinyORM + +TinyORM: Serialization - TinyORM @@ -13,14 +13,77 @@ - - - + + + -
-

TinyORM: Serialization

Introduction

When building APIs using TinyORM, you will often need to convert your models and relationships to vectors, maps, or JSON. TinyORM includes convenient methods for making these conversions, as well as controlling which attributes are included in the serialized representation of your models.

Serializing Models & Collections

Serializing To Vectors & Maps

To convert a model and its loaded relationships to a vector, you should use the toVector or toMap methods. This methods are recursive, so all attributes and all relations (including the relations of relations) will be converted to vectors:

using Models::User;

auto user = User::with("roles")->first();

return user->toVector();

return user->toMap();

The attributesToVector or attributesToMap methods may be used to convert a model's attributes to a vector or map but not its relationships:

auto user = User::first();

return user->attributesToVector();

return user->attributesToMap();

You may also convert entire collections of models to vectors or maps by calling the toVector or toMap methods on the collection instance:

ModelsCollection<User> users = User::with("roles")->all();

return users.toVector();

return users.toMap();

Serializing To JSON

To convert a model to JSON, you should use the toJson method. Like toVector or toMap, the toJson method is recursive, so all attributes and relations will be converted to JSON. You may also specify any JSON encoding options that are supported by QJsonDocument::toJson:

using Models::User;

auto user = User::with("roles")->find(1);

return user->toJson();

return user->toJson(QJsonDocument::Indented);

You may also convert entire collections of models to JSON by calling the toJson method on the collection instance:

ModelsCollection<User> users = User::with("roles")->findMany({1, 2});

return users.toJson();

You can also convert models to the QJsonObject and QJsonDocument using the toJsonArray and toJsonDocument methods and collection of models to QJsonArray and QJsonDocument using the toJsonArray and toJsonDocument methods.

Relationships

When a TinyORM model is converted to JSON, its loaded relationships will automatically be included as attributes on the JSON object. Also, though TinyORM relationship methods are defined using "camelCase" method names, a relationship's JSON attributes will be "snake_case".

This behavior is affected and can be overridden by the u_snakeAttributes static data member:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Album final : public Model<Album, AlbumImage>
{
friend Model;
using Model::Model;

/*! Indicates whether attributes are snake_cased during serialization. */
inline static const bool u_snakeAttributes = false;
};

Hiding Attributes From JSON

Sometimes you may wish to limit the attributes, such as passwords, that are included in your model's vector, map, or JSON representation. To do so, add a u_hidden static data member to your model. Attributes that are listed in the u_hidden data member set will not be included in the serialized representation of your model:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! The attributes that should be hidden during serialization. */
inline static std::set<QString> u_hidden {"password"};
};
note

To hide relationships, add the relationship's method name to your TinyORM model's u_hidden static data member.

Alternatively, you may use the u_visible static data member to define an "allow list" of attributes that should be included in your model's vector, map, and JSON representation. All attributes that are not present in the u_visible set will be hidden during serialization:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! The attributes that should be visible during serialization. */
inline static std::set<QString> u_visible {
"first_name", "last_name",
};
};

Temporarily Modifying Attribute Visibility

If you would like to make some typically hidden attributes visible on a given model instance, you may use the makeVisible method. The makeVisible method returns a model reference:

return user.makeVisible("attribute").toMap();

return user.makeVisible({"id", "name"}).toMap();

Likewise, if you would like to hide some attributes that are typically visible, you may use the makeHidden method.

return user.makeHidden("attribute").toVector();

return user.makeHidden({"id", "name"}).toVector();

If you wish to temporarily override all of the visible or hidden attributes, you may use the setVisible and setHidden methods respectively:

return user.setVisible({"id", "name"}).toMap();

return user.setHidden({"email", "password", "note"}).toJson();

You can also clear all visible and hidden attributes or determine whether a visible / hidden attribute is defined:

user.clearVisible();

user.clearHidden();

return user.hasVisible("name");

return user.hasHidden("password");

Appending Values To JSON

Occasionally, when converting models to vector, map, or JSON, you may wish to add attributes that do not have a corresponding column in your database. To do so, first define an accessor for the value:

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

protected:
/*! Accessor to determine if the user is an administrator. */
Attribute isAdmin() const noexcept
{
return Attribute::make(/* get */ []() -> QVariant
{
return QStringLiteral("yes");
});
}
};

If you would like the accessor to always be appended to your model's vector, map, and JSON representations, you may add the attribute name to the u_appends data member set of your model. Note that attribute names are typically referenced using their "snake_case" serialized representation, even though the accessor's method name is defined using "camelCase":

#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! Map of mutator names to methods. */
inline static const QHash<QString, MutatorFunction> u_mutators {
{"is_admin", &User::isAdmin},
};

/*! The attributes that should be appended during serialization. */
std::set<QString> u_appends {"is_admin"};
};

Once the attribute has been added to the u_appends set, it will be included in both the model's vector, map, and JSON representations. Attributes in the u_appends set will also respect the u_visible and u_hidden attribute settings configured on the model.

Special note should be given to the u_mutators static data member map, which maps accessors' attribute names to its methods. This data member is required because C++ does not currently support reflection.

Appending At Run Time

At runtime, you may instruct a model instance to append additional attributes using the append method. Or, you may use the setAppends method to override the entire set of appended attributes for a given model instance:

return user.append("is_admin").toVector();

return user.append({"is_admin", "is_banned"}).toMap();

return user.setAppends({"is_admin"}).toJson();

And you can also clear all appends or determine whether an append is defined:

user.clearAppends();

return user.hasAppend("is_admin");

Date Serialization

Customizing The Default Date Format

You may customize the default serialization format by overriding the serializeDate and serializeDateTime methods. These methods do not affect how your dates are formatted for storage in the database:

/*! 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");
}

Customizing The Date Format Per Attribute

You may customize the serialization format of individual TinyORM date attributes by specifying the date format in the model's cast declarations:

/*! The attributes that should be cast. */
inline static std::unordered_map<QString, CastItem> u_casts {
{"birthday", {CastType::CustomQDate, "yyyy-MM-dd"}},
{"joined_at", {CastType::CustomQDateTime, "yyyy-MM-dd HH:00"}},
};
- - +

TinyORM: Serialization

+ +

Introduction

+

When building APIs using TinyORM, you will often need to convert your models and relationships to vectors, maps, or JSON. TinyORM includes convenient methods for making these conversions, as well as controlling which attributes are included in the serialized representation of your models.

+

Serializing Models & Collections

+

Serializing To Vectors & Maps

+

To convert a model and its loaded relationships to a vector, you should use the toVector or toMap methods. This methods are recursive, so all attributes and all relations (including the relations of relations) will be converted to vectors:

+
using Models::User;

auto user = User::with("roles")->first();

return user->toVector();

return user->toMap();
+

The attributesToVector or attributesToMap methods may be used to convert a model's attributes to a vector or map but not its relationships:

+
auto user = User::first();

return user->attributesToVector();

return user->attributesToMap();
+

You may also convert entire collections of models to vectors or maps by calling the toVector or toMap methods on the collection instance:

+
ModelsCollection<User> users = User::with("roles")->all();

return users.toVector();

return users.toMap();
+

Serializing To JSON

+

To convert a model to JSON, you should use the toJson method. Like toVector or toMap, the toJson method is recursive, so all attributes and relations will be converted to JSON. You may also specify any JSON encoding options that are supported by QJsonDocument::toJson:

+
using Models::User;

auto user = User::with("roles")->find(1);

return user->toJson();

return user->toJson(QJsonDocument::Indented);
+

You may also convert entire collections of models to JSON by calling the toJson method on the collection instance:

+
ModelsCollection<User> users = User::with("roles")->findMany({1, 2});

return users.toJson();
+

You can also convert models to the QJsonObject and QJsonDocument using the toJsonArray and toJsonDocument methods and collection of models to QJsonArray and QJsonDocument using the toJsonArray and toJsonDocument methods.

+

Relationships

+

When a TinyORM model is converted to JSON, its loaded relationships will automatically be included as attributes on the JSON object. Also, though TinyORM relationship methods are defined using "camelCase" method names, a relationship's JSON attributes will be "snake_case".

+

This behavior is affected and can be overridden by the u_snakeAttributes static data member:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class Album final : public Model<Album, AlbumImage>
{
friend Model;
using Model::Model;

/*! Indicates whether attributes are snake_cased during serialization. */
inline static const bool u_snakeAttributes = false;
};
+

Hiding Attributes From JSON

+

Sometimes you may wish to limit the attributes, such as passwords, that are included in your model's vector, map, or JSON representation. To do so, add a u_hidden static data member to your model. Attributes that are listed in the u_hidden data member set will not be included in the serialized representation of your model:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! The attributes that should be hidden during serialization. */
inline static std::set<QString> u_hidden {"password"};
};
+
note

To hide relationships, add the relationship's method name to your TinyORM model's u_hidden static data member.

+

Alternatively, you may use the u_visible static data member to define an "allow list" of attributes that should be included in your model's vector, map, and JSON representation. All attributes that are not present in the u_visible set will be hidden during serialization:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! The attributes that should be visible during serialization. */
inline static std::set<QString> u_visible {
"first_name", "last_name",
};
};
+

Temporarily Modifying Attribute Visibility

+

If you would like to make some typically hidden attributes visible on a given model instance, you may use the makeVisible method. The makeVisible method returns a model reference:

+
return user.makeVisible("attribute").toMap();

return user.makeVisible({"id", "name"}).toMap();
+

Likewise, if you would like to hide some attributes that are typically visible, you may use the makeHidden method.

+
return user.makeHidden("attribute").toVector();

return user.makeHidden({"id", "name"}).toVector();
+

If you wish to temporarily override all of the visible or hidden attributes, you may use the setVisible and setHidden methods respectively:

+
return user.setVisible({"id", "name"}).toMap();

return user.setHidden({"email", "password", "note"}).toJson();
+

You can also clear all visible and hidden attributes or determine whether a visible / hidden attribute is defined:

+
user.clearVisible();

user.clearHidden();

return user.hasVisible("name");

return user.hasHidden("password");
+

Appending Values To JSON

+

Occasionally, when converting models to vector, map, or JSON, you may wish to add attributes that do not have a corresponding column in your database. To do so, first define an accessor for the value:

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

protected:
/*! Accessor to determine if the user is an administrator. */
Attribute isAdmin() const noexcept
{
return Attribute::make(/* get */ []() -> QVariant
{
return QStringLiteral("yes");
});
}
};
+

If you would like the accessor to always be appended to your model's vector, map, and JSON representations, you may add the attribute name to the u_appends data member set of your model. Note that attribute names are typically referenced using their "snake_case" serialized representation, even though the accessor's method name is defined using "camelCase":

+
#include <orm/tiny/model.hpp>

using Orm::Tiny::Model;

class User final : public Model<User>
{
friend Model;
using Model::Model;

/*! Map of mutator names to methods. */
inline static const QHash<QString, MutatorFunction> u_mutators {
{"is_admin", &User::isAdmin},
};

/*! The attributes that should be appended during serialization. */
std::set<QString> u_appends {"is_admin"};
};
+

Once the attribute has been added to the u_appends set, it will be included in both the model's vector, map, and JSON representations. Attributes in the u_appends set will also respect the u_visible and u_hidden attribute settings configured on the model.

+

Special note should be given to the u_mutators static data member map, which maps accessors' attribute names to its methods. This data member is required because C++ does not currently support reflection.

+

Appending At Run Time

+

At runtime, you may instruct a model instance to append additional attributes using the append method. Or, you may use the setAppends method to override the entire set of appended attributes for a given model instance:

+
return user.append("is_admin").toVector();

return user.append({"is_admin", "is_banned"}).toMap();

return user.setAppends({"is_admin"}).toJson();
+

And you can also clear all appends or determine whether an append is defined:

+
user.clearAppends();

return user.hasAppend("is_admin");
+

Date Serialization

+

Customizing The Default Date Format

+

You may customize the default serialization format by overriding the serializeDate and serializeDateTime methods. These methods do not affect how your dates are formatted for storage in the database:

+
/*! 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");
}
+

Customizing The Date Format Per Attribute

+

You may customize the serialization format of individual TinyORM date attributes by specifying the date format in the model's cast declarations:

+
/*! The attributes that should be cast. */
inline static std::unordered_map<QString, CastItem> u_casts {
{"birthday", {CastType::CustomQDate, "yyyy-MM-dd"}},
{"joined_at", {CastType::CustomQDateTime, "yyyy-MM-dd HH:00"}},
};
\ No newline at end of file