diff --git a/_elderjs/assets/svelte-cadeafe3.css b/_elderjs/assets/svelte-f4f8af75.css similarity index 55% rename from _elderjs/assets/svelte-cadeafe3.css rename to _elderjs/assets/svelte-f4f8af75.css index 677cf136..dde6ea03 100644 --- a/_elderjs/assets/svelte-cadeafe3.css +++ b/_elderjs/assets/svelte-f4f8af75.css @@ -1 +1 @@ -:root{--nav-height:41px;--bd-comment:#6a9955;--bd-content-dark:#22292e;--bd-sidebar-dark:#273c4a;--bd-content-light:#e4e4e4;--bd-sidebar-light:#a4beca}html[data-bs-theme=dark] header>nav,html[data-bs-theme=dark] main{background-color:var(--bd-content-dark)!important}html[data-bs-theme=light] header>nav,html[data-bs-theme=light] main{background-color:var(--bd-content-light)!important}.nav-divider.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{cursor:default;padding-left:1rem}.nav-divider.svelte-9zwk14 hr.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin:0}.nav-txt-divider.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{display:grid;align-items:center;justify-content:center;grid-template-columns:1fr auto 1fr;cursor:default;padding-left:1rem}.nav-txt-divider.svelte-9zwk14 hr.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin:0;margin-top:5px}.nav-txt-divider.svelte-9zwk14 span.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-left:.5rem;padding-right:.5rem;font-size:.75rem}main.svelte-9zwk14>.rightside.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,main.svelte-9zwk14>.sidebar.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{transition:transform .25s ease-out}main>.rightside.sidebar-show,main>.sidebar.sidebar-show{transform:translateX(0)}main>.rightside.sidebar-hide,main>.sidebar.sidebar-hide{transform:translateX(-100%)}main.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{display:grid;position:fixed;left:0;top:0;width:100%;height:100%}main.svelte-9zwk14>.rightside.svelte-9zwk14>div.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{position:relative;overflow-x:hidden;overflow-y:auto;top:var(--nav-height);height:calc(100vh - var(--nav-height));font-size:.85rem;padding-bottom:75px}main.svelte-9zwk14>.rightside>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,main.svelte-9zwk14>.sidebar>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-left:1rem;color:var(--bs-link-color);cursor:pointer}main.svelte-9zwk14>.rightside>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14:hover,main.svelte-9zwk14>.sidebar>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14:hover{text-decoration:underline;color:var(--bs-link-hover-color);border-left:.25rem rgba(51,103,145,.5) solid;padding-left:.75rem}main.svelte-9zwk14>.sidebar .accordion-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{border:0;background-color:initial}main.svelte-9zwk14>.sidebar .accordion-item .accordion-button.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-left:1rem;font-size:.85rem;font-weight:500;background-color:initial}main.svelte-9zwk14>.sidebar .accordion-item .accordion-button .bi.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14:first-child{margin-right:3px}main.svelte-9zwk14>.sidebar .accordion-item .accordion-body.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding:0}main.svelte-9zwk14>.sidebar .accordion-item .accordion-body .nav-item.active.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;color:var(--bs-emphasis-color)}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-right:1rem}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.svelte-9zwk14:first-child{padding-bottom:.5rem}main.svelte-9zwk14 .sidenav>.nav-item.right .nav-link.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-bottom:.2rem;padding-top:.2rem}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.nav-item.active.svelte-9zwk14:not(.right){border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;color:var(--bs-emphasis-color)}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.nav-item.right.active.svelte-9zwk14{border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;background-color:rgba(var(--bs-body-color-rgb),.1)}main.svelte-9zwk14>.rightside.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.nav-item.active.svelte-9zwk14{border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;background-color:rgba(var(--bs-body-color-rgb),.1)}.content.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{overflow:auto;scroll-behavior:smooth;margin-top:var(--nav-height)}.toc1.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500;text-transform:uppercase}.toc2.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500}.toc2.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:.25rem}.toc3.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500}.toc3.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:.75rem}.toc4.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500;font-size:.8rem!important}.toc4.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:1.25rem}.toc5.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:100}.toc5.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:2rem}.toc1.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc2.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc3.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc4.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc5.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-size:.9rem}.toc1.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc2.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc3.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc4.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc5.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{max-width:250px}.banner.svelte-nx1ckv{width:100%;height:150px;background-repeat:no-repeat;background-blend-mode:luminosity;background-color:var(--bs-body-bg);background-image:url(/stuff.jpg);background-size:cover;background-position:50% 0;opacity:.2;z-index:-1;position:sticky}.main-content.svelte-nx1ckv{margin-top:-145px}.background-svelte.svelte-18zbkxl.svelte-18zbkxl{background-image:url("/svelte_logo.svg")}.background-net.svelte-18zbkxl.svelte-18zbkxl{background-image:url("/NET_logo.png")}.background-pg.svelte-18zbkxl.svelte-18zbkxl{background-image:url("/postgresql-512.png")}.logo.svelte-18zbkxl.svelte-18zbkxl{width:35px;height:35px;background-repeat:no-repeat;background-size:contain;background-position:center;display:inline-block;border-radius:5px}.divider.svelte-18zbkxl.svelte-18zbkxl{display:grid;align-items:center;justify-content:center;grid-template-columns:1fr auto 1fr;padding-left:3.5rem;padding-right:3.5rem;margin-top:2rem;margin-bottom:2rem;font-size:smaller}.divider.svelte-18zbkxl>span.svelte-18zbkxl{margin-left:1rem;margin-right:1rem}.bannered.svelte-1bxfgrx.svelte-1bxfgrx{margin-top:-167px}.bannered.svelte-1bxfgrx h1{color:#dee2e6!important;z-index:1;position:relative;margin-bottom:25px}.bannered.svelte-1bxfgrx .post-meta{display:grid;grid-template-columns:auto min-content;margin-top:-6px;top:-50px;position:relative}.bannered.svelte-1bxfgrx .post-share{font-size:1.5rem;z-index:2;position:relative}.bannered.svelte-1bxfgrx .post-share a{color:#85a4bd!important}.bannered.svelte-1bxfgrx .post-share a:hover{color:#dee2e6!important}.bannered.svelte-1bxfgrx .post-details{display:grid;grid-template-columns:min-content auto;color:rgba(222,226,230,.7490196078)!important}.bannered.svelte-1bxfgrx .post-pic{border-radius:9999px;width:50px;height:50px;background-size:contain;margin-right:10px;background-repeat:round}.bannered.svelte-1bxfgrx .post-details-right{white-space:nowrap}.bannered.svelte-1bxfgrx .post-author{font-weight:700}.bannered.svelte-1bxfgrx .post-date{font-size:.75rem}.banner.svelte-1bxfgrx.svelte-1bxfgrx{background-size:cover;width:100%;height:177px;background-repeat:no-repeat;background-color:var(--bs-body-bg)}.blog-head.svelte-1bxfgrx a.svelte-1bxfgrx{font-size:.75rem}.blog-head.svelte-1bxfgrx>a.svelte-1bxfgrx{font-size:.75rem;float:right;font-style:italic}.links.svelte-1bxfgrx.svelte-1bxfgrx{display:flex;justify-content:space-between;width:100%}.links.svelte-1bxfgrx .link-title.svelte-1bxfgrx{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-size:.7rem}.img{max-width:100%}.categories.svelte-1bxfgrx a.svelte-1bxfgrx{color:#fff;font-size:.7rem}.links.svelte-oyz6mf.svelte-oyz6mf{display:flex;justify-content:space-between;width:100%}.links.svelte-oyz6mf .link-title.svelte-oyz6mf{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-size:.7rem}div.main-list.svelte-qb600q>div.svelte-qb600q{padding-left:2rem;margin-bottom:1rem}.content.svelte-qb600q.svelte-qb600q{padding-top:3rem}.bd-gutter.svelte-qb600q.svelte-qb600q{--bs-gutter-x:3rem}@media only screen and (min-width:478px){h1.svelte-qb600q.svelte-qb600q{font-size:3rem}}@media only screen and (min-width:478px){.lead.svelte-qb600q.svelte-qb600q{font-size:1.25rem}}@media only screen and (max-width:477px){.lead.svelte-qb600q.svelte-qb600q{font-size:1rem}}.lead.svelte-qb600q.svelte-qb600q{font-weight:500;color:var(--bs-secondary-color);position:relative}.lead.svelte-qb600q>a.svelte-qb600q{position:absolute;top:1px;left:-23px;visibility:hidden}.container.d-flex.svelte-qb600q:hover a.bookmark-target.svelte-qb600q{visibility:visible}.install .one-liner pre{margin-bottom:.25rem;padding-top:.5rem!important;padding-bottom:.5rem!important}.pill.svelte-qb600q.svelte-qb600q{display:inline-block;border-radius:1rem;color:var(--bs-secondary);border:1px solid var(--bs-primary);margin-bottom:.25rem;font-size:.75rem;padding-left:.5rem;padding-right:.5rem;font-family:var(--bs-font-monospace)}.perfs th{background-color:transparent!important}.perfs td{font-family:var(--bs-font-monospace);white-space:nowrap;text-align:right;background-color:transparent!important}i.tbl-info{margin-left:1rem}.background-floki.svelte-byttq0{background-image:url("/floki2.jpg");width:50px;height:50px;background-repeat:round;background-size:contain;background-position:center;display:inline-block;border-radius:9999px}img.svelte-byttq0{width:90px;height:90px}.lead.svelte-1jwx2u3.svelte-1jwx2u3{font-weight:500;color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-transform:capitalize;position:relative}.lead.svelte-1jwx2u3>a.svelte-1jwx2u3{position:absolute;top:1px;left:-23px;visibility:hidden}.container.d-flex.svelte-1jwx2u3:hover a.bookmark-target.svelte-1jwx2u3{visibility:visible}.docs.svelte-1jwx2u3.svelte-1jwx2u3{margin-top:-1rem}.card-list.svelte-kvbr7g{display:flex;flex-wrap:wrap;justify-content:center;gap:2rem}.card.svelte-kvbr7g{width:18rem;text-transform:none}.card-header.svelte-kvbr7g{background-size:cover;width:100%;height:110px;background-repeat:no-repeat;background-color:var(--bs-body-bg)}.card-body.small.svelte-kvbr7g{display:flex;align-items:center;justify-content:center}.card-corner.svelte-kvbr7g{font-size:.75rem;float:right;color:#fff!important}nav.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{box-shadow:none;height:var(--nav-height)}nav.svelte-30jr7w>div.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{gap:1rem}nav.svelte-30jr7w>div.svelte-30jr7w>.svelte-30jr7w.svelte-30jr7w{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}nav.svelte-30jr7w>div.svelte-30jr7w>.svelte-30jr7w>.svelte-30jr7w{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}nav.svelte-30jr7w>div a.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w:hover{color:#fff!important}#nav-btn.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{--bs-btn-color:#fff;--bs-btn-hover-color:#fff;--bs-btn-focus-color:#fff;--bs-btn-active-color:#fff;box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);color:var(--bs-emphasis-color)!important}html[data-bs-theme=dark] header>nav.navbar #nav-btn:hover{background-color:#21313c!important}html[data-bs-theme=light] header>nav.navbar #nav-btn:hover{background-color:#9eb6c9!important}html[data-bs-theme=dark] header>nav.navbar>div a{color:#adb5bd!important}html[data-bs-theme=light] header>nav.navbar>div a{color:#838383!important}.vr1.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{margin-left:1rem;margin-right:1rem;display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.right.svelte-30jr7w>span:first-of-type{display:flex;align-items:center}@media only screen and (max-width:400px){.right.svelte-30jr7w>span:first-of-type{display:none}}button#theme-btn.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{position:relative;border-radius:11px;display:block;width:40px;height:22px;flex-shrink:0;border:1px solid var(--bs-border-color);transition:border-color .25s;cursor:pointer;background-color:var(--bs-body-bg)}button#theme-btn.svelte-30jr7w>.check.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;transition:transform .25s;pointer-events:none}button#theme-btn.svelte-30jr7w>.check.svelte-30jr7w>.icon.svelte-30jr7w.svelte-30jr7w{position:relative;display:block;width:18px;height:18px;border-radius:50%;overflow:hidden}button#theme-btn.svelte-30jr7w>.check>.icon svg.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{position:absolute;top:3px;left:3px;width:12px;height:12px}button#theme-btn>.check.checked{transform:translate(18px)} \ No newline at end of file +:root{--nav-height:41px;--bd-comment:#6a9955;--bd-content-dark:#22292e;--bd-sidebar-dark:#273c4a;--bd-content-light:#e4e4e4;--bd-sidebar-light:#a4beca}html[data-bs-theme=dark] header>nav,html[data-bs-theme=dark] main{background-color:var(--bd-content-dark)!important}html[data-bs-theme=light] header>nav,html[data-bs-theme=light] main{background-color:var(--bd-content-light)!important}.nav-divider.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{cursor:default;padding-left:1rem}.nav-divider.svelte-9zwk14 hr.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin:0}.nav-txt-divider.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{display:grid;align-items:center;justify-content:center;grid-template-columns:1fr auto 1fr;cursor:default;padding-left:1rem}.nav-txt-divider.svelte-9zwk14 hr.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin:0;margin-top:5px}.nav-txt-divider.svelte-9zwk14 span.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-left:.5rem;padding-right:.5rem;font-size:.75rem}main.svelte-9zwk14>.rightside.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,main.svelte-9zwk14>.sidebar.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{transition:transform .25s ease-out}main>.rightside.sidebar-show,main>.sidebar.sidebar-show{transform:translateX(0)}main>.rightside.sidebar-hide,main>.sidebar.sidebar-hide{transform:translateX(-100%)}main.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{display:grid;position:fixed;left:0;top:0;width:100%;height:100%}main.svelte-9zwk14>.rightside.svelte-9zwk14>div.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{position:relative;overflow-x:hidden;overflow-y:auto;top:var(--nav-height);height:calc(100vh - var(--nav-height));font-size:.85rem;padding-bottom:75px}main.svelte-9zwk14>.rightside>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,main.svelte-9zwk14>.sidebar>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-left:1rem;color:var(--bs-link-color);cursor:pointer}main.svelte-9zwk14>.rightside>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14:hover,main.svelte-9zwk14>.sidebar>div>.navbar-nav .nav-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14:hover{text-decoration:underline;color:var(--bs-link-hover-color);border-left:.25rem rgba(51,103,145,.5) solid;padding-left:.75rem}main.svelte-9zwk14>.sidebar .accordion-item.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{border:0;background-color:initial}main.svelte-9zwk14>.sidebar .accordion-item .accordion-button.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-left:1rem;font-size:.85rem;font-weight:500;background-color:initial}main.svelte-9zwk14>.sidebar .accordion-item .accordion-button .bi.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14:first-child{margin-right:3px}main.svelte-9zwk14>.sidebar .accordion-item .accordion-body.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding:0}main.svelte-9zwk14>.sidebar .accordion-item .accordion-body .nav-item.active.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;color:var(--bs-emphasis-color)}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-right:1rem}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.svelte-9zwk14:first-child{padding-bottom:.5rem}main.svelte-9zwk14 .sidenav>.nav-item.right .nav-link.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{padding-bottom:.2rem;padding-top:.2rem}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.nav-item.active.svelte-9zwk14:not(.right){border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;color:var(--bs-emphasis-color)}main.svelte-9zwk14>.sidebar.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.nav-item.right.active.svelte-9zwk14{border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;background-color:rgba(var(--bs-body-color-rgb),.1)}main.svelte-9zwk14>.rightside.svelte-9zwk14>div.svelte-9zwk14>.navbar-nav.svelte-9zwk14>.nav-item.active.svelte-9zwk14{border-left:.25rem #336791 solid;padding-left:.75rem;font-weight:500;background-color:rgba(var(--bs-body-color-rgb),.1)}.content.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{overflow:auto;scroll-behavior:smooth;margin-top:var(--nav-height)}.toc1.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500;text-transform:uppercase}.toc2.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500}.toc2.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:.25rem}.toc3.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500}.toc3.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:.75rem}.toc4.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:500;font-size:.8rem!important}.toc4.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:1.25rem}.toc5.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-weight:100}.toc5.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{margin-left:2rem}.toc1.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc2.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc3.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc4.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc5.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{font-size:.9rem}.toc1.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc2.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc3.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc4.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14,.toc5.svelte-9zwk14>a.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14.svelte-9zwk14{max-width:250px}.bannered.svelte-1bxfgrx.svelte-1bxfgrx{margin-top:-167px}.bannered.svelte-1bxfgrx h1{color:#dee2e6!important;z-index:1;position:relative;margin-bottom:25px}.bannered.svelte-1bxfgrx .post-meta{display:grid;grid-template-columns:auto min-content;margin-top:-6px;top:-50px;position:relative}.bannered.svelte-1bxfgrx .post-share{font-size:1.5rem;z-index:2;position:relative}.bannered.svelte-1bxfgrx .post-share a{color:#85a4bd!important}.bannered.svelte-1bxfgrx .post-share a:hover{color:#dee2e6!important}.bannered.svelte-1bxfgrx .post-details{display:grid;grid-template-columns:min-content auto;color:rgba(222,226,230,.7490196078)!important}.bannered.svelte-1bxfgrx .post-pic{border-radius:9999px;width:50px;height:50px;background-size:contain;margin-right:10px;background-repeat:round}.bannered.svelte-1bxfgrx .post-details-right{white-space:nowrap}.bannered.svelte-1bxfgrx .post-author{font-weight:700}.bannered.svelte-1bxfgrx .post-date{font-size:.75rem}.banner.svelte-1bxfgrx.svelte-1bxfgrx{background-size:cover;width:100%;height:177px;background-repeat:no-repeat;background-color:var(--bs-body-bg)}.blog-head.svelte-1bxfgrx a.svelte-1bxfgrx{font-size:.75rem}.blog-head.svelte-1bxfgrx>a.svelte-1bxfgrx{font-size:.75rem;float:right;font-style:italic}.links.svelte-1bxfgrx.svelte-1bxfgrx{display:flex;justify-content:space-between;width:100%}.links.svelte-1bxfgrx .link-title.svelte-1bxfgrx{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-size:.7rem}.img{max-width:100%}.categories.svelte-1bxfgrx a.svelte-1bxfgrx{color:#fff;font-size:.7rem}.banner.svelte-nx1ckv{width:100%;height:150px;background-repeat:no-repeat;background-blend-mode:luminosity;background-color:var(--bs-body-bg);background-image:url(/stuff.jpg);background-size:cover;background-position:50% 0;opacity:.2;z-index:-1;position:sticky}.main-content.svelte-nx1ckv{margin-top:-145px}.background-svelte.svelte-18zbkxl.svelte-18zbkxl{background-image:url("/svelte_logo.svg")}.background-net.svelte-18zbkxl.svelte-18zbkxl{background-image:url("/NET_logo.png")}.background-pg.svelte-18zbkxl.svelte-18zbkxl{background-image:url("/postgresql-512.png")}.logo.svelte-18zbkxl.svelte-18zbkxl{width:35px;height:35px;background-repeat:no-repeat;background-size:contain;background-position:center;display:inline-block;border-radius:5px}.divider.svelte-18zbkxl.svelte-18zbkxl{display:grid;align-items:center;justify-content:center;grid-template-columns:1fr auto 1fr;padding-left:3.5rem;padding-right:3.5rem;margin-top:2rem;margin-bottom:2rem;font-size:smaller}.divider.svelte-18zbkxl>span.svelte-18zbkxl{margin-left:1rem;margin-right:1rem}.links.svelte-oyz6mf.svelte-oyz6mf{display:flex;justify-content:space-between;width:100%}.links.svelte-oyz6mf .link-title.svelte-oyz6mf{--bs-btn-padding-x:0.75rem;--bs-btn-padding-y:0.375rem;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-size:.7rem}div.main-list.svelte-qb600q>div.svelte-qb600q{padding-left:2rem;margin-bottom:1rem}.content.svelte-qb600q.svelte-qb600q{padding-top:3rem}.bd-gutter.svelte-qb600q.svelte-qb600q{--bs-gutter-x:3rem}@media only screen and (min-width:478px){h1.svelte-qb600q.svelte-qb600q{font-size:3rem}}@media only screen and (min-width:478px){.lead.svelte-qb600q.svelte-qb600q{font-size:1.25rem}}@media only screen and (max-width:477px){.lead.svelte-qb600q.svelte-qb600q{font-size:1rem}}.lead.svelte-qb600q.svelte-qb600q{font-weight:500;color:var(--bs-secondary-color);position:relative}.lead.svelte-qb600q>a.svelte-qb600q{position:absolute;top:1px;left:-23px;visibility:hidden}.container.d-flex.svelte-qb600q:hover a.bookmark-target.svelte-qb600q{visibility:visible}.install .one-liner pre{margin-bottom:.25rem;padding-top:.5rem!important;padding-bottom:.5rem!important}.pill.svelte-qb600q.svelte-qb600q{display:inline-block;border-radius:1rem;color:var(--bs-secondary);border:1px solid var(--bs-primary);margin-bottom:.25rem;font-size:.75rem;padding-left:.5rem;padding-right:.5rem;font-family:var(--bs-font-monospace)}.perfs th{background-color:transparent!important}.perfs td{font-family:var(--bs-font-monospace);white-space:nowrap;text-align:right;background-color:transparent!important}i.tbl-info{margin-left:1rem}.card-list.svelte-kvbr7g{display:flex;flex-wrap:wrap;justify-content:center;gap:2rem}.card.svelte-kvbr7g{width:18rem;text-transform:none}.card-header.svelte-kvbr7g{background-size:cover;width:100%;height:110px;background-repeat:no-repeat;background-color:var(--bs-body-bg)}.card-body.small.svelte-kvbr7g{display:flex;align-items:center;justify-content:center}.card-corner.svelte-kvbr7g{font-size:.75rem;float:right;color:#fff!important}.lead.svelte-1jwx2u3.svelte-1jwx2u3{font-weight:500;color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-transform:capitalize;position:relative}.lead.svelte-1jwx2u3>a.svelte-1jwx2u3{position:absolute;top:1px;left:-23px;visibility:hidden}.container.d-flex.svelte-1jwx2u3:hover a.bookmark-target.svelte-1jwx2u3{visibility:visible}.docs.svelte-1jwx2u3.svelte-1jwx2u3{margin-top:-1rem}nav.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{box-shadow:none;height:var(--nav-height)}nav.svelte-30jr7w>div.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{gap:1rem}nav.svelte-30jr7w>div.svelte-30jr7w>.svelte-30jr7w.svelte-30jr7w{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}nav.svelte-30jr7w>div.svelte-30jr7w>.svelte-30jr7w>.svelte-30jr7w{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}nav.svelte-30jr7w>div a.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w:hover{color:#fff!important}#nav-btn.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{--bs-btn-color:#fff;--bs-btn-hover-color:#fff;--bs-btn-focus-color:#fff;--bs-btn-active-color:#fff;box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);color:var(--bs-emphasis-color)!important}html[data-bs-theme=dark] header>nav.navbar #nav-btn:hover{background-color:#21313c!important}html[data-bs-theme=light] header>nav.navbar #nav-btn:hover{background-color:#9eb6c9!important}html[data-bs-theme=dark] header>nav.navbar>div a{color:#adb5bd!important}html[data-bs-theme=light] header>nav.navbar>div a{color:#838383!important}.vr1.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{margin-left:1rem;margin-right:1rem;display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.right.svelte-30jr7w>span:first-of-type{display:flex;align-items:center}@media only screen and (max-width:400px){.right.svelte-30jr7w>span:first-of-type{display:none}}button#theme-btn.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{position:relative;border-radius:11px;display:block;width:40px;height:22px;flex-shrink:0;border:1px solid var(--bs-border-color);transition:border-color .25s;cursor:pointer;background-color:var(--bs-body-bg)}button#theme-btn.svelte-30jr7w>.check.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;transition:transform .25s;pointer-events:none}button#theme-btn.svelte-30jr7w>.check.svelte-30jr7w>.icon.svelte-30jr7w.svelte-30jr7w{position:relative;display:block;width:18px;height:18px;border-radius:50%;overflow:hidden}button#theme-btn.svelte-30jr7w>.check>.icon svg.svelte-30jr7w.svelte-30jr7w.svelte-30jr7w{position:absolute;top:3px;left:3px;width:12px;height:12px}button#theme-btn>.check.checked{transform:translate(18px)}.background-floki.svelte-byttq0{background-image:url("/floki2.jpg");width:50px;height:50px;background-repeat:round;background-size:contain;background-position:center;display:inline-block;border-radius:9999px}img.svelte-byttq0{width:90px;height:90px} \ No newline at end of file diff --git a/blog/common-sense-design/index.html b/blog/common-sense-design/index.html index 66b31c79..935c9838 100644 --- a/blog/common-sense-design/index.html +++ b/blog/common-sense-design/index.html @@ -1,4 +1,4 @@ -Common Sense Software Design

Common Sense Software Design

This diagram is a representation of a design approach I refer to as the Common Sense Software Design for RDBMS-backed type of software.

1) Service Class

Service class does stuff.

It is the complete feature implementation that fulfills functional requirements:

  • Use parameters or requests to:
    • Create database queries, either with SQL or ORM, and execute and retrieve the data.
    • Call stored procedures or database functions, and retrieve the data.
  • Process the database results and form results or responses.

Pseudo example:

class MyFeature(Database db /*, other dependencies*/)
+Common Sense Software Design

Common Sense Software Design

This diagram is a representation of a design approach I refer to as the Common Sense Software Design for RDBMS-backed type of software.

1) Service Class

Service class does stuff.

It is the complete feature implementation that fulfills functional requirements:

  • Use parameters or requests to:
    • Create database queries, either with SQL or ORM, and execute and retrieve the data.
    • Call stored procedures or database functions, and retrieve the data.
  • Process the database results and form results or responses.

Pseudo example:

class MyFeature(Database db /*, other dependencies*/)
 {
     int ServiceMethod1(int p1, int p2)
     {
diff --git a/blog/haters-build-software/index.html b/blog/haters-build-software/index.html
index e245c528..806948dc 100644
--- a/blog/haters-build-software/index.html
+++ b/blog/haters-build-software/index.html
@@ -1 +1 @@
-Haters Build Software

Haters Build Software - Not Architectures

In all seriousness, and in my opinion - I don't think the goal of a software design should ever be to satisfy some particular architectural style.

I think that's nonsense, really do.

First and foremost, the primary goal is, of course, to satisfy your functional requirements.

The secondary goal is to achieve specific system attributes (also known as the "ilities" - look it up).

ility (plural ilities) (software engineering) An abstract quality that good software should exhibit. One reason to use software libraries is that the authors have had time to add ilities in addition to the basic functionality.

There are quite a number of these. In fact, Wikipedia says there are 80+ attributes your system may have.

That's a lot, but that's not the only issue.

Some ilities will be derived from your functional requirements. For example:

  • High Availability. That's an architecturally significant requirement that is a feature that allows your users to accomplish their tasks.
  • Scalability. Imagine you are building software in a football domain, and every two years during the Euro Cup and the World Cup, the number of concurrent users is *10,000 (at least). You need to plan and design for that scalability requirement, and again, that is a feature that will allow your users to accomplish their tasks (during those Cup games).

But that's not all.

Some "ilities" (or architecturally significant requirements to be academic about it) - are in direct contradiction with each other (or you can't have them all).

For example, you want high Maintainability (which implies Changeability and Flexibility), and you also want high Security.

Not happening.

Well, high Security assumes that you'll be introducing a couple of new layers of security; you want to have, of course, fine-grained user roles; of course, you'll need to have attached permission on those roles, permissions will have policies, and then you'll need to defined policies, perhaps on a row- level, then you need to think about row-level policy execution, etc., etc., and of course, you'll need a special and separate application that will manage all that, and finally, someone (meaning you) will have to maintain all of that, so much for maintainability.

And, finally, those "ilities" may apply to just one portion of a system, may depend on your environment, etc.

The point is that the goal of software architecture is not to achieve the pureness of a particular architectural style (Clean Architecture, for example).

Your goal should be to satisfy architecturally significant requirements (or "ilities") that are the result of careful and thorough analysis, so you may end up with a system that has specific system attributes you designed for.

That's a mouthful, but it is what it is, which brings me finally to the Clean Architecture (TM).

Correct me if I'm wrong, but according to Lindkein's posts and comments, the number one benefit of Clean Architecture is as follows:

  1. 𝗜𝗻𝗱𝗲𝗽𝗲𝗻𝗱𝗲𝗻𝗰𝗲 𝗳𝗿𝗼𝗺 𝗙𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸𝘀: Clean Architecture doesn't tie you to specific tools or frameworks. This allows you to swap out database ORMs, web frameworks or libraries without impacting the core business logic.

... umm, I have questions ... 🤔

So basically, your "ilities" are already set for you; you don't have to do anything - regardless of your system's unique requirements.

And I need to figure out where even to start with this...

  • Swapping databases. I've done it only once, like 15 years ago, and it was nerve-wracking. As far as I can see, that is the case with other people, too. Swapping databases is a very rare and extraordinary occurrence. But even that is always one RDBMS type for the other. I have never heard that someone swapped RDMBS for Docubase or Key-Value Storage just like that.
  • Swapping ORM's. Well, the entire idea with ORMs is that they can abstract your RDBMS so that you can swap your RDBMS database more easily. And they do help in that regard, I admit. But swapping ORM? Lol, are you kidding me? I have heard only once in my career that there was a need to replace the ORM library, basically, some exotic ORM library became unsupported and needed to be replaced with the supported one. But that implied literally rewriting everything from the ground up. So, essentially, we should be able to swap the thing that allows us to swap the other thing. Got it.
  • Swapping web frameworks. Now, this is just ridiculous. I'm not going to comment on that. Never even heard of such a thing.

Since I'm now considered as the "Clean Architecture" hater (ok, I admit, I am), and, also, I'm asked to provide an alternative, so here it is:

  • Carefully and thoroughly analyze your system, your requirements, and your environment - to distill your architecturally significant requirements. Find out what your "ilities" are and prioritize them accordingly.
  • Select the most appropriate database (PostgreSQL is always a good choice, but there are others like Snowflake, BigQuery, MariaDB, etc.) - and get the most out of it. You'll find out that are extremely powerful, capable, and feature-rich.
  • Don't abstract it away because the architectural flavor of the day says so - do it instead because your "ilities" say so. And they rarely do. Otherwise, you'll be denied many of those powerful features.

I'm not in a business telling other people what to do, I'm in business telling computers what to do.

But I wanted to say this given the amount of discussions lately over the Clean Architecture.

To receive notifications about new posts and updates, consider subscribing to my LinkdIn page:
vb-software linkedin

You will receive notifications about new posts on your LinkedIn feed.
Comments
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +Haters Build Software

Haters Build Software - Not Architectures

In all seriousness, and in my opinion - I don't think the goal of a software design should ever be to satisfy some particular architectural style.

I think that's nonsense, really do.

First and foremost, the primary goal is, of course, to satisfy your functional requirements.

The secondary goal is to achieve specific system attributes (also known as the "ilities" - look it up).

ility (plural ilities) (software engineering) An abstract quality that good software should exhibit. One reason to use software libraries is that the authors have had time to add ilities in addition to the basic functionality.

There are quite a number of these. In fact, Wikipedia says there are 80+ attributes your system may have.

That's a lot, but that's not the only issue.

Some ilities will be derived from your functional requirements. For example:

  • High Availability. That's an architecturally significant requirement that is a feature that allows your users to accomplish their tasks.
  • Scalability. Imagine you are building software in a football domain, and every two years during the Euro Cup and the World Cup, the number of concurrent users is *10,000 (at least). You need to plan and design for that scalability requirement, and again, that is a feature that will allow your users to accomplish their tasks (during those Cup games).

But that's not all.

Some "ilities" (or architecturally significant requirements to be academic about it) - are in direct contradiction with each other (or you can't have them all).

For example, you want high Maintainability (which implies Changeability and Flexibility), and you also want high Security.

Not happening.

Well, high Security assumes that you'll be introducing a couple of new layers of security; you want to have, of course, fine-grained user roles; of course, you'll need to have attached permission on those roles, permissions will have policies, and then you'll need to defined policies, perhaps on a row- level, then you need to think about row-level policy execution, etc., etc., and of course, you'll need a special and separate application that will manage all that, and finally, someone (meaning you) will have to maintain all of that, so much for maintainability.

And, finally, those "ilities" may apply to just one portion of a system, may depend on your environment, etc.

The point is that the goal of software architecture is not to achieve the pureness of a particular architectural style (Clean Architecture, for example).

Your goal should be to satisfy architecturally significant requirements (or "ilities") that are the result of careful and thorough analysis, so you may end up with a system that has specific system attributes you designed for.

That's a mouthful, but it is what it is, which brings me finally to the Clean Architecture (TM).

Correct me if I'm wrong, but according to Lindkein's posts and comments, the number one benefit of Clean Architecture is as follows:

  1. 𝗜𝗻𝗱𝗲𝗽𝗲𝗻𝗱𝗲𝗻𝗰𝗲 𝗳𝗿𝗼𝗺 𝗙𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸𝘀: Clean Architecture doesn't tie you to specific tools or frameworks. This allows you to swap out database ORMs, web frameworks or libraries without impacting the core business logic.

... umm, I have questions ... 🤔

So basically, your "ilities" are already set for you; you don't have to do anything - regardless of your system's unique requirements.

And I need to figure out where even to start with this...

  • Swapping databases. I've done it only once, like 15 years ago, and it was nerve-wracking. As far as I can see, that is the case with other people, too. Swapping databases is a very rare and extraordinary occurrence. But even that is always one RDBMS type for the other. I have never heard that someone swapped RDMBS for Docubase or Key-Value Storage just like that.
  • Swapping ORM's. Well, the entire idea with ORMs is that they can abstract your RDBMS so that you can swap your RDBMS database more easily. And they do help in that regard, I admit. But swapping ORM? Lol, are you kidding me? I have heard only once in my career that there was a need to replace the ORM library, basically, some exotic ORM library became unsupported and needed to be replaced with the supported one. But that implied literally rewriting everything from the ground up. So, essentially, we should be able to swap the thing that allows us to swap the other thing. Got it.
  • Swapping web frameworks. Now, this is just ridiculous. I'm not going to comment on that. Never even heard of such a thing.

Since I'm now considered as the "Clean Architecture" hater (ok, I admit, I am), and, also, I'm asked to provide an alternative, so here it is:

  • Carefully and thoroughly analyze your system, your requirements, and your environment - to distill your architecturally significant requirements. Find out what your "ilities" are and prioritize them accordingly.
  • Select the most appropriate database (PostgreSQL is always a good choice, but there are others like Snowflake, BigQuery, MariaDB, etc.) - and get the most out of it. You'll find out that are extremely powerful, capable, and feature-rich.
  • Don't abstract it away because the architectural flavor of the day says so - do it instead because your "ilities" say so. And they rarely do. Otherwise, you'll be denied many of those powerful features.

I'm not in a business telling other people what to do, I'm in business telling computers what to do.

But I wanted to say this given the amount of discussions lately over the Clean Architecture.

To receive notifications about new posts and updates, consider subscribing to my LinkdIn page:
vb-software linkedin

You will receive notifications about new posts on your LinkedIn feed.
Comments
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blog/micro-orm/index.html b/blog/micro-orm/index.html index 3ebbc24f..63ae0db3 100644 --- a/blog/micro-orm/index.html +++ b/blog/micro-orm/index.html @@ -1,4 +1,4 @@ -What is Micro ORM?

What is Micro ORM?

In software development, we all know very well what an ORM is:

A tool or usually a program library that implements object-relational mapping (ORM, O/RM), or O/R mapping.

This mapping is a two-way or bi-directional mapping:

  1. From the database to the database client (your application). DB -> APP

Or, to be more specific: from the query results - to your application memory structures, such as object instances and other structures.

  1. From the database client (your application) to the database. APP -> DB

Or, to be more specific: from the query and command programming constructs in your application language (such as C# Linq command and queries) - to query that your database understands and can run such as SQL typically.

The best-known and most widely used ORM in the .NET ecosystem is, of course, the Microsoft Entity Framework, which is, of course, the full-blown ORM that implements wo-way (bi-directional) mappings.

On the other hand, the Micro ORM means it's just a lightweight mapper that maps only one way and one way only. From the query results - to your application memory structures, such as object instances and other structures.

Micro ORM is a term invented and popularized by Dapper, the best-known MicroORM built by Stackoverflow. In practice, that means that when using Micro ORM - all SQL has to be in a raw string command (a raw SQL). For example:

public class Film
+What is Micro ORM?

What is Micro ORM?

In software development, we all know very well what an ORM is:

A tool or usually a program library that implements object-relational mapping (ORM, O/RM), or O/R mapping.

This mapping is a two-way or bi-directional mapping:

  1. From the database to the database client (your application). DB -> APP

Or, to be more specific: from the query results - to your application memory structures, such as object instances and other structures.

  1. From the database client (your application) to the database. APP -> DB

Or, to be more specific: from the query and command programming constructs in your application language (such as C# Linq command and queries) - to query that your database understands and can run such as SQL typically.

The best-known and most widely used ORM in the .NET ecosystem is, of course, the Microsoft Entity Framework, which is, of course, the full-blown ORM that implements wo-way (bi-directional) mappings.

On the other hand, the Micro ORM means it's just a lightweight mapper that maps only one way and one way only. From the query results - to your application memory structures, such as object instances and other structures.

Micro ORM is a term invented and popularized by Dapper, the best-known MicroORM built by Stackoverflow. In practice, that means that when using Micro ORM - all SQL has to be in a raw string command (a raw SQL). For example:

public class Film
 {
     public int FilmId { get; set; }
     public string Title { get; set; }
diff --git a/blog/npgsqlrest-update1.6.2/index.html b/blog/npgsqlrest-update1.6.2/index.html
index 03f1705e..bbfadbd2 100644
--- a/blog/npgsqlrest-update1.6.2/index.html
+++ b/blog/npgsqlrest-update1.6.2/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest Update 1.6.2

NpgsqlRest 1.6.2 Update

I'm glad to see that the NpgsqlRest Nuget library is getting matured and refined. Here are some highlights from the changelog since version 1.4.0:

Strict Function Support

Functions in a strict mode (labeled as STRICT or RETURNS NULL ON NULL INPUT) are the functions that will always return NULL if at least one of the parameters is NULL. In that case, the function isn't even executed.

NpgsqlRest will not even try to execute strict functions when at least one of the parameters is NULL. Instead, the call will return HTTP 204 NoContent and bypass talking to the database altogether.

Command Callback

You can add a lambda callback that will receive a created data reader for the PostgreSQL function and the current HTTP context. If you choose to modify the HTTP response, the default behavior will be skipped in favor of your customized response.

For example, if we have some function that returns data, we can add a handler to render CSV instead of the default JSON response:

app.UseNpgsqlRest(new(connectionString)
+NpgsqlRest Update 1.6.2

NpgsqlRest 1.6.2 Update

I'm glad to see that the NpgsqlRest Nuget library is getting matured and refined. Here are some highlights from the changelog since version 1.4.0:

Strict Function Support

Functions in a strict mode (labeled as STRICT or RETURNS NULL ON NULL INPUT) are the functions that will always return NULL if at least one of the parameters is NULL. In that case, the function isn't even executed.

NpgsqlRest will not even try to execute strict functions when at least one of the parameters is NULL. Instead, the call will return HTTP 204 NoContent and bypass talking to the database altogether.

Command Callback

You can add a lambda callback that will receive a created data reader for the PostgreSQL function and the current HTTP context. If you choose to modify the HTTP response, the default behavior will be skipped in favor of your customized response.

For example, if we have some function that returns data, we can add a handler to render CSV instead of the default JSON response:

app.UseNpgsqlRest(new(connectionString)
 {
     CommandCallbackAsync = async p =>
     {
diff --git a/blog/npgsqlrest-v2/index.html b/blog/npgsqlrest-v2/index.html
index 080d6dd4..c0a459b8 100644
--- a/blog/npgsqlrest-v2/index.html
+++ b/blog/npgsqlrest-v2/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest v2 Update 🐘🔥

NpgsqlRest Version 2 Update 🐘🔥

  • NpgsqlRest is .NET8 Nuget library for automatic REST API from PostgreSQL databases, implemented as .NET8 Middleware.
  • See the GitHub Readme file.
  • NpgsqlRest Version 2 is a major upgrade that introduces extendiblity with the concept of plugins..

There are two types of plugins:

  1. Routine Source Plugins
  2. Code Generation Plugins

Routine Source Plugins

Routine Source Plugins are plugins that define various sources - from which automatic REST API can be built.

For example, functions are stored procedures source is already built-in into the library and it has been since version 1.

With version 2, you can add the CRUD source plugin, published as a separate, plugin library NpgsqlRest.CrudSource. This plugin can generate automatic REST API for PostgreSQL tables and views, that can:

  • Insert into tables and insertable views with or without conflict resolutions and with or without returning the inserted record (Create).
  • Read data from tables and views using select operation and filtering by provided parameters (Read).
  • Update data in tables and updateable views with or without returning updated data (Update).
  • Delete data in tables and deletable views with or without returning deleted data (Delete).

See NpgsqlRest.CrudSource for more information.

Code Generation Plugins

Code Generation Plugins are plugins that are executed after the REST API has been defined and generated from the source. As such, they are used mostly for automatic generations of, well, more code.

Code Generation Plugins automatically generate code.

From the first version - there was always a feature that, based on generated REST APIs - could generate the HTTP Code File.

Those HTTP Code files are the REST Client files, with syntax based on the Visual Studio Code REST Client extension. These files can be used with Visual Studio Code or with the latest Visual Studio to test and run easily REST endpoints.

With version 2, the code generation interface is standardized and the HTTP Code Files functionality is moved to a separate plugin: NpgsqlRest.HttpFiles

Now, there are no more default code generators in the core library - they are all added through plugins as additional libraries.

Besides HTTP Code Files - there is also a Typescript Client Code Generator Plugin: NpgsqlRest.TsClient.

This plugin was created and developed to avoid writing tedious and boring Typescript code. Since REST API endpoints are now automatically generated - there is no reason not to generate API calls for the frontend in Typescript.

Short example of the part of the generated Typescript module:

interface IGetDuplicateEmailsResponse {
+NpgsqlRest v2 Update 🐘🔥

NpgsqlRest Version 2 Update 🐘🔥

  • NpgsqlRest is .NET8 Nuget library for automatic REST API from PostgreSQL databases, implemented as .NET8 Middleware.
  • See the GitHub Readme file.
  • NpgsqlRest Version 2 is a major upgrade that introduces extendiblity with the concept of plugins..

There are two types of plugins:

  1. Routine Source Plugins
  2. Code Generation Plugins

Routine Source Plugins

Routine Source Plugins are plugins that define various sources - from which automatic REST API can be built.

For example, functions are stored procedures source is already built-in into the library and it has been since version 1.

With version 2, you can add the CRUD source plugin, published as a separate, plugin library NpgsqlRest.CrudSource. This plugin can generate automatic REST API for PostgreSQL tables and views, that can:

  • Insert into tables and insertable views with or without conflict resolutions and with or without returning the inserted record (Create).
  • Read data from tables and views using select operation and filtering by provided parameters (Read).
  • Update data in tables and updateable views with or without returning updated data (Update).
  • Delete data in tables and deletable views with or without returning deleted data (Delete).

See NpgsqlRest.CrudSource for more information.

Code Generation Plugins

Code Generation Plugins are plugins that are executed after the REST API has been defined and generated from the source. As such, they are used mostly for automatic generations of, well, more code.

Code Generation Plugins automatically generate code.

From the first version - there was always a feature that, based on generated REST APIs - could generate the HTTP Code File.

Those HTTP Code files are the REST Client files, with syntax based on the Visual Studio Code REST Client extension. These files can be used with Visual Studio Code or with the latest Visual Studio to test and run easily REST endpoints.

With version 2, the code generation interface is standardized and the HTTP Code Files functionality is moved to a separate plugin: NpgsqlRest.HttpFiles

Now, there are no more default code generators in the core library - they are all added through plugins as additional libraries.

Besides HTTP Code Files - there is also a Typescript Client Code Generator Plugin: NpgsqlRest.TsClient.

This plugin was created and developed to avoid writing tedious and boring Typescript code. Since REST API endpoints are now automatically generated - there is no reason not to generate API calls for the frontend in Typescript.

Short example of the part of the generated Typescript module:

interface IGetDuplicateEmailsResponse {
     email: string | null;
     count: number | null;
 }
diff --git a/blog/npgsqlrest/index.html b/blog/npgsqlrest/index.html
index 7fa88c8c..2a8d754f 100644
--- a/blog/npgsqlrest/index.html
+++ b/blog/npgsqlrest/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest NuGet Library

NpgsqlRest NuGet Library

NpgsqlRest is a .NET8 NuGet library that can build a RESTful API from the existing PostgreSQL routines (functions or procedures) with a single extension on a web application builder.

You can think of it as PostgREST, but only for routines (functions or procedures), since PostgREST is doing a lot more. It is implemented as .NET8 middleware so you can create custom builds, or integrate with your .NET8 projects, and it is highly customizable, with some unique features.

The library is AOT-ready, which means it can utilize .NET AOT feature to create self-contained, native binary executables, but more on that later.

Motivation

This is built to be a crucial part of the future low-code data platform based on PostgreSQL. And, as such it was built to satisfy very specific requirements (as opposed to catering to a wider audience). For example, it has two dependencies 1) the latest Microsoft.NET.Sdk.Web that targets net8.0 framework. 2) the latest Npgsql ADO.NET Data Provider for PostgreSQL (current version 8.0.1). Those dependencies will be updated with each new release. If you need to work with older versions, you need to either 1) update them in your project - or - 2) clone the NpgsqlRest repository and make a custom build with downgraded dependencies.

Furthermore, future developments such as new features highly depend on the main project that will be using this library, but with the right sponsorship, anything is possible.

Features and Usage

Most basic usage in a standard .NET8 web application looks like this:

using NpgsqlRest;
+NpgsqlRest NuGet Library

NpgsqlRest NuGet Library

NpgsqlRest is a .NET8 NuGet library that can build a RESTful API from the existing PostgreSQL routines (functions or procedures) with a single extension on a web application builder.

You can think of it as PostgREST, but only for routines (functions or procedures), since PostgREST is doing a lot more. It is implemented as .NET8 middleware so you can create custom builds, or integrate with your .NET8 projects, and it is highly customizable, with some unique features.

The library is AOT-ready, which means it can utilize .NET AOT feature to create self-contained, native binary executables, but more on that later.

Motivation

This is built to be a crucial part of the future low-code data platform based on PostgreSQL. And, as such it was built to satisfy very specific requirements (as opposed to catering to a wider audience). For example, it has two dependencies 1) the latest Microsoft.NET.Sdk.Web that targets net8.0 framework. 2) the latest Npgsql ADO.NET Data Provider for PostgreSQL (current version 8.0.1). Those dependencies will be updated with each new release. If you need to work with older versions, you need to either 1) update them in your project - or - 2) clone the NpgsqlRest repository and make a custom build with downgraded dependencies.

Furthermore, future developments such as new features highly depend on the main project that will be using this library, but with the right sponsorship, anything is possible.

Features and Usage

Most basic usage in a standard .NET8 web application looks like this:

using NpgsqlRest;
 
 var builder = WebApplication.CreateBuilder(args);
 var app = builder.Build();
diff --git a/blog/pgroutiner/code-gen/index.html b/blog/pgroutiner/code-gen/index.html
index 48edf264..52f0c667 100644
--- a/blog/pgroutiner/code-gen/index.html
+++ b/blog/pgroutiner/code-gen/index.html
@@ -1,4 +1,4 @@
-PgRoutiner Code-Gen

PgRoutiner Code-Gen

Data-Access Extensions

pgroutiner -r | --r | -rout | --rout | -routines | --routines
pgroutiner -r | --r | -rout | --rout | -routines | --routines

// pgroutiner auto-generated code
+PgRoutiner Code-Gen

PgRoutiner Code-Gen

Data-Access Extensions

pgroutiner -r | --r | -rout | --rout | -routines | --routines
pgroutiner -r | --r | -rout | --rout | -routines | --routines

// pgroutiner auto-generated code
 #pragma warning disable CS8632
 #pragma warning disable CS8618
 using System.Threading.Tasks;
diff --git a/blog/pgroutiner/concept/index.html b/blog/pgroutiner/concept/index.html
index 651e4047..475a935a 100644
--- a/blog/pgroutiner/concept/index.html
+++ b/blog/pgroutiner/concept/index.html
@@ -1,4 +1,4 @@
-PgRoutiner Concept

PgRoutiner High-Level Concept

PgRoutiner is a command-line set of tools that work seamlessly with your NET project configuration in JSON files.

.NET projects usually have some configuration files, for example, appsettings.json or appsettings.Development.json or both. And usually, those files will contain a workable connection string. For example, they might look something like this:

{
+PgRoutiner Concept

PgRoutiner High-Level Concept

PgRoutiner is a command-line set of tools that work seamlessly with your NET project configuration in JSON files.

.NET projects usually have some configuration files, for example, appsettings.json or appsettings.Development.json or both. And usually, those files will contain a workable connection string. For example, they might look something like this:

{
   "ConnectionStrings": {
     "MyConnection": "Server=localhost;Db=dvdrental;Port=5432;User Id=postgres;Password=postgres;"
   },
diff --git a/blog/pgroutiner/database/index.html b/blog/pgroutiner/database/index.html
index 56206554..f443fad8 100644
--- a/blog/pgroutiner/database/index.html
+++ b/blog/pgroutiner/database/index.html
@@ -1,4 +1,4 @@
-PgRoutiner Database Management

PgRoutiner Database Management

List Database Objects

pgroutiner -l | -ls | --ls | --list [ term ]
pgroutiner -l | -ls | --ls | --list [ term ]

Search Database Objects

pgroutiner -s | --s | --search [ term ]
pgroutiner -s | --s | --search [ term ]

View Database Object Definitions

pgroutiner -def | -ddl | --ddl | -definition | --definition [ name|names ]
pgroutiner -def | -ddl | --ddl | -definition | --definition [ name|names ]

PSQL Tool

pgroutiner -sql | -psql | --sql | --psql
pgroutiner -sql | -psql | --sql | --psql

Execution

pgroutiner -x | --x | -exec | --exec | -execute | --execute | --execute [ command|commands|script|dir ]
pgroutiner -x | --x | -exec | --exec | -execute | --execute | --execute [ command|commands|script|dir ]

Insert Scripts

pgroutiner -i | -ins | -inserts | --inserts [ table|tables|view|views|query|queries ]
pgroutiner -i | -ins | -inserts | --inserts [ table|tables|view|views|query|queries ]

Backup and Restore Helpers

pgroutiner --backup [ filename|name_pattern ]
pgroutiner --backup [ filename|name_pattern ]
pgroutiner --restore [ filename|name_pattern ]
pgroutiner --restore [ filename|name_pattern ]

Schema Files and Data Files

pgroutiner -sd | --schema-dump
+PgRoutiner Database Management

PgRoutiner Database Management

List Database Objects

pgroutiner -l | -ls | --ls | --list [ term ]
pgroutiner -l | -ls | --ls | --list [ term ]

Search Database Objects

pgroutiner -s | --s | --search [ term ]
pgroutiner -s | --s | --search [ term ]

View Database Object Definitions

pgroutiner -def | -ddl | --ddl | -definition | --definition [ name|names ]
pgroutiner -def | -ddl | --ddl | -definition | --definition [ name|names ]

PSQL Tool

pgroutiner -sql | -psql | --sql | --psql
pgroutiner -sql | -psql | --sql | --psql

Execution

pgroutiner -x | --x | -exec | --exec | -execute | --execute | --execute [ command|commands|script|dir ]
pgroutiner -x | --x | -exec | --exec | -execute | --execute | --execute [ command|commands|script|dir ]

Insert Scripts

pgroutiner -i | -ins | -inserts | --inserts [ table|tables|view|views|query|queries ]
pgroutiner -i | -ins | -inserts | --inserts [ table|tables|view|views|query|queries ]

Backup and Restore Helpers

pgroutiner --backup [ filename|name_pattern ]
pgroutiner --backup [ filename|name_pattern ]
pgroutiner --restore [ filename|name_pattern ]
pgroutiner --restore [ filename|name_pattern ]

Schema Files and Data Files

pgroutiner -sd | --schema-dump
 pgroutiner -sd | --schema-dump -sdf | --schema-dump-file [ schema filename ]
pgroutiner -sd | --schema-dump
 pgroutiner -sd | --schema-dump -sdf | --schema-dump-file [ schema filename ]
pgroutiner -dd | --data-dump -dumplist [ object list ]
 pgroutiner -dd | --data-dump -dumplist [ object list ] -ddf | --data-dump-file [ data dump filename ]
pgroutiner -dd | --data-dump -dumplist [ object list ]
diff --git a/blog/pgroutiner/documentation/index.html b/blog/pgroutiner/documentation/index.html
index e846d59e..87310452 100644
--- a/blog/pgroutiner/documentation/index.html
+++ b/blog/pgroutiner/documentation/index.html
@@ -1,3 +1,3 @@
-PgRoutiner Documentation

PgRoutiner Documentation

pgroutiner -md --markdown
+PgRoutiner Documentation

PgRoutiner Documentation

pgroutiner -md --markdown
 pgroutiner -md --markdown -mdf --md-file [ md filename ]
pgroutiner -md --markdown
 pgroutiner -md --markdown -mdf --md-file [ md filename ]

Example

MORE ON PGROUTINER
To receive notifications about new posts and updates, consider subscribing to my LinkdIn page:
vb-software linkedin

You will receive notifications about new posts on your LinkedIn feed.
Comments
\ No newline at end of file diff --git a/blog/pgroutiner/index.html b/blog/pgroutiner/index.html index abe79c15..236813a7 100644 --- a/blog/pgroutiner/index.html +++ b/blog/pgroutiner/index.html @@ -1 +1 @@ -PgRoutiner Blog

PgRoutiner Blog

PgRoutiner is a set of command-line tools I created for fun and for my development needs while working on various .NET and PostgreSQL projects.

It integrates with .NET project configuration and allows you to do various stuff out of the box, no configuration needed. For example:

This is just one small example. PgRoutiner is incredibly feature-rich. As it happened, I was constantly adding new features as I was working on other projects. Initially, it was intended to be my personal code generator to relieve me of writing boring data-access code (calling a function and mapping the results, for example).

It was first published as the .NET Global Tool because that was, and still is - the most convenient and easiest way of managing different versions and updates, at least for me. I was really surprised to find out that, at the time of writing this blog, it had over 135K. That's, well, decent, but still not much. Note, while I was working on this blog series, it grew over 140K already.

However, I really didn't think anyone else would want to use it.

It was more of a fun experiment for me. It changed concepts a couple of times; it is loaded with features, and I thought it would be too complicated to be used by someone other than me. I guess I was wrong. I didn't even have time to properly finish the entire documentation, as you can see on the main readme file.

But I did create a nice presentation at one point. In any case, that won't stop me from blogging about it.

A few days ago, I did a migration of PgRoutiner to the new .NET8, and I wanted to try out how it works with the new NativeAOT Feature of the NET8. Native AOT is when we take our normal NET8 project, and we compile it to a native binary executable for the target OS.

AOT builds have very short, almost instantaneous startup times and are, in general, very optimized and fast.

It required some reconfiguration and some tweaking, and some parts had to be rewritten completely - but the final result blew me away: AOT build runs so fast that it is a completely different user experience. I can't go back to the normal .NET Tool after this.

If anyone wants to try it out, builds are on the GitHub release page.

So, what is it, and how it works?

See the PgRoutiner Concept next.

MORE ON PGROUTINER
To receive notifications about new posts and updates, consider subscribing to my LinkdIn page:
vb-software linkedin

You will receive notifications about new posts on your LinkedIn feed.
Comments
\ No newline at end of file +PgRoutiner Blog

PgRoutiner Blog

PgRoutiner is a set of command-line tools I created for fun and for my development needs while working on various .NET and PostgreSQL projects.

It integrates with .NET project configuration and allows you to do various stuff out of the box, no configuration needed. For example:

This is just one small example. PgRoutiner is incredibly feature-rich. As it happened, I was constantly adding new features as I was working on other projects. Initially, it was intended to be my personal code generator to relieve me of writing boring data-access code (calling a function and mapping the results, for example).

It was first published as the .NET Global Tool because that was, and still is - the most convenient and easiest way of managing different versions and updates, at least for me. I was really surprised to find out that, at the time of writing this blog, it had over 135K. That's, well, decent, but still not much. Note, while I was working on this blog series, it grew over 140K already.

However, I really didn't think anyone else would want to use it.

It was more of a fun experiment for me. It changed concepts a couple of times; it is loaded with features, and I thought it would be too complicated to be used by someone other than me. I guess I was wrong. I didn't even have time to properly finish the entire documentation, as you can see on the main readme file.

But I did create a nice presentation at one point. In any case, that won't stop me from blogging about it.

A few days ago, I did a migration of PgRoutiner to the new .NET8, and I wanted to try out how it works with the new NativeAOT Feature of the NET8. Native AOT is when we take our normal NET8 project, and we compile it to a native binary executable for the target OS.

AOT builds have very short, almost instantaneous startup times and are, in general, very optimized and fast.

It required some reconfiguration and some tweaking, and some parts had to be rewritten completely - but the final result blew me away: AOT build runs so fast that it is a completely different user experience. I can't go back to the normal .NET Tool after this.

If anyone wants to try it out, builds are on the GitHub release page.

So, what is it, and how it works?

See the PgRoutiner Concept next.

MORE ON PGROUTINER
To receive notifications about new posts and updates, consider subscribing to my LinkdIn page:
vb-software linkedin

You will receive notifications about new posts on your LinkedIn feed.
Comments
\ No newline at end of file diff --git a/blog/piko-orm/index.html b/blog/piko-orm/index.html index 7d03902c..ddf29e67 100644 --- a/blog/piko-orm/index.html +++ b/blog/piko-orm/index.html @@ -1,4 +1,4 @@ -Piko ORM

Piko ORM

Piko ORM is so, so tiny. It's Piko. The world's tiniest, smallest ORM for .NET.

Works best with PostgreSQL.

using System.Data;
+Piko ORM

Piko ORM

Piko ORM is so, so tiny. It's Piko. The world's tiniest, smallest ORM for .NET.

Works best with PostgreSQL.

using System.Data;
 using NpgsqlTypes;
 
 namespace DataAccess;
diff --git a/blog/postgresql-array/index.html b/blog/postgresql-array/index.html
index 70df43ec..b0eebe71 100644
--- a/blog/postgresql-array/index.html
+++ b/blog/postgresql-array/index.html
@@ -1,4 +1,4 @@
-PostgreSQL Arrays 🐘

PostgreSQL Arrays 🐘

Many-To-Many

Traditionally in relational databases, many-to-many data design is implemented using three tables.

Classic examples are users and roles: One user can be in many roles and one role can be on many users. For example, most developers are familiar with something like this (or, a variation of this approach):

create table users (
+PostgreSQL Arrays 🐘

PostgreSQL Arrays 🐘

Many-To-Many

Traditionally in relational databases, many-to-many data design is implemented using three tables.

Classic examples are users and roles: One user can be in many roles and one role can be on many users. For example, most developers are familiar with something like this (or, a variation of this approach):

create table users (
     user_id int not null primary key generated always as identity,
     name text not null unique
 );
diff --git a/blog/postgresql-paging/index.html b/blog/postgresql-paging/index.html
index 7eb69aa5..fa755ca9 100644
--- a/blog/postgresql-paging/index.html
+++ b/blog/postgresql-paging/index.html
@@ -1,4 +1,4 @@
-PostgreSQL Paging Benchmarks

PostgreSQL Paging Benchmarks

This is a performance benchmark project that tests different data paging approaches in PostgreSQL. You can find the source code in the PgPagingBenchmarks repository.

Setup

PostgreSQL 16 instance on my laptop:

select version();
+PostgreSQL Paging Benchmarks

PostgreSQL Paging Benchmarks

This is a performance benchmark project that tests different data paging approaches in PostgreSQL. You can find the source code in the PgPagingBenchmarks repository.

Setup

PostgreSQL 16 instance on my laptop:

select version();
 PostgreSQL 16.0 (Ubuntu 16.0-1.pgdg20.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0, 64-bit
select version();
 PostgreSQL 16.0 (Ubuntu 16.0-1.pgdg20.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0, 64-bit

Initial schema (source):

begin;
 
diff --git a/blog/postgresql-record-type/index.html b/blog/postgresql-record-type/index.html
index dd08c3b2..825c7c14 100644
--- a/blog/postgresql-record-type/index.html
+++ b/blog/postgresql-record-type/index.html
@@ -1,4 +1,4 @@
-Execute Custom Function For Each Record

Execute Custom Function For Each Record

  • Start with a query that returns a series of numbers: select q.i from generate_series(1, 10) q(i)

  • The goal is to execute a custom function for each record in this select (this is just an example; query could be anything).

  • That something will always return a previous value for the field i in the q(i) test table.

  • That is essentially a custom implementation of the LAG window function, but this serves as a proof of concept to demonstrate that we can do a custom function call for each value in any SELECT.

  • We will do this in a function that test_rec() that returns table (i, j), where i is a value from generate_series and j is the result from a custom function executed for each result that represents a previous (lag) value.

  • First, we need a wrap-up that generate-series in a subquery because generate_series returns a number, not a table record, and we need a table record:

select *
+Execute Custom Function For Each Record

Execute Custom Function For Each Record

  • Start with a query that returns a series of numbers: select q.i from generate_series(1, 10) q(i)

  • The goal is to execute a custom function for each record in this select (this is just an example; query could be anything).

  • That something will always return a previous value for the field i in the q(i) test table.

  • That is essentially a custom implementation of the LAG window function, but this serves as a proof of concept to demonstrate that we can do a custom function call for each value in any SELECT.

  • We will do this in a function that test_rec() that returns table (i, j), where i is a value from generate_series and j is the result from a custom function executed for each result that represents a previous (lag) value.

  • First, we need a wrap-up that generate-series in a subquery because generate_series returns a number, not a table record, and we need a table record:

select *
 from (
     select q.i
     from generate_series(1, 10) q(i)
diff --git a/blog/postgresql-temporal-tables/index.html b/blog/postgresql-temporal-tables/index.html
index d4d3fcae..bdbd4cd4 100644
--- a/blog/postgresql-temporal-tables/index.html
+++ b/blog/postgresql-temporal-tables/index.html
@@ -1,4 +1,4 @@
-Custom Temporal Tables in PostgreSQL

Custom Temporal Tables in PostgreSQL

The following script will add support for temporal tables in PostgreSQL.

Description

It will add two new functions in the public schema:

1) function temporal_table_trigger

Trigger function that inserts temporal data.

This function will create a new schema (source schema plus __history) and a new table with temporal data in it.

The new table will have the exact same schema without keys and constraints with one extra field - data_valid_to timestamptz not null default now();

2) function init_temporal_tables

This function initiates the entire temporal tables system by creating trigger temporal_table_trigger on each tables It accepts an array of schema names we want to have temporal tables.

To call this function for the public schema:

select init_temporal_tables(array['public']);
select init_temporal_tables(array['public']);

Script

create or replace function temporal_table_trigger()
+Custom Temporal Tables in PostgreSQL

Custom Temporal Tables in PostgreSQL

The following script will add support for temporal tables in PostgreSQL.

Description

It will add two new functions in the public schema:

1) function temporal_table_trigger

Trigger function that inserts temporal data.

This function will create a new schema (source schema plus __history) and a new table with temporal data in it.

The new table will have the exact same schema without keys and constraints with one extra field - data_valid_to timestamptz not null default now();

2) function init_temporal_tables

This function initiates the entire temporal tables system by creating trigger temporal_table_trigger on each tables It accepts an array of schema names we want to have temporal tables.

To call this function for the public schema:

select init_temporal_tables(array['public']);
select init_temporal_tables(array['public']);

Script

create or replace function temporal_table_trigger()
 returns trigger
 language plpgsql
 as
diff --git a/blog/recursion-postgresql/part1-different-type-of-recursion/index.html b/blog/recursion-postgresql/part1-different-type-of-recursion/index.html
index e1227fc6..4f54c752 100644
--- a/blog/recursion-postgresql/part1-different-type-of-recursion/index.html
+++ b/blog/recursion-postgresql/part1-different-type-of-recursion/index.html
@@ -1,4 +1,4 @@
-Recursion with PostgreSQL Part 1 - A Different Type of Recursion

Recursion with PostgreSQL Part 1 - A Different Type of Recursion

PostgreSQL offers a powerful procedural programming model out of the box (in addition to the standard SQL).

You can combine that with the standard SQL approach to overcome almost any issue and solve any programming task. Sometimes, the good old procedural approach may be a more straightforward way out of the complex data problems than standard SQL.

This article will try to demonstrate that approach to a complex problem example.

The Problem

Let's say we want to write a function that will return all related tables for a table name in a parameter.

We will start with a made-up schema:

create table division_status (
+Recursion with PostgreSQL Part 1 - A Different Type of Recursion

Recursion with PostgreSQL Part 1 - A Different Type of Recursion

PostgreSQL offers a powerful procedural programming model out of the box (in addition to the standard SQL).

You can combine that with the standard SQL approach to overcome almost any issue and solve any programming task. Sometimes, the good old procedural approach may be a more straightforward way out of the complex data problems than standard SQL.

This article will try to demonstrate that approach to a complex problem example.

The Problem

Let's say we want to write a function that will return all related tables for a table name in a parameter.

We will start with a made-up schema:

create table division_status (
     division_status_id int primary key, 
     name text
 );
diff --git a/blog/recursion-postgresql/part2-performances/index.html b/blog/recursion-postgresql/part2-performances/index.html
index f139bca5..34ff04da 100644
--- a/blog/recursion-postgresql/part2-performances/index.html
+++ b/blog/recursion-postgresql/part2-performances/index.html
@@ -1,4 +1,4 @@
-Recursion with PostgreSQL Part 2 - Performances

Recursion with PostgreSQL Part 2 - Performances

This is a follow-up article on my previous blog post A Different Type of SQL Recursion with PostgreSQL.

Previously, I explored two different approaches to recursion with PostgreSQL.

Now, it's time to do some testing.

Testing

Instead of a view on system tables that enables us to traverse table relationship tree, I've decided to create a simple test table:

create table big_tree_test (
+Recursion with PostgreSQL Part 2 - Performances

Recursion with PostgreSQL Part 2 - Performances

This is a follow-up article on my previous blog post A Different Type of SQL Recursion with PostgreSQL.

Previously, I explored two different approaches to recursion with PostgreSQL.

Now, it's time to do some testing.

Testing

Instead of a view on system tables that enables us to traverse table relationship tree, I've decided to create a simple test table:

create table big_tree_test (
       id text not null,
       parent_id text not null
   );
create table big_tree_test (
diff --git a/blog/recursion-postgresql/part3-cycle-detection/index.html b/blog/recursion-postgresql/part3-cycle-detection/index.html
index 802bfb42..f4bb7e56 100644
--- a/blog/recursion-postgresql/part3-cycle-detection/index.html
+++ b/blog/recursion-postgresql/part3-cycle-detection/index.html
@@ -1,4 +1,4 @@
-Recursion with PostgreSQL Part 3 - Cycle Detection

Recursion with PostgreSQL Part 3 - Cycle Detection

Yesterday, I wrote another article for my Recursion with PostgreSQL series: Recursion with PostgreSQL Follow-Up 1 - Performances .

My conclusion was that the CTE recursion method was severely lacking a way out of the infinite loops - and then I proceeded to write a version that defined a maximum recursion depth as a parameter:

create or replace function select_nodes_recursive_cte(
+Recursion with PostgreSQL Part 3 - Cycle Detection

Recursion with PostgreSQL Part 3 - Cycle Detection

Yesterday, I wrote another article for my Recursion with PostgreSQL series: Recursion with PostgreSQL Follow-Up 1 - Performances .

My conclusion was that the CTE recursion method was severely lacking a way out of the infinite loops - and then I proceeded to write a version that defined a maximum recursion depth as a parameter:

create or replace function select_nodes_recursive_cte(
     _id text,
     _max_recursion int = 100
 )
diff --git a/blog/recursion-postgresql/part4-right-path/index.html b/blog/recursion-postgresql/part4-right-path/index.html
index 3e70346a..bd37c87f 100644
--- a/blog/recursion-postgresql/part4-right-path/index.html
+++ b/blog/recursion-postgresql/part4-right-path/index.html
@@ -1,4 +1,4 @@
-Recursion with PostgreSQL Part 4 - Finding the Right Path

Recursion with PostgreSQL Part 4 - Finding the Right Path

The mystery has finally been resolved, and I have learned something today.

In my previous article, I managed to get some really crazy performances in tree processing by using PostgreSQL recursive procedural-style function.

While recursive CTE was getting some severe performance degradation - even on a smaller scale: It usually would eat all of my available space.

Thanks to @fatalmind (Markus Winand) comment, I got better clarification on what path and cycle really mean.

Example

So we have this test table:

create table big_tree_test (id text, parent_id text);
create table big_tree_test (id text, parent_id text);
   id    | parent_id | 
+Recursion with PostgreSQL Part 4 - Finding the Right Path

Recursion with PostgreSQL Part 4 - Finding the Right Path

The mystery has finally been resolved, and I have learned something today.

In my previous article, I managed to get some really crazy performances in tree processing by using PostgreSQL recursive procedural-style function.

While recursive CTE was getting some severe performance degradation - even on a smaller scale: It usually would eat all of my available space.

Thanks to @fatalmind (Markus Winand) comment, I got better clarification on what path and cycle really mean.

Example

So we have this test table:

create table big_tree_test (id text, parent_id text);
create table big_tree_test (id text, parent_id text);
   id    | parent_id | 
 ---------+-----------+
  node_1  | node_3    |
  node_1  | node_8    |
diff --git a/blog/sql-vs-ddd/index.html b/blog/sql-vs-ddd/index.html
index 1f28bcd2..d70d3d77 100644
--- a/blog/sql-vs-ddd/index.html
+++ b/blog/sql-vs-ddd/index.html
@@ -1,4 +1,4 @@
-How DDD is screwing up your SQL

How DDD is screwing up your SQL

This morning, I came across an interesting article about DDD and SQL on the internet named How SQL is screwing up your DDD. Normally I would post this article on my LinkedIn page with my own thoughts, but the subject matter is way too interesting, so, I'll just make my own blogpost.

The main premise of the article is an exercise, a code kata, in data modeling. Quote:

The goal is to model a collection of value object items, where the collection maintains a “default” item. It forces you to consider things like

How do you handle selecting which item is the default? How do you avoid the possibility of the collection ending up with no default item? How do you handle the case where the default item is removed from the collection? How do you avoid the possibility of the collection having no items at all?

A hypothetical example given is the Customer entity, which possesses a collection of Address.

It appears that the ideal domain model in a domain-driven world for this problem would be something like this:

public class Address
+How DDD is screwing up your SQL

How DDD is screwing up your SQL

This morning, I came across an interesting article about DDD and SQL on the internet named How SQL is screwing up your DDD. Normally I would post this article on my LinkedIn page with my own thoughts, but the subject matter is way too interesting, so, I'll just make my own blogpost.

The main premise of the article is an exercise, a code kata, in data modeling. Quote:

The goal is to model a collection of value object items, where the collection maintains a “default” item. It forces you to consider things like

How do you handle selecting which item is the default? How do you avoid the possibility of the collection ending up with no default item? How do you handle the case where the default item is removed from the collection? How do you avoid the possibility of the collection having no items at all?

A hypothetical example given is the Customer entity, which possesses a collection of Address.

It appears that the ideal domain model in a domain-driven world for this problem would be something like this:

public class Address
 {
   public int Id { get; private set; }
   public string Street { get; private set; }
diff --git a/blog/transaction-script/index.html b/blog/transaction-script/index.html
index c1cdd040..d4521784 100644
--- a/blog/transaction-script/index.html
+++ b/blog/transaction-script/index.html
@@ -1,4 +1,4 @@
-Transaction Script DDD vs SQL

Which is the Better Approach?

And why?

  • Readability?
  • Maintainability?
  • Testability?
  • Debugging?
  • Performances?

Transaction Script in Java

(source)

import java.sql.Connection;
+Transaction Script DDD vs SQL

Which is the Better Approach?

And why?

  • Readability?
  • Maintainability?
  • Testability?
  • Debugging?
  • Performances?

Transaction Script in Java

(source)

import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
diff --git a/blog/what-have-stored-procedures-ever-done/index.html b/blog/what-have-stored-procedures-ever-done/index.html
index ce459b15..84ffb3e5 100644
--- a/blog/what-have-stored-procedures-ever-done/index.html
+++ b/blog/what-have-stored-procedures-ever-done/index.html
@@ -1 +1 @@
-What have the STORED PROCEDURES ever done for us?

What have the STORED PROCEDURES ever done for us?

So, in all seriousness - what have the STORED PROCEDURES ever done for us?

Security?

You can very easily set up any database that has support for SP in a way that:

  • Your application is only aware of that one database account that can only execute the SP required by your application and nothing more.

  • That application account can't access data at all directly.

  • That application account is created and managed by another database account with a higher level of privileges and that is stored and protected much more securely.

That system is usually called the least-privilege principle and it can help you to:

  • Protect your data from theft way more securely because the account exposed to the application doesn't have direct access to data.

  • Guard your system against SQL injection attacks. The SQL injection is an impossibility (unless you decide to use dynamic SQL).

  • Prevents well-meaning junior developers from writing horribly inefficient queries. Well, that's not security per se, but it is a very useful side-effect.

Militaries around the world use this principle also called - "need-to-know-basis".

And the military takes security very, very seriously.

Do you?

Performances?

Well, this one is easy, everyone knows that at least - STORED PROCEDURES will give you performance gain.

Database code needs to be closer to the actual data and usually, there is much less network utilization between database and application.

Besides that, STORED PROCEDURE can be heavily optimized by the database engine and execution plans cached and ready.

Maintainability?

Imagine this scenario:

Users are seeing data on their screens that shouldn't be there. So, it's a bug, it needs a bit of maintenance obviously.

What do you do?

You can, of course, just create a Jira ticket ... or, or you can do something like this:

Connect to the database server with the query tool Execute the STORED PROCEDURE that serves that screen and examine the data. If data contains the bug, then you know that the problem is within the STORED PROCEDURE, if it doesn't then the bug is somewhere within the application layer. Now, within seconds you narrowed a search for a bug to at least half of the system.

If it is in your database layer, you can fix it immediately with one ALTER PROCEDURE (or REPLACE FUNCTION) call ... and it's fixed within minutes or even less - with zero downtime.

If it is not, then at least you know that it doesn't have anything to do with the database layer, and you can focus your investigation on your classes, designed domain models with patterns, abstract factories, reducers API controllers, injected services and whatnot you name it. Good luck with that, it will take some time for sure, and the application needs to be patched, redeployed, and all that jazz.

Does your user care about that?

Or, do they usually want to see bugs fixed right here and right now?

But that is not the only factor in this story that affects maintainability.

Your database is a system of course, and if you surround your database with STORED PROCEDURES, which is essentially an API layer - you got yourself a black box.

A black box is a system with known inputs and known outputs - without any knowledge of inner workings.

Your database may serve dozens and dozens of applications, services, micro-services, reporting systems, integrations, etc, etc, and, by having a black box concept you can change the schema and inner workings while respecting known outputs for know inputs with supreme confidence and efficiency.

How's that for maintainability?

Availability?

You want to have a system with maximum availability, don't you? I mean, downtimes are bad for business. Very bad.

I may have already mentioned above that you can patch a bug in STORED PROCEDURE without having to stop anything. Hence, availability.

No downtime.

Simply run "ALTER PROCEDURE" or "REPLACE FUNCTION" and there you go.

But it gets better. Imagine this. You have a huge table with a gazillion records. And for some reason, you have to change the data type of one field in that table. What do you do? Well, of course, you rush to create a migration that alters the table and alters the field type and then you deploy your update and ... nothing happens. For hours. The table is locked, and the entire system is unresponsive because everybody has to wait for your alter to finish and that may take hours. Many, many expensive hours of downtime.

But not if you use STORED PROCEDURES!

You could also write a script that will do this.

Create an auxiliary table from your main table without relations Alter procedures to insert data in that auxiliary table Alter the main table to change the data type in your field, and wait to finish After it finishes, insert data from the auxiliary table and revert procedure to original version No downtime.

Availability.

Apart from security, performance, maintainability, and availability, what STORED PROCEDURES have ever really done for us?

I really don't know.

To receive notifications about new posts and updates, consider subscribing to my LinkdIn page:
vb-software linkedin

You will receive notifications about new posts on your LinkedIn feed.
Comments
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +What have the STORED PROCEDURES ever done for us?

What have the STORED PROCEDURES ever done for us?

So, in all seriousness - what have the STORED PROCEDURES ever done for us?

Security?

You can very easily set up any database that has support for SP in a way that:

  • Your application is only aware of that one database account that can only execute the SP required by your application and nothing more.

  • That application account can't access data at all directly.

  • That application account is created and managed by another database account with a higher level of privileges and that is stored and protected much more securely.

That system is usually called the least-privilege principle and it can help you to:

  • Protect your data from theft way more securely because the account exposed to the application doesn't have direct access to data.

  • Guard your system against SQL injection attacks. The SQL injection is an impossibility (unless you decide to use dynamic SQL).

  • Prevents well-meaning junior developers from writing horribly inefficient queries. Well, that's not security per se, but it is a very useful side-effect.

Militaries around the world use this principle also called - "need-to-know-basis".

And the military takes security very, very seriously.

Do you?

Performances?

Well, this one is easy, everyone knows that at least - STORED PROCEDURES will give you performance gain.

Database code needs to be closer to the actual data and usually, there is much less network utilization between database and application.

Besides that, STORED PROCEDURE can be heavily optimized by the database engine and execution plans cached and ready.

Maintainability?

Imagine this scenario:

Users are seeing data on their screens that shouldn't be there. So, it's a bug, it needs a bit of maintenance obviously.

What do you do?

You can, of course, just create a Jira ticket ... or, or you can do something like this:

Connect to the database server with the query tool Execute the STORED PROCEDURE that serves that screen and examine the data. If data contains the bug, then you know that the problem is within the STORED PROCEDURE, if it doesn't then the bug is somewhere within the application layer. Now, within seconds you narrowed a search for a bug to at least half of the system.

If it is in your database layer, you can fix it immediately with one ALTER PROCEDURE (or REPLACE FUNCTION) call ... and it's fixed within minutes or even less - with zero downtime.

If it is not, then at least you know that it doesn't have anything to do with the database layer, and you can focus your investigation on your classes, designed domain models with patterns, abstract factories, reducers API controllers, injected services and whatnot you name it. Good luck with that, it will take some time for sure, and the application needs to be patched, redeployed, and all that jazz.

Does your user care about that?

Or, do they usually want to see bugs fixed right here and right now?

But that is not the only factor in this story that affects maintainability.

Your database is a system of course, and if you surround your database with STORED PROCEDURES, which is essentially an API layer - you got yourself a black box.

A black box is a system with known inputs and known outputs - without any knowledge of inner workings.

Your database may serve dozens and dozens of applications, services, micro-services, reporting systems, integrations, etc, etc, and, by having a black box concept you can change the schema and inner workings while respecting known outputs for know inputs with supreme confidence and efficiency.

How's that for maintainability?

Availability?

You want to have a system with maximum availability, don't you? I mean, downtimes are bad for business. Very bad.

I may have already mentioned above that you can patch a bug in STORED PROCEDURE without having to stop anything. Hence, availability.

No downtime.

Simply run "ALTER PROCEDURE" or "REPLACE FUNCTION" and there you go.

But it gets better. Imagine this. You have a huge table with a gazillion records. And for some reason, you have to change the data type of one field in that table. What do you do? Well, of course, you rush to create a migration that alters the table and alters the field type and then you deploy your update and ... nothing happens. For hours. The table is locked, and the entire system is unresponsive because everybody has to wait for your alter to finish and that may take hours. Many, many expensive hours of downtime.

But not if you use STORED PROCEDURES!

You could also write a script that will do this.

Create an auxiliary table from your main table without relations Alter procedures to insert data in that auxiliary table Alter the main table to change the data type in your field, and wait to finish After it finishes, insert data from the auxiliary table and revert procedure to original version No downtime.

Availability.

Apart from security, performance, maintainability, and availability, what STORED PROCEDURES have ever really done for us?

I really don't know.

To receive notifications about new posts and updates, consider subscribing to my LinkdIn page:
vb-software linkedin

You will receive notifications about new posts on your LinkedIn feed.
Comments
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blog/where-to/index.html b/blog/where-to/index.html index 12a92d35..1c1e6fc7 100644 --- a/blog/where-to/index.html +++ b/blog/where-to/index.html @@ -1,4 +1,4 @@ -Which Way .NET Developer?

Which Way .NET Developer?

You must create an endpoint that will return games, joined by genre by id, from the database.

Option 1

public abstract class BaseModel
+Which Way .NET Developer?

Which Way .NET Developer?

You must create an endpoint that will return games, joined by genre by id, from the database.

Option 1

public abstract class BaseModel
 {
     public Guid Id { get; set; }
 }
diff --git a/blogs/aot/index.html b/blogs/aot/index.html
index 7dd79625..26065d14 100644
--- a/blogs/aot/index.html
+++ b/blogs/aot/index.html
@@ -1 +1 @@
-aot blogs
\ No newline at end of file +aot blogs
\ No newline at end of file diff --git a/blogs/benchmarks/index.html b/blogs/benchmarks/index.html index 5444495a..5b49cda5 100644 --- a/blogs/benchmarks/index.html +++ b/blogs/benchmarks/index.html @@ -1 +1 @@ -benchmarks blogs
\ No newline at end of file +benchmarks blogs
\ No newline at end of file diff --git a/blogs/c#/index.html b/blogs/c#/index.html index fc0b1156..630b8f57 100644 --- a/blogs/c#/index.html +++ b/blogs/c#/index.html @@ -1 +1 @@ -c# blogs
\ No newline at end of file +c# blogs
\ No newline at end of file diff --git a/blogs/csharp/index.html b/blogs/csharp/index.html index d61233ba..84f63fed 100644 --- a/blogs/csharp/index.html +++ b/blogs/csharp/index.html @@ -1 +1 @@ -csharp blogs
\ No newline at end of file +csharp blogs
\ No newline at end of file diff --git a/blogs/database/index.html b/blogs/database/index.html index f769067e..d974bde0 100644 --- a/blogs/database/index.html +++ b/blogs/database/index.html @@ -1 +1 @@ -database blogs
\ No newline at end of file +database blogs
\ No newline at end of file diff --git a/blogs/ddd/index.html b/blogs/ddd/index.html index 49a576f1..24d552d2 100644 --- a/blogs/ddd/index.html +++ b/blogs/ddd/index.html @@ -1 +1 @@ -ddd blogs
\ No newline at end of file +ddd blogs
\ No newline at end of file diff --git a/blogs/dotnet/index.html b/blogs/dotnet/index.html index 8009d918..1be362c3 100644 --- a/blogs/dotnet/index.html +++ b/blogs/dotnet/index.html @@ -1 +1 @@ -dotnet blogs

api, api-rest, restful-api, http, postgres, dotnet, net8, c#, aot, database, rest, server, postgresql, npgsqlrest, pgsql, pg, automatic, .net, .net core, orm, software, development, software-development, tool

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +dotnet blogs

api, api-rest, restful-api, http, postgres, dotnet, net8, c#, aot, database, rest, server, postgresql, npgsqlrest, pgsql, pg, automatic, .net, .net core, orm, software, development, software-development, tool

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blogs/general/index.html b/blogs/general/index.html index 33bd4455..4e5c97c8 100644 --- a/blogs/general/index.html +++ b/blogs/general/index.html @@ -1 +1 @@ -general blogs

ddd, sql, software-development, software-architecture, architecture, software, development, postgresql, programming, arrays, model, modeling, data, data model, relational model, domain, domain model, benchmarks, c#, dotnet, .net, .net core, orm, database

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +general blogs

ddd, sql, software-development, software-architecture, architecture, software, development, postgresql, programming, arrays, model, modeling, data, data model, relational model, domain, domain model, benchmarks, c#, dotnet, .net, .net core, orm, database

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blogs/index.html b/blogs/index.html index 45b7f2f2..03074f81 100644 --- a/blogs/index.html +++ b/blogs/index.html @@ -1 +1 @@ -blogs

ddd, sql, software-development, software-architecture, architecture, software, development, api, api-rest, restful-api, http, postgres, dotnet, net8, c#, aot, database, rest, server, postgresql, npgsqlrest, pgsql, pg, automatic, programming, arrays, model, modeling, data, data model, relational model, domain, domain model, benchmarks, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte, .net, .net core, orm, tool, stored procedure, procedure

May 10, 2024
Transaction Script DDD vs SQL
Transaction Script DDD vs SQL
Read more...
May 4, 2024
Common Sense Software Design
Common Sense Software Design Approach for RDBMS-backed Type of Software
Read more...
May 4, 2024
NpgsqlRest v2 Update 🐘🔥
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
NpgsqlRest Update 1.6.2
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
PostgreSQL Arrays 🐘
PostgreSQL Array Example
Read more...
Mar 20, 2024
How DDD is screwing up your SQL
How DDD is screwing up your SQL
Read more...
Feb 16, 2024
PostgreSQL Paging Benchmarks
PostgreSQL Paging Benchmarks
Read more...
Jan 23, 2024
NpgsqlRest NuGet Library
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
Nov 6, 2023
Execute Custom Function For Each Record
PostgreSQL crazy experiment with the record type.
Read more...
Oct 10, 2023
Custom Temporal Tables in PostgreSQL
PostgreSQL script that implements temporal tables without extension.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 1 - A Different Type of Recursion
Exploring a different approach to recursion with PostgreSQL by using recursive plpgsql function instead of recursive CTE query.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 2 - Performances
Follow-Up 1 on PostgreSQL recursive function. Some performance optimizations.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 4 - Finding the Right Path
The last part of the PostgreSQL recursive function series resolves a mystery and tree paths calculation — final performance benchmarks.
Read more...
Sep 16, 2023
Which Way .NET Developer?
You take the blue pill - the story ends, ... etc, select option 1 or option 2. Which one is better?
Read more...
May 19, 2023
What is Micro ORM?
What are the Micro ORM libraries, why do they even exist, what are their purpose, what are they used for, and what are the alternatives?
Read more...
Feb 12, 2024
PgRoutiner Documentation
PgRoutiner Documentation
Read more...
Feb 12, 2024
PgRoutiner Code-Gen
PgRoutiner Database Management
Read more...
Feb 11, 2024
PgRoutiner Blog
Database-First Tool for Development With .NET And PostgreSQL Native Build
Read more...
Feb 11, 2024
PgRoutiner Concept
PgRoutiner High Level Concept
Read more...
Feb 11, 2024
PgRoutiner Database Management
PgRoutiner Database Management
Read more...
Feb 8, 2024
Piko ORM
The world's tiniest, smallest ORM for .NET
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 3 - Cycle Detection
Follow-Up 2 on PostgreSQL recursive function. Learning the cycle detection in recursive queries.
Read more...
May 19, 2023
Haters Build Software
Some opinions on software architecture and design. What are the "ilities" what are quality attributes and why are they important for software architecture and design?
Read more...
Feb 7, 2020
What have the STORED PROCEDURES ever done for us?
Apart from security, performance, maintainability, and availability, what STORED PROCEDURES have ever really done for us?
Read more...
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +blogs

ddd, sql, software-development, software-architecture, architecture, software, development, api, api-rest, restful-api, http, postgres, dotnet, net8, c#, aot, database, rest, server, postgresql, npgsqlrest, pgsql, pg, automatic, programming, arrays, model, modeling, data, data model, relational model, domain, domain model, benchmarks, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte, .net, .net core, orm, tool, stored procedure, procedure

May 10, 2024
Transaction Script DDD vs SQL
Transaction Script DDD vs SQL
Read more...
May 4, 2024
Common Sense Software Design
Common Sense Software Design Approach for RDBMS-backed Type of Software
Read more...
May 4, 2024
NpgsqlRest v2 Update 🐘🔥
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
NpgsqlRest Update 1.6.2
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
PostgreSQL Arrays 🐘
PostgreSQL Array Example
Read more...
Mar 20, 2024
How DDD is screwing up your SQL
How DDD is screwing up your SQL
Read more...
Feb 16, 2024
PostgreSQL Paging Benchmarks
PostgreSQL Paging Benchmarks
Read more...
Jan 23, 2024
NpgsqlRest NuGet Library
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
Nov 6, 2023
Execute Custom Function For Each Record
PostgreSQL crazy experiment with the record type.
Read more...
Oct 10, 2023
Custom Temporal Tables in PostgreSQL
PostgreSQL script that implements temporal tables without extension.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 1 - A Different Type of Recursion
Exploring a different approach to recursion with PostgreSQL by using recursive plpgsql function instead of recursive CTE query.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 2 - Performances
Follow-Up 1 on PostgreSQL recursive function. Some performance optimizations.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 4 - Finding the Right Path
The last part of the PostgreSQL recursive function series resolves a mystery and tree paths calculation — final performance benchmarks.
Read more...
Sep 16, 2023
Which Way .NET Developer?
You take the blue pill - the story ends, ... etc, select option 1 or option 2. Which one is better?
Read more...
May 19, 2023
What is Micro ORM?
What are the Micro ORM libraries, why do they even exist, what are their purpose, what are they used for, and what are the alternatives?
Read more...
Feb 12, 2024
PgRoutiner Documentation
PgRoutiner Documentation
Read more...
Feb 12, 2024
PgRoutiner Code-Gen
PgRoutiner Database Management
Read more...
Feb 11, 2024
PgRoutiner Blog
Database-First Tool for Development With .NET And PostgreSQL Native Build
Read more...
Feb 11, 2024
PgRoutiner Concept
PgRoutiner High Level Concept
Read more...
Feb 11, 2024
PgRoutiner Database Management
PgRoutiner Database Management
Read more...
Feb 8, 2024
Piko ORM
The world's tiniest, smallest ORM for .NET
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 3 - Cycle Detection
Follow-Up 2 on PostgreSQL recursive function. Learning the cycle detection in recursive queries.
Read more...
May 19, 2023
Haters Build Software
Some opinions on software architecture and design. What are the "ilities" what are quality attributes and why are they important for software architecture and design?
Read more...
Feb 7, 2020
What have the STORED PROCEDURES ever done for us?
Apart from security, performance, maintainability, and availability, what STORED PROCEDURES have ever really done for us?
Read more...
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blogs/net8/index.html b/blogs/net8/index.html index 36a5744a..fa5de6a6 100644 --- a/blogs/net8/index.html +++ b/blogs/net8/index.html @@ -1 +1 @@ -net8 blogs
\ No newline at end of file +net8 blogs
\ No newline at end of file diff --git a/blogs/npgsqlrest/index.html b/blogs/npgsqlrest/index.html index 26707039..95824317 100644 --- a/blogs/npgsqlrest/index.html +++ b/blogs/npgsqlrest/index.html @@ -1 +1 @@ -npgsqlrest blogs
\ No newline at end of file +npgsqlrest blogs
\ No newline at end of file diff --git a/blogs/orm/index.html b/blogs/orm/index.html index 6e7a03f0..39c0dbd9 100644 --- a/blogs/orm/index.html +++ b/blogs/orm/index.html @@ -1 +1 @@ -orm blogs
\ No newline at end of file +orm blogs
\ No newline at end of file diff --git a/blogs/pgroutiner/index.html b/blogs/pgroutiner/index.html index 78b4d7db..d6042508 100644 --- a/blogs/pgroutiner/index.html +++ b/blogs/pgroutiner/index.html @@ -1 +1 @@ -pgroutiner blogs
\ No newline at end of file +pgroutiner blogs
\ No newline at end of file diff --git a/blogs/plpgsql/index.html b/blogs/plpgsql/index.html index eba4bb27..7e45884c 100644 --- a/blogs/plpgsql/index.html +++ b/blogs/plpgsql/index.html @@ -1 +1 @@ -plpgsql blogs

postgresql, sql, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +plpgsql blogs

postgresql, sql, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blogs/postgres/index.html b/blogs/postgres/index.html index 7d1f5c14..94ff7095 100644 --- a/blogs/postgres/index.html +++ b/blogs/postgres/index.html @@ -1 +1 @@ -postgres blogs
\ No newline at end of file +postgres blogs
\ No newline at end of file diff --git a/blogs/postgresql/index.html b/blogs/postgresql/index.html index f2d24893..5bd049c7 100644 --- a/blogs/postgresql/index.html +++ b/blogs/postgresql/index.html @@ -1 +1 @@ -postgresql blogs

api, api-rest, restful-api, http, postgres, dotnet, net8, c#, aot, database, rest, server, postgresql, npgsqlrest, pgsql, pg, automatic, programming, arrays, sql, benchmarks, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte, tool

May 4, 2024
NpgsqlRest v2 Update 🐘🔥
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
NpgsqlRest Update 1.6.2
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
PostgreSQL Arrays 🐘
PostgreSQL Array Example
Read more...
Feb 16, 2024
PostgreSQL Paging Benchmarks
PostgreSQL Paging Benchmarks
Read more...
Jan 23, 2024
NpgsqlRest NuGet Library
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
Nov 6, 2023
Execute Custom Function For Each Record
PostgreSQL crazy experiment with the record type.
Read more...
Oct 10, 2023
Custom Temporal Tables in PostgreSQL
PostgreSQL script that implements temporal tables without extension.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 1 - A Different Type of Recursion
Exploring a different approach to recursion with PostgreSQL by using recursive plpgsql function instead of recursive CTE query.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 2 - Performances
Follow-Up 1 on PostgreSQL recursive function. Some performance optimizations.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 4 - Finding the Right Path
The last part of the PostgreSQL recursive function series resolves a mystery and tree paths calculation — final performance benchmarks.
Read more...
Feb 12, 2024
PgRoutiner Documentation
PgRoutiner Documentation
Read more...
Feb 12, 2024
PgRoutiner Code-Gen
PgRoutiner Database Management
Read more...
Feb 11, 2024
PgRoutiner Blog
Database-First Tool for Development With .NET And PostgreSQL Native Build
Read more...
Feb 11, 2024
PgRoutiner Concept
PgRoutiner High Level Concept
Read more...
Feb 11, 2024
PgRoutiner Database Management
PgRoutiner Database Management
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 3 - Cycle Detection
Follow-Up 2 on PostgreSQL recursive function. Learning the cycle detection in recursive queries.
Read more...
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +postgresql blogs

api, api-rest, restful-api, http, postgres, dotnet, net8, c#, aot, database, rest, server, postgresql, npgsqlrest, pgsql, pg, automatic, programming, arrays, sql, benchmarks, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte, tool

May 4, 2024
NpgsqlRest v2 Update 🐘🔥
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
NpgsqlRest Update 1.6.2
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
May 4, 2024
PostgreSQL Arrays 🐘
PostgreSQL Array Example
Read more...
Feb 16, 2024
PostgreSQL Paging Benchmarks
PostgreSQL Paging Benchmarks
Read more...
Jan 23, 2024
NpgsqlRest NuGet Library
Automatic REST API for PostgreSQL Database as .NET8 Middleware
Read more...
Nov 6, 2023
Execute Custom Function For Each Record
PostgreSQL crazy experiment with the record type.
Read more...
Oct 10, 2023
Custom Temporal Tables in PostgreSQL
PostgreSQL script that implements temporal tables without extension.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 1 - A Different Type of Recursion
Exploring a different approach to recursion with PostgreSQL by using recursive plpgsql function instead of recursive CTE query.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 2 - Performances
Follow-Up 1 on PostgreSQL recursive function. Some performance optimizations.
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 4 - Finding the Right Path
The last part of the PostgreSQL recursive function series resolves a mystery and tree paths calculation — final performance benchmarks.
Read more...
Feb 12, 2024
PgRoutiner Documentation
PgRoutiner Documentation
Read more...
Feb 12, 2024
PgRoutiner Code-Gen
PgRoutiner Database Management
Read more...
Feb 11, 2024
PgRoutiner Blog
Database-First Tool for Development With .NET And PostgreSQL Native Build
Read more...
Feb 11, 2024
PgRoutiner Concept
PgRoutiner High Level Concept
Read more...
Feb 11, 2024
PgRoutiner Database Management
PgRoutiner Database Management
Read more...
Sep 18, 2023
Recursion with PostgreSQL Part 3 - Cycle Detection
Follow-Up 2 on PostgreSQL recursive function. Learning the cycle detection in recursive queries.
Read more...
If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blogs/rest/index.html b/blogs/rest/index.html index 8dbc0f3b..5cda8b2b 100644 --- a/blogs/rest/index.html +++ b/blogs/rest/index.html @@ -1 +1 @@ -rest blogs
\ No newline at end of file +rest blogs
\ No newline at end of file diff --git a/blogs/software-architecture/index.html b/blogs/software-architecture/index.html index 55fe0431..e12fb283 100644 --- a/blogs/software-architecture/index.html +++ b/blogs/software-architecture/index.html @@ -1 +1 @@ -software-architecture blogs
\ No newline at end of file +software-architecture blogs
\ No newline at end of file diff --git a/blogs/software-design/index.html b/blogs/software-design/index.html index 8608c716..ba516934 100644 --- a/blogs/software-design/index.html +++ b/blogs/software-design/index.html @@ -1 +1 @@ -software-design blogs
\ No newline at end of file +software-design blogs
\ No newline at end of file diff --git a/blogs/software-development/index.html b/blogs/software-development/index.html index 31393ab2..e24d36cc 100644 --- a/blogs/software-development/index.html +++ b/blogs/software-development/index.html @@ -1 +1 @@ -software-development blogs

ddd, sql, software-development, software-architecture, architecture, software, development, postgresql, programming, arrays, model, modeling, data, data model, relational model, domain, domain model, benchmarks, c#, dotnet, .net, .net core, orm, database

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +software-development blogs

ddd, sql, software-development, software-architecture, architecture, software, development, postgresql, programming, arrays, model, modeling, data, data model, relational model, domain, domain model, benchmarks, c#, dotnet, .net, .net core, orm, database

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blogs/sql/index.html b/blogs/sql/index.html index 215c05d8..70ec4f3b 100644 --- a/blogs/sql/index.html +++ b/blogs/sql/index.html @@ -1 +1 @@ -sql blogs

postgresql, programming, arrays, ddd, sql, model, modeling, data, data model, relational model, domain, domain model, benchmarks, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte, database, stored procedure, procedure

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file +sql blogs

postgresql, programming, arrays, ddd, sql, model, modeling, data, data model, relational model, domain, domain model, benchmarks, plpgsql, function, functions, record, temporal, history, table, tables, recursion, tree, cte, database, stored procedure, procedure

If you like my content, use my software, or otherwise benefit from my work, consider supporting me by buying me a coffee. The software runs on coffee after all.
Buy me a Coffee Scan Here To Buy Me a Cofee
\ No newline at end of file diff --git a/blogs/stored-procedure/index.html b/blogs/stored-procedure/index.html index 56d36e6e..82d2e56f 100644 --- a/blogs/stored-procedure/index.html +++ b/blogs/stored-procedure/index.html @@ -1 +1 @@ -stored-procedure blogs
\ No newline at end of file +stored-procedure blogs
\ No newline at end of file diff --git a/blogs/tool/index.html b/blogs/tool/index.html index adf07d98..c92106c6 100644 --- a/blogs/tool/index.html +++ b/blogs/tool/index.html @@ -1 +1 @@ -tool blogs
\ No newline at end of file +tool blogs
\ No newline at end of file diff --git a/index.html b/index.html index 1f3118be..01edc303 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -VB-Consulting

no-nonsense software development and consulting

Get the most out of the world's most advanced open-source full-stack eco-systems


featured

open-source tools

blogs
See All Blogs
\ No newline at end of file +VB-Consulting

no-nonsense software development and consulting

Get the most out of the world's most advanced open-source full-stack eco-systems


featured

open-source tools

blogs
See All Blogs
\ No newline at end of file diff --git a/norm.net/benchmarks/index.html b/norm.net/benchmarks/index.html index 08c52ac2..a62ff7d2 100644 --- a/norm.net/benchmarks/index.html +++ b/norm.net/benchmarks/index.html @@ -1,4 +1,4 @@ -Norm.NET Perfomance Benchmarks

Perfomance Benchmarks

Configuration

        
+Norm.NET Perfomance Benchmarks

Perfomance Benchmarks

Configuration

        
 Norm 5.4.0.0
 Dapper 2.0.0.0
 EntityFrameworkCore 8.0.0.0
diff --git a/norm.net/changelog/index.html b/norm.net/changelog/index.html
index cfb05425..8719c05c 100644
--- a/norm.net/changelog/index.html
+++ b/norm.net/changelog/index.html
@@ -1,4 +1,4 @@
-Norm.net Changelog

Changelog

Edit this page on GitHub

Note: changelogs prior to version 5.3.0 can be found in archive markup: changelog-archive.md

5.4.0 (2023-11-27)

Full Changelog

New feature: GetRecordsAffected method

Signature:

  • Extension: public static int? GetRecordsAffected(this DbConnection connection)
  • Instance: public int? GetRecordsAffected()

Returns a number of records affected by the last query.

This is the value that ExecuteNonQuery() method returns if one of the Execute versions is executed.

Example:

var rowsAffected = connection
+Norm.net Changelog

Changelog

Edit this page on GitHub

Note: changelogs prior to version 5.3.0 can be found in archive markup: changelog-archive.md

5.4.0 (2023-11-27)

Full Changelog

New feature: GetRecordsAffected method

Signature:

  • Extension: public static int? GetRecordsAffected(this DbConnection connection)
  • Instance: public int? GetRecordsAffected()

Returns a number of records affected by the last query.

This is the value that ExecuteNonQuery() method returns if one of the Execute versions is executed.

Example:

var rowsAffected = connection
     .Execute("insert into rows_affected_test values ('foo')")
     .GetRecordsAffected();
var rowsAffected = connection
     .Execute("insert into rows_affected_test values ('foo')")
diff --git a/norm.net/docs/getting-started/basic-concepts/index.html b/norm.net/docs/getting-started/basic-concepts/index.html
index 0e6d376e..d0bc56de 100644
--- a/norm.net/docs/getting-started/basic-concepts/index.html
+++ b/norm.net/docs/getting-started/basic-concepts/index.html
@@ -1,4 +1,4 @@
-Basic Concepts

Basic Concepts

Edit this page on GitHub

Extensions And Fluid Syntax

  • Norm is implemented as a set of extensions over the System.Data.Common.DbConnection object.

  • Some extensions may return the new Norm object instance.

  • Norm object instances have methods with the same signature as the System.Data.Common.DbConnection extensions.

  • This allows the use of the fluid syntax over the connection object. Example:

//
+Basic Concepts

Basic Concepts

Edit this page on GitHub

Extensions And Fluid Syntax

  • Norm is implemented as a set of extensions over the System.Data.Common.DbConnection object.

  • Some extensions may return the new Norm object instance.

  • Norm object instances have methods with the same signature as the System.Data.Common.DbConnection extensions.

  • This allows the use of the fluid syntax over the connection object. Example:

//
 // Execute a stored procedure with command timoout 60 seconds
 //
 connection
diff --git a/norm.net/docs/getting-started/first-use/index.html b/norm.net/docs/getting-started/first-use/index.html
index e97326bf..76baf825 100644
--- a/norm.net/docs/getting-started/first-use/index.html
+++ b/norm.net/docs/getting-started/first-use/index.html
@@ -1,4 +1,4 @@
-First Use

First Use

Edit this page on GitHub

Add Using

Add using Norm directive to the using section of your source file:

using Norm;
+First Use

First Use

Edit this page on GitHub

Add Using

Add using Norm directive to the using section of your source file:

using Norm;
 
 //... the rest of the source code ...
using Norm;
 
diff --git a/norm.net/docs/getting-started/installation/index.html b/norm.net/docs/getting-started/installation/index.html
index 5dcec21b..c838234d 100644
--- a/norm.net/docs/getting-started/installation/index.html
+++ b/norm.net/docs/getting-started/installation/index.html
@@ -1 +1 @@
-Installation

Installation

Edit this page on GitHub

.NET Command-Line-Interface

Run this command from the command line to install the latest version:

dotnet add package Norm.net --version 5.4.0
dotnet add package Norm.net --version 5.4.0

Visual Studio Package Manager Console (PowerShell)

Run this command from the Visual Studio Package Manager Console (PowerShell) to install the latest version:

NuGet\Install-Package Norm.net -Version 5.4.0
NuGet\Install-Package Norm.net -Version 5.4.0

Package Reference

Add this line to your csproj`` project file inside` section to install the latest version:

<PackageReference Include="Norm.net" Version="5.4.0" />
<PackageReference Include="Norm.net" Version="5.4.0" />

Script & Interactive

In your C# Interactive console or another scripting engine (such as csrepl, for example) - execute the following command to install the latest version:

#r "nuget: Norm.net, 5.4.0
#r "nuget: Norm.net, 5.4.0
Comments
\ No newline at end of file +Installation

Installation

Edit this page on GitHub

.NET Command-Line-Interface

Run this command from the command line to install the latest version:

dotnet add package Norm.net --version 5.4.0
dotnet add package Norm.net --version 5.4.0

Visual Studio Package Manager Console (PowerShell)

Run this command from the Visual Studio Package Manager Console (PowerShell) to install the latest version:

NuGet\Install-Package Norm.net -Version 5.4.0
NuGet\Install-Package Norm.net -Version 5.4.0

Package Reference

Add this line to your csproj`` project file inside` section to install the latest version:

<PackageReference Include="Norm.net" Version="5.4.0" />
<PackageReference Include="Norm.net" Version="5.4.0" />

Script & Interactive

In your C# Interactive console or another scripting engine (such as csrepl, for example) - execute the following command to install the latest version:

#r "nuget: Norm.net, 5.4.0
#r "nuget: Norm.net, 5.4.0
Comments
\ No newline at end of file diff --git a/norm.net/docs/getting-started/introduction/index.html b/norm.net/docs/getting-started/introduction/index.html index 53ddc635..85c42e26 100644 --- a/norm.net/docs/getting-started/introduction/index.html +++ b/norm.net/docs/getting-started/introduction/index.html @@ -1 +1 @@ -Introduction

Introduction

Edit this page on GitHub

Norm is the Micro-ORM library for efficient data access in the .NET ecosystem.

It supports .NET Standard 2.1 or higher and .NET Core 3.0 and higher (.NET Core 3, .NET 5, 6, 7, 8, etc).

See the full compatibility table.


Micro-ORM

Micro-ORM libraries implement one-way mapping - from your database commands and queries - to .NET types and structures.

That means that all database commands and queries must be handwritten in SQL - and Norm is here to help you efficiently map the results into the .NET types and structures.


Connection Extensions

Norm is a set of extensions over the System.Data.Common.DbConnection object.

That means that if the connection implements System.Data.Common.DbConnection type - the database that implements that connection is supported. And that includes, for example:

Comments
\ No newline at end of file +Introduction

Introduction

Edit this page on GitHub

Norm is the Micro-ORM library for efficient data access in the .NET ecosystem.

It supports .NET Standard 2.1 or higher and .NET Core 3.0 and higher (.NET Core 3, .NET 5, 6, 7, 8, etc).

See the full compatibility table.


Micro-ORM

Micro-ORM libraries implement one-way mapping - from your database commands and queries - to .NET types and structures.

That means that all database commands and queries must be handwritten in SQL - and Norm is here to help you efficiently map the results into the .NET types and structures.


Connection Extensions

Norm is a set of extensions over the System.Data.Common.DbConnection object.

That means that if the connection implements System.Data.Common.DbConnection type - the database that implements that connection is supported. And that includes, for example:

Comments
\ No newline at end of file diff --git a/norm.net/docs/reference/methods/index.html b/norm.net/docs/reference/methods/index.html index b10bbaa0..731f8e83 100644 --- a/norm.net/docs/reference/methods/index.html +++ b/norm.net/docs/reference/methods/index.html @@ -1,4 +1,4 @@ -Methods

Extensions Methods

Edit this page on GitHub
  • To implement fluid syntax, Norm extensions are implemented in two versions:
  1. As DbConnection object extension methods.

  2. As instance methods.

  • Both extension methods and instance methods have the same basic signature (except for this DbConnection connection parameter in extension methods), and they return the Norm instance whenever they can to ensure fluid syntax.

As

// Extension
+Methods

Extensions Methods

Edit this page on GitHub
  • To implement fluid syntax, Norm extensions are implemented in two versions:
  1. As DbConnection object extension methods.

  2. As instance methods.

  • Both extension methods and instance methods have the same basic signature (except for this DbConnection connection parameter in extension methods), and they return the Norm instance whenever they can to ensure fluid syntax.

As

// Extension
 public static Norm As(this DbConnection connection, System.Data.CommandType type);
 // Norm Instance Method
 public Norm As(System.Data.CommandType type);
// Extension
diff --git a/norm.net/docs/reference/multiple/index.html b/norm.net/docs/reference/multiple/index.html
index 46cead37..2b4ca085 100644
--- a/norm.net/docs/reference/multiple/index.html
+++ b/norm.net/docs/reference/multiple/index.html
@@ -1,4 +1,4 @@
-Multiple Mappings

Multiple Commands

Edit this page on GitHub
  • There's built-in support for working with multiple mappings in a single batch.

  • Extensions and methods Multiple (in all versions) accept multiple commands separated by the semicolon character (;) - and will return a disposable instance used for reading and mapping each command:

// Extensions
+Multiple Mappings

Multiple Commands

Edit this page on GitHub
  • There's built-in support for working with multiple mappings in a single batch.

  • Extensions and methods Multiple (in all versions) accept multiple commands separated by the semicolon character (;) - and will return a disposable instance used for reading and mapping each command:

// Extensions
 public static NormMultipleBatch Multiple(this DbConnection connection, string command, object parameters = null);
 public static NormMultipleBatch MultipleFormat(this DbConnection connection, FormattableString command, object parameters = null);
 // Sync Extensions
diff --git a/norm.net/docs/reference/options/index.html b/norm.net/docs/reference/options/index.html
index b1b12a7b..fc73fd1f 100644
--- a/norm.net/docs/reference/options/index.html
+++ b/norm.net/docs/reference/options/index.html
@@ -1,4 +1,4 @@
-Options

Norm Options

Edit this page on GitHub
  • Norm options are set at the program startup by calling NormOptions.Configure static method.

  • This method has the following signature:

public static void Configure(Action<NormOptions> options)
public static void Configure(Action<NormOptions> options)
  • The parameter is a callback action to the options object where we can set different options that affect the later behavior.

  • Call to NormOptions.Configure is not thread-safe - it is intended to be called only once on a program startup.

  • The list of available options is listed below.


CommandCommentHeader

  • Sets the command comment header options that will be applied for all commands.

  • This is a complex object containing multiple different commands:

class CommandCommentHeader
+Options

Norm Options

Edit this page on GitHub
  • Norm options are set at the program startup by calling NormOptions.Configure static method.

  • This method has the following signature:

public static void Configure(Action<NormOptions> options)
public static void Configure(Action<NormOptions> options)
  • The parameter is a callback action to the options object where we can set different options that affect the later behavior.

  • Call to NormOptions.Configure is not thread-safe - it is intended to be called only once on a program startup.

  • The list of available options is listed below.


CommandCommentHeader

  • Sets the command comment header options that will be applied for all commands.

  • This is a complex object containing multiple different commands:

class CommandCommentHeader
 {
     public bool Enabled { get; set; } = false;
     public bool IncludeCommandAttributes { get; set; } = true;
diff --git a/norm.net/docs/reference/parameters/index.html b/norm.net/docs/reference/parameters/index.html
index b38ab87d..19719701 100644
--- a/norm.net/docs/reference/parameters/index.html
+++ b/norm.net/docs/reference/parameters/index.html
@@ -1,4 +1,4 @@
-Parameters

Working With Parameters

Edit this page on GitHub

1) WithParameters Extension Method

  • WithParameters extension sets parameters for the next command and it has the following signature:
// Extension
+Parameters

Working With Parameters

Edit this page on GitHub

1) WithParameters Extension Method

  • WithParameters extension sets parameters for the next command and it has the following signature:
// Extension
 public static Norm WithParameters(this DbConnection connection, params object[] parameters);
 // Norm Instance Method
 public Norm WithParameters(params object[] parameters);
// Extension
diff --git a/norm.net/docs/reference/read/index.html b/norm.net/docs/reference/read/index.html
index cf4cc00b..c153fe6d 100644
--- a/norm.net/docs/reference/read/index.html
+++ b/norm.net/docs/reference/read/index.html
@@ -1,4 +1,4 @@
-Read Mappings

Read Mappings

Edit this page on GitHub
  • Read methods implement a complex mapping system that enables you to map to anything from simple types to tuples and object instances.

  • There are four groups: Read, ReadAsync, ReadFormat and ReadFormatAsync.

  • Each of these methods has:

    1. Connections extension and the instance method version. These are identical in functionality and exist only to implement fluid syntax.

    2. A non-generic version that yields a name and value tuple array for each row.

    3. Single generic type version that yields the same type as supplied by the generic parameter for each row.

    4. Multiple generic types that yields tuples based on generic parameters for each row.

    5. Instance blueprint version that yields new instances based on the blueprint instance for each row.


Non-generic Version

// Extension
+Read Mappings

Read Mappings

Edit this page on GitHub
  • Read methods implement a complex mapping system that enables you to map to anything from simple types to tuples and object instances.

  • There are four groups: Read, ReadAsync, ReadFormat and ReadFormatAsync.

  • Each of these methods has:

    1. Connections extension and the instance method version. These are identical in functionality and exist only to implement fluid syntax.

    2. A non-generic version that yields a name and value tuple array for each row.

    3. Single generic type version that yields the same type as supplied by the generic parameter for each row.

    4. Multiple generic types that yields tuples based on generic parameters for each row.

    5. Instance blueprint version that yields new instances based on the blueprint instance for each row.


Non-generic Version

// Extension
 public static IEnumerable<(string name, object value)[]> Read(this DbConnection connection, 
     string command, 
     object parameters = null);
diff --git a/norm.net/example/index.html b/norm.net/example/index.html
index e4277b4d..3e574ace 100644
--- a/norm.net/example/index.html
+++ b/norm.net/example/index.html
@@ -1,4 +1,4 @@
-Norm.NET Data Access Example Project

Norm Example Project

Sample project with various examples of Norm usage and features. You can find the source code for this project on GitHub.

using System.Data.Common;
+Norm.NET Data Access Example Project

Norm Example Project

Sample project with various examples of Norm usage and features. You can find the source code for this project on GitHub.

using System.Data.Common;
 using Norm;
 using Npgsql;
 using static System.Console;
diff --git a/norm.net/index.html b/norm.net/index.html
index 26c26e58..7f0cb52d 100644
--- a/norm.net/index.html
+++ b/norm.net/index.html
@@ -1,4 +1,4 @@
-Norm.NET Data Access

Norm.NET Micro ORM

Norm.NET Micro ORM is a one-way lightweight object-relational mapping library.

Micro ORM for .NET/C#.

What is Micro ORM Blog Post

Installation
dotnet add package Norm.net --version 5.4.0
dotnet add package Norm.net --version 5.4.0
NuGet\Install-Package Norm.net -Version 5.4.0
NuGet\Install-Package Norm.net -Version 5.4.0
<PackageReference Include="Norm.net" Version="5.4.0" />
<PackageReference Include="Norm.net" Version="5.4.0" />
#r "nuget: Norm.net, 5.4.0"
#r "nuget: Norm.net, 5.4.0"
Compatibility
netstandard2.1
net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows net7.0 net7.0-android net7.0-ios net7.0-maccatalyst net7.0-macos net7.0-tvos net7.0-windows net8.0 net8.0-android net8.0-ios net8.0-maccatalyst net8.0-macos net8.0-tvos net8.0-windows
netcoreapp3.0 netcoreapp3.1
monoandroid monomac monotouch
tizen60
xamarinios xamarinmac xamarintvos xamarinwatchos
Perfomances
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,664.21.00740.911.00
ADO.NET Raw5,213.10.92295.410.40
EF Core 86,188.41.10493.080.67
Norm (instances) 5,768.01.02594.890.80
Norm (tuple values) 6,068.61.07209.060.28
Norm (named tuples) 5,805.51.03764.461.03
Norm (anonymous inst.) 6,178.61.10695.440.94
Norm (tuple array) 5,441.50.97686.660.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)60,626.51.007521.521.00
ADO.NET Raw39,086.70.652968.310.39
EF Core 849,088.00.8148540.65
Norm (instances) 46,987.10.785941.230.79
Norm (tuple values) 48,000.40.802108.960.28
Norm (named tuples) 45,584.70.757655.891.02
Norm (anonymous inst.) 49,914.90.836953.850.92
Norm (tuple array) 41,510.40.696875.110.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)591,684.01.0075439.471.00
ADO.NET Raw360,967.30.6230390.180.40
EF Core 8430,804.80.7349150.920.65
Norm (instances) 399,019.80.6860101.440.80
Norm (tuple values) 407,943.40.6921809.590.29
Norm (named tuples) 421,935.60.7177267.791.02
Norm (anonymous inst.) 409,893.50.6970242.370.93
Norm (tuple array) 402,777.60.6869454.650.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)649.91.008.261.00
ADO.NET Raw524.00.813.560.43
EF Core 8734.21.1316.251.97
Norm (instances) 568.70.889.581.16
Norm (tuple values) 536.90.832.90.35
Norm (named tuples) 545.00.849.151.11
Norm (anonymous inst.) 575.00.899.771.18
Norm (tuple array) 542.20.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,777.21.00740.931.00
ADO.NET Raw5,379.70.93295.350.40
EF Core 86,258.61.09493.110.67
Norm (instances) 6,019.71.05594.980.80
Norm (tuple values) 5,865.61.02209.120.28
Norm (named tuples) 6,017.91.05764.491.03
Norm (anonymous inst.) 6,354.11.11695.570.94
Norm (tuple array) 5,522.80.96686.670.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)58,930.51.007520.981.00
ADO.NET Raw39,097.30.662969.410.39
EF Core 848,248.90.824854.970.65
Norm (instances) 46,338.40.805942.90.79
Norm (tuple values) 48,488.90.822109.420.28
Norm (named tuples) 44,790.40.767657.11.02
Norm (anonymous inst.) 50,031.20.856954.210.92
Norm (tuple array) 41,447.60.716877.550.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)592,008.81.0075409.61.00
ADO.NET Raw367,873.00.6330420.180.40
EF Core 8408,393.70.7049150.920.65
Norm (instances) 414,667.60.7060081.190.80
Norm (tuple values) 408,334.90.7021799.090.29
Norm (named tuples) 425,086.20.7177268.351.02
Norm (anonymous inst.) 431,558.50.7470255.870.93
Norm (tuple array) 385,006.60.6569478.790.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)658.51.008.251.00
ADO.NET Raw524.80.803.560.43
EF Core 8733.31.1216.251.97
Norm (instances) 554.70.859.581.16
Norm (tuple values) 537.00.822.90.35
Norm (named tuples) 542.00.839.141.11
Norm (anonymous inst.) 555.90.859.761.18
Norm (tuple array) 521.00.798.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,697.91.00740.821.00
ADO.NET Raw5,212.00.92295.620.40
EF Core 86,200.31.09493.180.67
Norm (instances) 5,883.71.04594.950.80
Norm (tuple values) 5,846.51.03209.10.28
Norm (named tuples) 5,719.61.01764.61.03
Norm (anonymous inst.) 6,241.51.10695.510.94
Norm (tuple array) 5,391.80.95686.520.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)59,447.51.007521.161.00
ADO.NET Raw38,727.80.662970.950.40
EF Core 849,114.70.834853.490.65
Norm (instances) 45,102.20.765940.40.79
Norm (tuple values) 46,517.70.782111.590.28
Norm (named tuples) 45,105.40.767655.521.02
Norm (anonymous inst.) 48,528.60.826955.490.92
Norm (tuple array) 40,575.90.686877.660.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)565,696.91.0075438.921.00
ADO.NET Raw361,561.30.6430411.510.40
EF Core 8462,485.90.8349149.660.65
Norm (instances) 403,805.50.71600990.80
Norm (tuple values) 420,217.30.7521804.710.29
Norm (named tuples) 400,954.00.7177267.931.02
Norm (anonymous inst.) 411,138.90.7370237.30.93
Norm (tuple array) 381,007.90.6769453.710.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)643.31.008.231.00
ADO.NET Raw512.80.803.560.43
EF Core 8725.31.1416.241.97
Norm (instances) 570.70.899.581.16
Norm (tuple values) 525.40.822.90.35
Norm (named tuples) 527.30.829.151.11
Norm (anonymous inst.) 541.70.849.771.19
Norm (tuple array) 519.10.818.291.01
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)6,180.01.00741.021.00
ADO.NET Raw5,681.00.92295.280.40
EF Core 86,608.41.07493.340.67
Norm (instances) 5,821.90.95594.840.80
Norm (tuple values) 5,829.50.95209.060.28
Norm (named tuples) 6,090.30.99764.541.03
Norm (anonymous inst.) 6,594.01.07695.540.94
Norm (tuple array) 5,339.50.87686.780.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)58,674.01.007521.11.00
ADO.NET Raw38,436.20.662970.360.39
EF Core 847,979.20.824854.780.65
Norm (instances) 44,340.50.765940.010.79
Norm (tuple values) 48,177.70.822108.040.28
Norm (named tuples) 45,144.30.787657.481.02
Norm (anonymous inst.) 48,940.20.846957.480.93
Norm (tuple array) 41,034.20.7068760.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)578,149.01.0075409.661.00
ADO.NET Raw359,674.20.6430395.050.40
EF Core 8404,648.00.7049150.920.65
Norm (instances) 411,144.20.7260081.190.80
Norm (tuple values) 399,769.80.6921797.020.29
Norm (named tuples) 396,422.10.6977266.661.02
Norm (anonymous inst.) 432,315.60.7570240.870.93
Norm (tuple array) 384,060.60.6669457.090.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)629.51.008.271.00
ADO.NET Raw526.30.843.560.43
EF Core 8730.21.1616.251.97
Norm (instances) 557.30.899.581.16
Norm (tuple values) 531.90.852.90.35
Norm (named tuples) 533.50.859.151.11
Norm (anonymous inst.) 540.20.869.771.18
Norm (tuple array) 530.60.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,584.51.00740.91.00
ADO.NET Raw5,034.80.91295.650.40
EF Core 86,108.41.10493.030.67
Norm (instances) 5,841.81.05594.810.80
Norm (tuple values) 6,590.31.19209.030.28
Norm (named tuples) 5,564.51.00764.631.03
Norm (anonymous inst.) 6,194.71.12695.460.94
Norm (tuple array) 5,309.50.96686.90.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)61,134.91.007520.61.00
ADO.NET Raw42,847.00.702969.960.39
EF Core 851,986.00.854855.920.65
Norm (instances) 48,545.40.805940.020.79
Norm (tuple values) 51,634.40.852108.180.28
Norm (named tuples) 47,648.40.787655.761.02
Norm (anonymous inst.) 51,557.80.856954.640.92
Norm (tuple array) 42,906.10.706876.750.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)601,452.61.0075412.971.00
ADO.NET Raw367,371.10.6130389.80.40
EF Core 8426,235.90.7149150.920.65
Norm (instances) 447,736.00.7560087.190.80
Norm (tuple values) 442,534.90.7421800.210.29
Norm (named tuples) 426,983.90.7177275.11.02
Norm (anonymous inst.) 419,724.80.7070237.870.93
Norm (tuple array) 396,666.10.6669492.310.92
see more details on perfomance page
Build database tuples iterator
You can read an array of name and value tuples (string name, value object) - for each record, where the name is the field name, and the value is, well, the value of that record.

Use LINQ expressions to build appropriate data structures such as dictionaries directly from your database and with minimum iterations.
using System.Linq;
+Norm.NET Data Access

Norm.NET Micro ORM

Norm.NET Micro ORM is a one-way lightweight object-relational mapping library.

Micro ORM for .NET/C#.

What is Micro ORM Blog Post

Installation
dotnet add package Norm.net --version 5.4.0
dotnet add package Norm.net --version 5.4.0
NuGet\Install-Package Norm.net -Version 5.4.0
NuGet\Install-Package Norm.net -Version 5.4.0
<PackageReference Include="Norm.net" Version="5.4.0" />
<PackageReference Include="Norm.net" Version="5.4.0" />
#r "nuget: Norm.net, 5.4.0"
#r "nuget: Norm.net, 5.4.0"
Compatibility
netstandard2.1
net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows net7.0 net7.0-android net7.0-ios net7.0-maccatalyst net7.0-macos net7.0-tvos net7.0-windows net8.0 net8.0-android net8.0-ios net8.0-maccatalyst net8.0-macos net8.0-tvos net8.0-windows
netcoreapp3.0 netcoreapp3.1
monoandroid monomac monotouch
tizen60
xamarinios xamarinmac xamarintvos xamarinwatchos
Perfomances
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,664.21.00740.911.00
ADO.NET Raw5,213.10.92295.410.40
EF Core 86,188.41.10493.080.67
Norm (instances) 5,768.01.02594.890.80
Norm (tuple values) 6,068.61.07209.060.28
Norm (named tuples) 5,805.51.03764.461.03
Norm (anonymous inst.) 6,178.61.10695.440.94
Norm (tuple array) 5,441.50.97686.660.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)60,626.51.007521.521.00
ADO.NET Raw39,086.70.652968.310.39
EF Core 849,088.00.8148540.65
Norm (instances) 46,987.10.785941.230.79
Norm (tuple values) 48,000.40.802108.960.28
Norm (named tuples) 45,584.70.757655.891.02
Norm (anonymous inst.) 49,914.90.836953.850.92
Norm (tuple array) 41,510.40.696875.110.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)591,684.01.0075439.471.00
ADO.NET Raw360,967.30.6230390.180.40
EF Core 8430,804.80.7349150.920.65
Norm (instances) 399,019.80.6860101.440.80
Norm (tuple values) 407,943.40.6921809.590.29
Norm (named tuples) 421,935.60.7177267.791.02
Norm (anonymous inst.) 409,893.50.6970242.370.93
Norm (tuple array) 402,777.60.6869454.650.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)649.91.008.261.00
ADO.NET Raw524.00.813.560.43
EF Core 8734.21.1316.251.97
Norm (instances) 568.70.889.581.16
Norm (tuple values) 536.90.832.90.35
Norm (named tuples) 545.00.849.151.11
Norm (anonymous inst.) 575.00.899.771.18
Norm (tuple array) 542.20.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,777.21.00740.931.00
ADO.NET Raw5,379.70.93295.350.40
EF Core 86,258.61.09493.110.67
Norm (instances) 6,019.71.05594.980.80
Norm (tuple values) 5,865.61.02209.120.28
Norm (named tuples) 6,017.91.05764.491.03
Norm (anonymous inst.) 6,354.11.11695.570.94
Norm (tuple array) 5,522.80.96686.670.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)58,930.51.007520.981.00
ADO.NET Raw39,097.30.662969.410.39
EF Core 848,248.90.824854.970.65
Norm (instances) 46,338.40.805942.90.79
Norm (tuple values) 48,488.90.822109.420.28
Norm (named tuples) 44,790.40.767657.11.02
Norm (anonymous inst.) 50,031.20.856954.210.92
Norm (tuple array) 41,447.60.716877.550.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)592,008.81.0075409.61.00
ADO.NET Raw367,873.00.6330420.180.40
EF Core 8408,393.70.7049150.920.65
Norm (instances) 414,667.60.7060081.190.80
Norm (tuple values) 408,334.90.7021799.090.29
Norm (named tuples) 425,086.20.7177268.351.02
Norm (anonymous inst.) 431,558.50.7470255.870.93
Norm (tuple array) 385,006.60.6569478.790.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)658.51.008.251.00
ADO.NET Raw524.80.803.560.43
EF Core 8733.31.1216.251.97
Norm (instances) 554.70.859.581.16
Norm (tuple values) 537.00.822.90.35
Norm (named tuples) 542.00.839.141.11
Norm (anonymous inst.) 555.90.859.761.18
Norm (tuple array) 521.00.798.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,697.91.00740.821.00
ADO.NET Raw5,212.00.92295.620.40
EF Core 86,200.31.09493.180.67
Norm (instances) 5,883.71.04594.950.80
Norm (tuple values) 5,846.51.03209.10.28
Norm (named tuples) 5,719.61.01764.61.03
Norm (anonymous inst.) 6,241.51.10695.510.94
Norm (tuple array) 5,391.80.95686.520.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)59,447.51.007521.161.00
ADO.NET Raw38,727.80.662970.950.40
EF Core 849,114.70.834853.490.65
Norm (instances) 45,102.20.765940.40.79
Norm (tuple values) 46,517.70.782111.590.28
Norm (named tuples) 45,105.40.767655.521.02
Norm (anonymous inst.) 48,528.60.826955.490.92
Norm (tuple array) 40,575.90.686877.660.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)565,696.91.0075438.921.00
ADO.NET Raw361,561.30.6430411.510.40
EF Core 8462,485.90.8349149.660.65
Norm (instances) 403,805.50.71600990.80
Norm (tuple values) 420,217.30.7521804.710.29
Norm (named tuples) 400,954.00.7177267.931.02
Norm (anonymous inst.) 411,138.90.7370237.30.93
Norm (tuple array) 381,007.90.6769453.710.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)643.31.008.231.00
ADO.NET Raw512.80.803.560.43
EF Core 8725.31.1416.241.97
Norm (instances) 570.70.899.581.16
Norm (tuple values) 525.40.822.90.35
Norm (named tuples) 527.30.829.151.11
Norm (anonymous inst.) 541.70.849.771.19
Norm (tuple array) 519.10.818.291.01
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)6,180.01.00741.021.00
ADO.NET Raw5,681.00.92295.280.40
EF Core 86,608.41.07493.340.67
Norm (instances) 5,821.90.95594.840.80
Norm (tuple values) 5,829.50.95209.060.28
Norm (named tuples) 6,090.30.99764.541.03
Norm (anonymous inst.) 6,594.01.07695.540.94
Norm (tuple array) 5,339.50.87686.780.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)58,674.01.007521.11.00
ADO.NET Raw38,436.20.662970.360.39
EF Core 847,979.20.824854.780.65
Norm (instances) 44,340.50.765940.010.79
Norm (tuple values) 48,177.70.822108.040.28
Norm (named tuples) 45,144.30.787657.481.02
Norm (anonymous inst.) 48,940.20.846957.480.93
Norm (tuple array) 41,034.20.7068760.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)578,149.01.0075409.661.00
ADO.NET Raw359,674.20.6430395.050.40
EF Core 8404,648.00.7049150.920.65
Norm (instances) 411,144.20.7260081.190.80
Norm (tuple values) 399,769.80.6921797.020.29
Norm (named tuples) 396,422.10.6977266.661.02
Norm (anonymous inst.) 432,315.60.7570240.870.93
Norm (tuple array) 384,060.60.6669457.090.92
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)629.51.008.271.00
ADO.NET Raw526.30.843.560.43
EF Core 8730.21.1616.251.97
Norm (instances) 557.30.899.581.16
Norm (tuple values) 531.90.852.90.35
Norm (named tuples) 533.50.859.151.11
Norm (anonymous inst.) 540.20.869.771.18
Norm (tuple array) 530.60.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)634.31.008.261.00
ADO.NET Raw517.60.823.560.43
EF Core 8731.31.1516.241.96
Norm (instances) 569.90.909.581.16
Norm (tuple values) 544.70.862.90.35
Norm (named tuples) 530.40.849.151.11
Norm (anonymous inst.) 549.60.879.761.18
Norm (tuple array) 535.10.848.291.00
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)5,584.51.00740.91.00
ADO.NET Raw5,034.80.91295.650.40
EF Core 86,108.41.10493.030.67
Norm (instances) 5,841.81.05594.810.80
Norm (tuple values) 6,590.31.19209.030.28
Norm (named tuples) 5,564.51.00764.631.03
Norm (anonymous inst.) 6,194.71.12695.460.94
Norm (tuple array) 5,309.50.96686.90.93
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)61,134.91.007520.61.00
ADO.NET Raw42,847.00.702969.960.39
EF Core 851,986.00.854855.920.65
Norm (instances) 48,545.40.805940.020.79
Norm (tuple values) 51,634.40.852108.180.28
Norm (named tuples) 47,648.40.787655.761.02
Norm (anonymous inst.) 51,557.80.856954.640.92
Norm (tuple array) 42,906.10.706876.750.91
Library (method)Mean μsRatioAllocated KBAllocated Ratio
Dapper (instances)601,452.61.0075412.971.00
ADO.NET Raw367,371.10.6130389.80.40
EF Core 8426,235.90.7149150.920.65
Norm (instances) 447,736.00.7560087.190.80
Norm (tuple values) 442,534.90.7421800.210.29
Norm (named tuples) 426,983.90.7177275.11.02
Norm (anonymous inst.) 419,724.80.7070237.870.93
Norm (tuple array) 396,666.10.6669492.310.92
see more details on perfomance page
Build database tuples iterator
You can read an array of name and value tuples (string name, value object) - for each record, where the name is the field name, and the value is, well, the value of that record.

Use LINQ expressions to build appropriate data structures such as dictionaries directly from your database and with minimum iterations.
using System.Linq;
 using Norm;
 
 //
diff --git a/npgsqlrest/annotations/index.html b/npgsqlrest/annotations/index.html
index 45e78de5..75002ea2 100644
--- a/npgsqlrest/annotations/index.html
+++ b/npgsqlrest/annotations/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest Annotations - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Annotations Guide

Edit this page on GitHub

BufferRows

bufferrows number                                          
+NpgsqlRest Annotations - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Annotations Guide

Edit this page on GitHub

BufferRows

bufferrows number                                          
 buffer_rows number                                         
 buffer-rows number                                         
 buffer number
bufferrows number                                          
diff --git a/npgsqlrest/changelog/index.html b/npgsqlrest/changelog/index.html
index 1ac8a8d7..28173493 100644
--- a/npgsqlrest/changelog/index.html
+++ b/npgsqlrest/changelog/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Changelog

Edit this page on GitHub

Note: For a changelog for a client application see the client application page changelog.


Version 2.8.2 (2024-06-09)

Full Changelog

Fixed bug with default parameters

Using a routine that has a default parameters and supplying one of the parameters would sometimes caused mixing of the parameter order. For example, if the routine is defined as:

create function get_two_default_params(
+NpgsqlRest - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Changelog

Edit this page on GitHub

Note: For a changelog for a client application see the client application page changelog.


Version 2.8.3 (2024-06-11)

Full Changelog

Fix inconsistency with sending request parameters by routine parameters.

Previously it was possible to send request parameters to parameters without default values. To use request parameters in routine parameters, that parameter has to have a default value always.

This inconsistency is actually a bug in cases when the request header parameter name wasn't provided a value.

This is fixed now.

TsClient 1.8.1:

  • If all routines are skipped, don't write any files.

Version 2.8.2 (2024-06-09)

Full Changelog

Fixed bug with default parameters

Using a routine that has default parameters and supplying one of the parameters would sometimes cause mixing of the parameter order. For example, if the routine is defined like this:

create function get_two_default_params(
     _p1 text = 'abc', 
     _p2 text = 'xyz'
 ) 
@@ -16,7 +16,7 @@
 as 
 $$
 select _p1 || _p2;
-$$;

And invoking it with only second parameter parameter (p2) would mix p1 and p2 and wrongly assume that the first parameter is the second parameter and vice versa.

This is now fixed and the parameters are correctly assigned.

Fixed bug with default parameters for PostgreSQL roles that are not super-users.

When using a PostgreSQL role that is not a super-user, the default parameters were not correctly assigned.

This may be a bug in PostgreSQL itself (reported), column parameter_default in system table information_schema.parameters always returns null for roles that are not super-users.

Workaround is implemented and tested to use the pg_get_function_arguments function and then to parse the default values from the function definition.


Version 2.8.1 (2024-05-10)

Full Changelog

  • Upgrade Npgsql from 8.0.0 to 8.0.3
  • Fix null dereference of a possibly null build warning.

Version 2.8.0 (2024-05-02)

Full Changelog

  • New Option: Dictionary<string, StringValues> CustomRequestHeaders

Custom request headers dictionary that will be added to NpgsqlRest requests.

Note: these values are added to the request headers dictionary before they are sent as a context or parameter to the PostgreSQL routine and as such not visible to the browser debugger.

TsClient Version 1.7.0

  • Sanitaze generated TypeScript names.
  • Add SkipRoutineNames, SkipFunctionNames and SkipPaths options.

Version 2.7.1 (2024-04-30)

Full Changelog

  • Small fix on the Login endpoint that fixed the problem with the custom message not being written to the response in some rare circumstances.
  • Redesigned the auth module and changed the access modifiers to the public of the ClaimTypes Dictionary to be used with the client application.

Version 2.7.0 (2024-04-17)

Full Changelog

New callback option: Action<NpgsqlConnection, Routine, RoutineEndpoint, HttpContext>? BeforeConnectionOpen.

This is used to set the application name parameter (for example) without having to use the service provider. It executes before the new connection is open for the request. For example:

app.UseNpgsqlRest(new()
+$$;

Invoking it with only the second parameter parameter (p2) would mix p1 and p2 and wrongly assume that the first parameter is the second parameter and vice versa.

This is now fixed and the parameters are correctly assigned.

Fixed bug with default parameters for PostgreSQL roles that are not super-users.

When using a PostgreSQL role that is not a super-user, the default parameters were not correctly assigned.

This may be a bug in PostgreSQL itself (reported), column parameter_default in system table information_schema.parameters always returns null for roles that are not super-users.

Workaround is implemented and tested to use the pg_get_function_arguments function and then to parse the default values from the function definition.


Version 2.8.1 (2024-05-10)

Full Changelog

  • Upgrade Npgsql from 8.0.0 to 8.0.3
  • Fix null dereference of a possibly null build warning.

Version 2.8.0 (2024-05-02)

Full Changelog

  • New Option: Dictionary<string, StringValues> CustomRequestHeaders

Custom request headers dictionary that will be added to NpgsqlRest requests.

Note: these values are added to the request headers dictionary before they are sent as a context or parameter to the PostgreSQL routine and as such not visible to the browser debugger.

TsClient Version 1.7.0

  • Sanitaze generated TypeScript names.
  • Add SkipRoutineNames, SkipFunctionNames and SkipPaths options.

Version 2.7.1 (2024-04-30)

Full Changelog

  • Small fix on the Login endpoint that fixed the problem with the custom message not being written to the response in some rare circumstances.
  • Redesigned the auth module and changed the access modifiers to the public of the ClaimTypes Dictionary to be used with the client application.

Version 2.7.0 (2024-04-17)

Full Changelog

New callback option: Action<NpgsqlConnection, Routine, RoutineEndpoint, HttpContext>? BeforeConnectionOpen.

This is used to set the application name parameter (for example) without having to use the service provider. It executes before the new connection is open for the request. For example:

app.UseNpgsqlRest(new()
 {
     ConnectionString = connectionString,
     BeforeConnectionOpen = (NpgsqlConnection connection, Routine routine, RoutineEndpoint endpoint, HttpContext context) =>
@@ -174,4 +174,4 @@
     SourcesCreated = sources => sources.Add(new CrudSource())
 });
 
-app.Run();

Other Changes

Other changes include:

  • Optimizations
  • Bugfixes for edge cases

Full list of available options and annotations for version 2:


Older Versions

The changelog for the previous version can be found here: Changelog Version 1


Comments
\ No newline at end of file +app.Run();

Other Changes

Other changes include:

  • Optimizations
  • Bugfixes for edge cases

Full list of available options and annotations for version 2:


Older Versions

The changelog for the previous version can be found here: Changelog Version 1


Comments
\ No newline at end of file diff --git a/npgsqlrest/client-npm/index.html b/npgsqlrest/client-npm/index.html index cbccd39a..47e4eea5 100644 --- a/npgsqlrest/client-npm/index.html +++ b/npgsqlrest/client-npm/index.html @@ -1,4 +1,4 @@ -NpgsqlRest Client NPM Package - Automatic REST API for PostgreSQL Database as .NET8 Middleware

npgsqlrest

Edit this page on GitHub

npm version build-test-publish License GitHub Stars GitHub Forks

Description

The npgsqlrest is an NPM distribution of the self-contained ahead-of-time (AOT) compiled to native code executables of the NpgsqlRest Client Web App.

NpgsqlRest is an Automatic REST API for PostgreSQL Database as the .NET8 Middleware. See the GitHub Readme for more info.

NpgsqlRest Client Web App is a command line utility that runs as a configurable Kestrel web server that can:

  • Create an Automatic REST API for the PostgreSQL Databases.
  • Generate TypeScript Code and HTTP files for testing.
  • Configure security for use the of either encrypted cookies or JWT Bearer tokens or both.
  • Expose REST API endpoints for the PostgreSQL Databases as Login/Logout.
  • Use external authentication providers such as Google, LinkedIn or GitHub.
  • Server static content.
  • Use and configure built-in Serilog structured logging.
  • Configure Cross-origin resource sharing (CORS) access, SSL, Server Certificates and more, everything needed for modern Web development.

See the default configuration file with descriptions for more information.

Notes Before Installation

This package will download an executable file for the target OS on installation (see the postinstall.js script) from the GitHub release page.

Currently, only the Windows-64 and Linux-64 builds are supported.

The Mac OS builds are missing because I don't have a Mac machine. If someone could help me out with this I'd be grateful.

If you try to install this package on MacOS, or any other unsupported OS, installation will report: Unsupported OS detected: [OS Type].

To see how you can create your own custom build follow these instructions:

Steps:

  1. Make sure that you have .NET8 SDK installed and ready.
  2. Clone NpgsqlRest repository
  3. Navigate to the NpgsqlRestClient project directory.
  4. Make your desired customizations (or not).
  5. Run publish command, for example, dotnet publish -r win-x64 -c Release --output [target dir]

Notes: win-x64 is the designated target OS for the build. Adjust this parameter appropriately for the target OS. See https://learn.microsoft.com/en-us/dotnet/core/rid-catalog#known-rids. The project is already configured for the AOT builds, but you will need to run the publish command from the same flavor OS as the build target OS (Windows for Windows builds, Linux for Linux builds, etc).

Installation

Install npgsqlrest using npm:

npm install npgsqlrest --save-dev
npm install npgsqlrest --save-dev

Usage

$ npx npgsqlrest --help
+NpgsqlRest Client NPM Package - Automatic REST API for PostgreSQL Database as .NET8 Middleware

npgsqlrest

Edit this page on GitHub

npm version build-test-publish License GitHub Stars GitHub Forks

Description

The npgsqlrest is an NPM distribution of the self-contained ahead-of-time (AOT) compiled to native code executables of the NpgsqlRest Client Web App.

NpgsqlRest is an Automatic REST API for PostgreSQL Database as the .NET8 Middleware. See the GitHub Readme for more info.

NpgsqlRest Client Web App is a command line utility that runs as a configurable Kestrel web server that can:

  • Create an Automatic REST API for the PostgreSQL Databases.
  • Generate TypeScript Code and HTTP files for testing.
  • Configure security for use the of either encrypted cookies or JWT Bearer tokens or both.
  • Expose REST API endpoints for the PostgreSQL Databases as Login/Logout.
  • Use external authentication providers such as Google, LinkedIn or GitHub.
  • Server static content.
  • Use and configure built-in Serilog structured logging.
  • Configure Cross-origin resource sharing (CORS) access, SSL, Server Certificates and more, everything needed for modern Web development.

See the default configuration file with descriptions for more information.

Notes Before Installation

This package will download an executable file for the target OS on installation (see the postinstall.js script) from the GitHub release page.

Currently, only the Windows-64 and Linux-64 builds are supported.

The Mac OS builds are missing because I don't have a Mac machine. If someone could help me out with this I'd be grateful.

If you try to install this package on MacOS, or any other unsupported OS, installation will report: Unsupported OS detected: [OS Type].

To see how you can create your own custom build follow these instructions:

Steps:

  1. Make sure that you have .NET8 SDK installed and ready.
  2. Clone NpgsqlRest repository
  3. Navigate to the NpgsqlRestClient project directory.
  4. Make your desired customizations (or not).
  5. Run publish command, for example, dotnet publish -r win-x64 -c Release --output [target dir]

Notes: win-x64 is the designated target OS for the build. Adjust this parameter appropriately for the target OS. See https://learn.microsoft.com/en-us/dotnet/core/rid-catalog#known-rids. The project is already configured for the AOT builds, but you will need to run the publish command from the same flavor OS as the build target OS (Windows for Windows builds, Linux for Linux builds, etc).

Installation

Install npgsqlrest using npm:

npm install npgsqlrest --save-dev
npm install npgsqlrest --save-dev

Usage

$ npx npgsqlrest --help
 Usage:
 npgsqlrest                             Run with the default configuration files: appsettings.json (required) and appsettings.Development.json (optional).
 npgsqlrest [files...]                  Run with the custom configuration files. All configuration files are required.
@@ -44,50 +44,58 @@
 [11:29:07.083 INF] Created endpoint POST /api/case-return-long-table1 [NpgsqlRest]
 [11:29:07.083 INF] Created HTTP file: /home/vbilopav/npgsqlrest-npm-test/test_public.http [NpgsqlRest.HttpFiles]
 [11:29:07.100 INF] Started in 00:00:00.5527040 [Program]
-[11:29:07.100 INF] Listening on ["http://localhost:5001"] [Program]

Changelog

See the detailed change log:

1.2.5

Versions:
+[11:29:07.100 INF] Listening on ["http://localhost:5001"] [Program]

Changelog

See the detailed change log:

1.2.6

Versions:
+Client Build         1.2.5.0
+NpgsqlRest           2.8.3.0
+NpgsqlRest.HttpFiles 1.0.2.0
+NpgsqlRest.TsClient  1.8.1.0
Versions:
+Client Build         1.2.5.0
+NpgsqlRest           2.8.3.0
+NpgsqlRest.HttpFiles 1.0.2.0
+NpgsqlRest.TsClient  1.8.1.0

1.2.5

Versions:
 Client Build         1.2.4.0
-Npgsql               2.8.2.0
+NpgsqlRest           2.8.2.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.8.0.0
Versions:
 Client Build         1.2.4.0
-Npgsql               2.8.2.0
+NpgsqlRest           2.8.2.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.8.0.0

1.2.4

Versions:
 Client Build         1.2.3.0
-Npgsql               2.8.1.0
+NpgsqlRest           2.8.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0
Versions:
 Client Build         1.2.3.0
-Npgsql               2.8.1.0
+NpgsqlRest           2.8.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0

1.2.3

Versions:
 Client Build         1.2.2.0
-Npgsql               2.8.1.0
+NpgsqlRest           2.8.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0
Versions:
 Client Build         1.2.2.0
-Npgsql               2.8.1.0
+NpgsqlRest           2.8.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0

1.2.2

Versions:
 Client Build         1.2.1.0
-Npgsql               2.8.1.0
+NpgsqlRest           2.8.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0
Versions:
 Client Build         1.2.1.0
-Npgsql               2.8.1.0
+NpgsqlRest           2.8.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0

1.2.1

Fix readme

1.2.0

Versions:
 Client Build         1.2.0.0
-Npgsql               2.8.0.0
+NpgsqlRest           2.8.0.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0
Versions:
 Client Build         1.2.0.0
-Npgsql               2.8.0.0
+NpgsqlRest           2.8.0.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.7.0.0

1.1.8

Changed the download target from ./node_modules/npgsqlrest/.bin/ to shared bin: ./node_modules/.bin/.

The reason is that when using the ./node_modules/npgsqlrest/.bin/ directory, I have to use the node spawn process wrapper which slows down the startup time. When the executable is in the ./node_modules/.bin/ it can be invoked directly which is an extremely fast, almost instant startup (a couple of milliseconds).

But now, I have to use the uninstall script too, to ensure the proper cleanup on the install.

1.1.7

Update readme.

1.1.6

1.1.5

1.1.4

1.1.3

1.1.2

Fixing the issue with the local .bin directory.

1.1.1

  • Move the download bin directory from share /node_modules/.bin/ to package local /node_modules/npgsqlrest/.bin/
  • Added copy default configuration command that, well, copies the default configuration npx npgsqlrest-config-copy [optional dir]

1.1.0

New build versions:

Client Build         1.1.0.0
-Npgsql               2.7.1.0
+NpgsqlRest           2.7.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
 NpgsqlRest.TsClient  1.6.0.0
Client Build         1.1.0.0
-Npgsql               2.7.1.0
+NpgsqlRest           2.7.1.0
 NpgsqlRest.HttpFiles 1.0.2.0
-NpgsqlRest.TsClient  1.6.0.0
Comments
\ No newline at end of file +NpgsqlRest.TsClient 1.6.0.0
Comments
\ No newline at end of file diff --git a/npgsqlrest/client/index.html b/npgsqlrest/client/index.html index be70c9bb..5fb35218 100644 --- a/npgsqlrest/client/index.html +++ b/npgsqlrest/client/index.html @@ -1,4 +1,4 @@ -NpgsqlRest Client - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Client Application

Edit this page on GitHub

Download

The client application is available for download from the latest GitHub release page.

There are three files available for download:

  1. appsettings.json: The default configuration file. See the default configuration file.
  2. npgsqlrest-linux64: Linux64 build. This is a self-contained ahead-of-time (AOT) compiled to native code executable for the Linux 64x systems.
  3. npgsqlrest-win64.exe: Windows64 build. This is a self-contained ahead-of-time (AOT) compiled to native code executable for the Windows 64x systems.

NPM

Installation is possible via the NPM package manager:

npm install npgsqlrest --save-dev
npm install npgsqlrest --save-dev

The NPM package will download on installation the appropriate executable binary for your target operating system. The command will be available with the NPX runner:

$ npx npgsqlrest [arguments]
$ npx npgsqlrest [arguments]

See usage for more info.

Custom Builds

The client application was built from the NpgsqlRestClient project directory.

To create a custom build follow these steps:

  1. Make sure that you have .NET8 SDK installed and ready.
  2. Clone NpgsqlRest repository
  3. Navigate to the NpgsqlRestClient project directory.
  4. Make your desired customizations (or not).
  5. Run publish command, for example, dotnet publish -r win-x64 -c Release --output [target dir]

Notes: win-x64 is the designated target OS for the build. Adjust this parameter appropriately for the target OS. See https://learn.microsoft.com/en-us/dotnet/core/rid-catalog#known-rids. The project is already configured for the AOT builds, but you will need to run the publish command from the same flavor OS as the build target OS (Windows for Windows builds, Linux for Linux builds, etc).

MacOS Builds

The Mac OS builds are missing because I don't have a Mac machine. If someone could help me out with this I'd be grateful.

Features

  • Create an Automatic REST API for the PostgreSQL Databases.
  • Generate TypeScript Code and HTTP files for testing.
  • Configure security for use the of either encrypted cookies or JWT Bearer tokens or both.
  • Expose REST API endpoints for the PostgreSQL Databases as Login/Logout.
  • Use external authentication providers such as Google, LinkedIn or GitHub.
  • Server static content.
  • Use and configure built-in Serilog structured logging.
  • Configure Cross-origin resource sharing (CORS) access, SSL, Server Certificates and more, everything needed for modern Web development.

See the default configuration file with descriptions for more information.

Usage

❯ npgsqlrest --help
+NpgsqlRest Client - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Client Application

Edit this page on GitHub

Download

The client application is available for download from the latest GitHub release page.

There are three files available for download:

  1. appsettings.json: The default configuration file. See the default configuration file.
  2. npgsqlrest-linux64: Linux64 build. This is a self-contained ahead-of-time (AOT) compiled to native code executable for the Linux 64x systems.
  3. npgsqlrest-win64.exe: Windows64 build. This is a self-contained ahead-of-time (AOT) compiled to native code executable for the Windows 64x systems.

NPM

Installation is possible via the NPM package manager:

npm install npgsqlrest --save-dev
npm install npgsqlrest --save-dev

The NPM package will download on installation the appropriate executable binary for your target operating system. The command will be available with the NPX runner:

$ npx npgsqlrest [arguments]
$ npx npgsqlrest [arguments]

See usage for more info.

Custom Builds

The client application was built from the NpgsqlRestClient project directory.

To create a custom build follow these steps:

  1. Make sure that you have .NET8 SDK installed and ready.
  2. Clone NpgsqlRest repository
  3. Navigate to the NpgsqlRestClient project directory.
  4. Make your desired customizations (or not).
  5. Run publish command, for example, dotnet publish -r win-x64 -c Release --output [target dir]

Notes: win-x64 is the designated target OS for the build. Adjust this parameter appropriately for the target OS. See https://learn.microsoft.com/en-us/dotnet/core/rid-catalog#known-rids. The project is already configured for the AOT builds, but you will need to run the publish command from the same flavor OS as the build target OS (Windows for Windows builds, Linux for Linux builds, etc).

MacOS Builds

The Mac OS builds are missing because I don't have a Mac machine. If someone could help me out with this I'd be grateful.

Features

  • Create an Automatic REST API for the PostgreSQL Databases.
  • Generate TypeScript Code and HTTP files for testing.
  • Configure security for use the of either encrypted cookies or JWT Bearer tokens or both.
  • Expose REST API endpoints for the PostgreSQL Databases as Login/Logout.
  • Use external authentication providers such as Google, LinkedIn or GitHub.
  • Server static content.
  • Use and configure built-in Serilog structured logging.
  • Configure Cross-origin resource sharing (CORS) access, SSL, Server Certificates and more, everything needed for modern Web development.

See the default configuration file with descriptions for more information.

Usage

❯ npgsqlrest --help
 Usage:
 npgsqlrest                             Run with the default configuration files: appsettings.json (required) and appsettings.Development.json (optional).
 npgsqlrest [files...]                  Run with the custom configuration files. All configuration files are required.
diff --git a/npgsqlrest/config/index.html b/npgsqlrest/config/index.html
index 22f84c8a..6d4fc9ab 100644
--- a/npgsqlrest/config/index.html
+++ b/npgsqlrest/config/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest Default Client Config - Automatic REST API for PostgreSQL Database as .NET8 Middleware
{
+NpgsqlRest Default Client Config - Automatic REST API for PostgreSQL Database as .NET8 Middleware
{
     //
     // The application name used to set the application name property in connection string by "NpgsqlRest"."SetApplicationNameInConnection" or the "NpgsqlRest"."UseJsonApplicationName" settings.
     // It is the name of the top-level directory set to null.
@@ -359,7 +359,7 @@
         //
         // See https://vb-consulting.github.io/npgsqlrest/options/#requestheadersparametername
         //
-        "RequestHeadersParameterName": "headers",
+        "RequestHeadersParameterName": "_headers",
         //
         // See https://vb-consulting.github.io/npgsqlrest/options/#returnnpgsqlexceptionmessage
         //
@@ -1013,7 +1013,7 @@
         //
         // See https://vb-consulting.github.io/npgsqlrest/options/#requestheadersparametername
         //
-        "RequestHeadersParameterName": "headers",
+        "RequestHeadersParameterName": "_headers",
         //
         // See https://vb-consulting.github.io/npgsqlrest/options/#returnnpgsqlexceptionmessage
         //
diff --git a/npgsqlrest/crudsource/index.html b/npgsqlrest/crudsource/index.html
index 64f4b795..ce61385b 100644
--- a/npgsqlrest/crudsource/index.html
+++ b/npgsqlrest/crudsource/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest CrudSource Plugin - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest.CrudSource

Edit this page on GitHub

Data source plug-in for the NpgsqlRest library.

It provides data source access to PostgreSQL tables and views to create CRUD endpoints:

  • GET table for the SELECT operations.
  • POST table for the UPDATE operations.
  • POST table/returning for the UPDATE RETURNING operations.
  • DELETE table for the DELETE operations.
  • DELETE table/returning for the DELETE RETURNING operations.
  • PUT table for the INSERT operations.
  • PUT table/returning for the INSERT RETURNING operations.
  • PUT table/on-conflict-do-nothing for the INSERT ON CONFLICT DO NOTHING operations.
  • PUT table/on-conflict-do-nothing/returning for the INSERT ON CONFLICT DO NOTHING RETURING operations.
  • PUT table/on-conflict-do-update for the INSERT ON CONFLICT DO UPDATE operations.
  • PUT table/on-conflict-do-update/returning for the INSERT ON CONFLICT DO NOTHING UPDATE operations.

Install

dotnet add package NpgsqlRest.CrudSource --version 1.0.0
dotnet add package NpgsqlRest.CrudSource --version 1.0.0

Usages

Initialize SourcesCreated callback function that receives an initialized list of sources to add CrudSource source:

using NpgsqlRest;
+NpgsqlRest CrudSource Plugin - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest.CrudSource

Edit this page on GitHub

Data source plug-in for the NpgsqlRest library.

It provides data source access to PostgreSQL tables and views to create CRUD endpoints:

  • GET table for the SELECT operations.
  • POST table for the UPDATE operations.
  • POST table/returning for the UPDATE RETURNING operations.
  • DELETE table for the DELETE operations.
  • DELETE table/returning for the DELETE RETURNING operations.
  • PUT table for the INSERT operations.
  • PUT table/returning for the INSERT RETURNING operations.
  • PUT table/on-conflict-do-nothing for the INSERT ON CONFLICT DO NOTHING operations.
  • PUT table/on-conflict-do-nothing/returning for the INSERT ON CONFLICT DO NOTHING RETURING operations.
  • PUT table/on-conflict-do-update for the INSERT ON CONFLICT DO UPDATE operations.
  • PUT table/on-conflict-do-update/returning for the INSERT ON CONFLICT DO NOTHING UPDATE operations.

Install

dotnet add package NpgsqlRest.CrudSource --version 1.0.0
dotnet add package NpgsqlRest.CrudSource --version 1.0.0

Usages

Initialize SourcesCreated callback function that receives an initialized list of sources to add CrudSource source:

using NpgsqlRest;
 using NpgsqlRest.CrudSource;
 
 var app = builder.Build();
diff --git a/npgsqlrest/httpfiles/index.html b/npgsqlrest/httpfiles/index.html
index ff73f0bc..2c688d13 100644
--- a/npgsqlrest/httpfiles/index.html
+++ b/npgsqlrest/httpfiles/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest HttpFiles Plugin - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest.HttpFiles

Edit this page on GitHub

Automatic HTTP File Client Code Generation for NpgsqlRest

Metadata plug-in for the NpgsqlRest library.

Provides support for the generation of the HTTP Client Files.

Overview

Outputs a file or multiple files with the .http extension containing the HTTP request definitions for endpoints generated by NpgsqlRest.

The .http file format and editor were inspired by the Visual Studio Code REST Client extension.

Example of the generated file for the hello_world function:

@host=http://localhost:5000
+NpgsqlRest HttpFiles Plugin - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest.HttpFiles

Edit this page on GitHub

Automatic HTTP File Client Code Generation for NpgsqlRest

Metadata plug-in for the NpgsqlRest library.

Provides support for the generation of the HTTP Client Files.

Overview

Outputs a file or multiple files with the .http extension containing the HTTP request definitions for endpoints generated by NpgsqlRest.

The .http file format and editor were inspired by the Visual Studio Code REST Client extension.

Example of the generated file for the hello_world function:

@host=http://localhost:5000
 
 ###
 
diff --git a/npgsqlrest/index.html b/npgsqlrest/index.html
index 06894b53..559c4902 100644
--- a/npgsqlrest/index.html
+++ b/npgsqlrest/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest

build-test-publishLicense GitHub Stars GitHub Forks

Automatic REST API for PostgreSQL Databases implemented as AOT-Ready .NET8 Middleware

If you have a PostgreSQL database - based on your configuration, NpgsqlRest can create blazing fast REST API automatically and write client code for your project.

Read the NpgsqlRest Version 2 Blog Post.

See the changelog for the latest release changes in the Changelog.

There is also a client application (AOT Build) available for download from the Release page or as an NPM package. See the client application page or the NPM Package.

High Performance

Number of Requests in 60 seconds stress test:

PlatformNumber Of Requests in 60 SecondsRatio For 1 Request How Many NpgsqlRest AOT Requests
NpgsqlRest AOT781,8031
NpgsqlRest JIT562,3041.39
.NET8 ADO440,8961.77
.NET8 EF337,6122.32
PostgREST72,30510.81
Django21,19336.89
Express160,2414.88
GO78,5309.96
FastAPI13,65057.27

Read More

Modular Design

Read More

Quick Example

1) Your PostgreSQL Function

create function hello_world()                                    
+NpgsqlRest - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest

build-test-publishLicense GitHub Stars GitHub Forks

Automatic REST API for PostgreSQL Databases implemented as AOT-Ready .NET8 Middleware

If you have a PostgreSQL database - based on your configuration, NpgsqlRest can create blazing fast REST API automatically and write client code for your project.

Read the NpgsqlRest Version 2 Blog Post.

See the changelog for the latest release changes in the Changelog.

There is also a client application (AOT Build) available for download from the Release page or as an NPM package. See the client application page or the NPM Package.

High Performance

Number of Requests in 60 seconds stress test:

PlatformNumber Of Requests in 60 SecondsRatio For 1 Request How Many NpgsqlRest AOT Requests
NpgsqlRest AOT781,8031
NpgsqlRest JIT562,3041.39
.NET8 ADO440,8961.77
.NET8 EF337,6122.32
PostgREST72,30510.81
Django21,19336.89
Express160,2414.88
GO78,5309.96
FastAPI13,65057.27

Read More

Modular Design

Read More

Quick Example

1) Your PostgreSQL Function

create function hello_world()                                    
 returns text 
 language sql
 as $$
diff --git a/npgsqlrest/login-endpoints/index.html b/npgsqlrest/login-endpoints/index.html
index 1cb3c64a..b5a77799 100644
--- a/npgsqlrest/login-endpoints/index.html
+++ b/npgsqlrest/login-endpoints/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest Login Endpoints - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Login Endpoints

Edit this page on GitHub

Endpoints can be labeled as Login endpoints to act as authentication endpoints and perform user sign-in operations.

How To Label Login Endpoint

  1. By using EndpointCreated callback:
app.UseNpgsqlRest(new NpgsqlRestOptions
+NpgsqlRest Login Endpoints - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Login Endpoints

Edit this page on GitHub

Endpoints can be labeled as Login endpoints to act as authentication endpoints and perform user sign-in operations.

How To Label Login Endpoint

  1. By using EndpointCreated callback:
app.UseNpgsqlRest(new NpgsqlRestOptions
 {
     EndpointCreated = (routine, endpoint) =>
     {
diff --git a/npgsqlrest/options/index.html b/npgsqlrest/options/index.html
index f7138ed0..e56b0c36 100644
--- a/npgsqlrest/options/index.html
+++ b/npgsqlrest/options/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest Options - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Npgsql Options

Edit this page on GitHub

Options are passed as a parameter of the UseNpgsqlRest extension:

var app = builder.Build();
+NpgsqlRest Options - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Npgsql Options

Edit this page on GitHub

Options are passed as a parameter of the UseNpgsqlRest extension:

var app = builder.Build();
 app.UseNpgsqlRest(new NpgsqlRestOptions());
 app.Run();
var app = builder.Build();
 app.UseNpgsqlRest(new NpgsqlRestOptions());
diff --git a/npgsqlrest/performances/index.html b/npgsqlrest/performances/index.html
index d1ffb6f6..adfa8c5d 100644
--- a/npgsqlrest/performances/index.html
+++ b/npgsqlrest/performances/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest Performances - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Performance Tests

Edit this page on GitHub

This directory contains files required for performance tests with the Grafana K6 REST API load and performance testing tool.

Used API's are from:

Files

  • appsettings.json - configuration for NpgsqlRest used in testing.
  • k6-api-tests.js - K6 testing script.
  • perf_tests_script.sql - database script that creates functions that are tested.
  • perf_tests.http - HTTP file for smoke tests for both systems.
  • postgrest.conf - PostgREST configuration file used in testing.
  • readme.md - this file.
  • test-script.sh - shell script that orchestrates and runs all tests.
  • results - directory with the raw dump of text files from the testing session.

Results

The number of successful requests executed by the K6 (see the k6-api-tests.js file in this dir):

  • Duration of 60 seconds.
  • 100 simultaneous virtual users.
  • Retrieval of 10 and 100 records.

Numbers represent an overall number of successful requests (higher is better).

RecordsFunctionAOT 1JIT 2PostgRESTRatio (AOT / PostgREST)Ratio (JIT / PostgREST)
10perf_test781,803562,30472,30510.817.78
100perf_test307,427303,69240,4567.607.51
10perf_test_arrays495,190384,09055,3318.956.94
100perf_test_arrays124,912127,70732,4183.853.94
10perf_test_record642,772561,85561,82510.409.09
100perf_test_record216,775227,29736,6425.926.20
10perf_test_record_arrays448,273403,90050,5798.867.99
100perf_test_record_arrays100,485112,98932,6193.083.46

Other Platforms

RecordsFunctionAOT 1JIT 2EF 3ADO 4Django 5Express 6GO 7FastAPI 8
10perf_test781,803562,304337,612440,89621,193160,24178,53013,650
100perf_test307,427303,692235,331314,19818,34558,13055,1199,666
10perf_test_arrays495,190384,090254,787309,05919,01191,987N/A11,881
100perf_test_arrays124,912127,707113,663130,47111,45217,896N/A6,192

Consolidated Results

Platform10 Records100 Records
AOT is an ahead-of-time native compilation of NpgsqlRest. NpgsqlRest compiled to the native binary.781,803307,427
JIT is a just-in-time compilation of NpgsqlRest to NET8 CLR (Common Language Runtime) on NET8 runtime.562,304303,692
ADO is NET8 Raw ADO Data Reader approach. Source440,896314,198
EF is Entity Framework Core 8 on NET8 runtime. Source337,612235,331
PostgREST version 12.0.272,30540,456
Django REST Framework 4.2.10 on Python 3.8 Source Link21,19318,345
Express on NodeJS v20.11.1, express v4.18.3, pg 8.11.3 Source Link160,24155,119
GO version go1.13.8 Source Link78,53055,119
FastAPI version 0.110.0 on Python 3.8 Source Link13,6509,666

1) AOT

NpgsqlRest .NET8 AOT build is ahead-of-time (AOT) compiled to native code. AOT has an average startup time of between 180 to 200 milliseconds.

2) JIT

NpgsqlRest JIT build is a Just-In-Time (JIT) compilation of Common Intermediate Language (CIL). JIT has an average startup time of between 360 to 400 milliseconds.

3) EF

.NET8 Npgsql.EntityFrameworkCore.PostgreSQL 8.0.2

var builder = WebApplication.CreateBuilder(args);
+NpgsqlRest Performances - Automatic REST API for PostgreSQL Database as .NET8 Middleware

Performance Tests

Edit this page on GitHub

This directory contains files required for performance tests with the Grafana K6 REST API load and performance testing tool.

Used API's are from:

Files

  • appsettings.json - configuration for NpgsqlRest used in testing.
  • k6-api-tests.js - K6 testing script.
  • perf_tests_script.sql - database script that creates functions that are tested.
  • perf_tests.http - HTTP file for smoke tests for both systems.
  • postgrest.conf - PostgREST configuration file used in testing.
  • readme.md - this file.
  • test-script.sh - shell script that orchestrates and runs all tests.
  • results - directory with the raw dump of text files from the testing session.

Results

The number of successful requests executed by the K6 (see the k6-api-tests.js file in this dir):

  • Duration of 60 seconds.
  • 100 simultaneous virtual users.
  • Retrieval of 10 and 100 records.

Numbers represent an overall number of successful requests (higher is better).

RecordsFunctionAOT 1JIT 2PostgRESTRatio (AOT / PostgREST)Ratio (JIT / PostgREST)
10perf_test781,803562,30472,30510.817.78
100perf_test307,427303,69240,4567.607.51
10perf_test_arrays495,190384,09055,3318.956.94
100perf_test_arrays124,912127,70732,4183.853.94
10perf_test_record642,772561,85561,82510.409.09
100perf_test_record216,775227,29736,6425.926.20
10perf_test_record_arrays448,273403,90050,5798.867.99
100perf_test_record_arrays100,485112,98932,6193.083.46

Other Platforms

RecordsFunctionAOT 1JIT 2EF 3ADO 4Django 5Express 6GO 7FastAPI 8
10perf_test781,803562,304337,612440,89621,193160,24178,53013,650
100perf_test307,427303,692235,331314,19818,34558,13055,1199,666
10perf_test_arrays495,190384,090254,787309,05919,01191,987N/A11,881
100perf_test_arrays124,912127,707113,663130,47111,45217,896N/A6,192

Consolidated Results

Platform10 Records100 Records
AOT is an ahead-of-time native compilation of NpgsqlRest. NpgsqlRest compiled to the native binary.781,803307,427
JIT is a just-in-time compilation of NpgsqlRest to NET8 CLR (Common Language Runtime) on NET8 runtime.562,304303,692
ADO is NET8 Raw ADO Data Reader approach. Source440,896314,198
EF is Entity Framework Core 8 on NET8 runtime. Source337,612235,331
PostgREST version 12.0.272,30540,456
Django REST Framework 4.2.10 on Python 3.8 Source Link21,19318,345
Express on NodeJS v20.11.1, express v4.18.3, pg 8.11.3 Source Link160,24155,119
GO version go1.13.8 Source Link78,53055,119
FastAPI version 0.110.0 on Python 3.8 Source Link13,6509,666

1) AOT

NpgsqlRest .NET8 AOT build is ahead-of-time (AOT) compiled to native code. AOT has an average startup time of between 180 to 200 milliseconds.

2) JIT

NpgsqlRest JIT build is a Just-In-Time (JIT) compilation of Common Intermediate Language (CIL). JIT has an average startup time of between 360 to 400 milliseconds.

3) EF

.NET8 Npgsql.EntityFrameworkCore.PostgreSQL 8.0.2

var builder = WebApplication.CreateBuilder(args);
 AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
 
 builder.Services.AddDbContext<DbContext>(options => 
diff --git a/npgsqlrest/tsclient/index.html b/npgsqlrest/tsclient/index.html
index 8f818b36..df2d53a1 100644
--- a/npgsqlrest/tsclient/index.html
+++ b/npgsqlrest/tsclient/index.html
@@ -1,4 +1,4 @@
-NpgsqlRest TsClient Plugin - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest.TsClient

Edit this page on GitHub

Automatic Typescript Client Code Generation for NpgsqlRest

Metadata plug-in for the NpgsqlRest library.

Provides support for the generation of the [Typescript files] with interfaces and fetch functions.

The generated Typescript module can be re-generated on every build which effectively gives a static type-checking of your database.

Install

dotnet add package NpgsqlRest.TsClient --version 1.0.0
dotnet add package NpgsqlRest.TsClient --version 1.0.0

Example

Usage

app.UseNpgsqlRest(new(connectionString)
+NpgsqlRest TsClient Plugin - Automatic REST API for PostgreSQL Database as .NET8 Middleware

NpgsqlRest.TsClient

Edit this page on GitHub

Automatic Typescript Client Code Generation for NpgsqlRest

Metadata plug-in for the NpgsqlRest library.

Provides support for the generation of the [Typescript files] with interfaces and fetch functions.

The generated Typescript module can be re-generated on every build which effectively gives a static type-checking of your database.

Install

dotnet add package NpgsqlRest.TsClient --version 1.0.0
dotnet add package NpgsqlRest.TsClient --version 1.0.0

Example

Usage

app.UseNpgsqlRest(new(connectionString)
 {
     EndpointCreateHandlers = [
         //
diff --git a/pg_schema_tools/index.html b/pg_schema_tools/index.html
index d3678e22..e1fe8a76 100644
--- a/pg_schema_tools/index.html
+++ b/pg_schema_tools/index.html
@@ -1,4 +1,4 @@
-PostrgeSQL Schema Tools

pg_schema_tools

Edit this page on GitHub

License GitHub Stars GitHub Forks

pg_schema_tools is a collection of tools and utilities for working with PostgreSQL database schemas implemented as set of Open-Source PostrgeSQL Functions.

Features

Currently, there two public functions implemeneted:

  1. schema.search
  2. schema.dump

More functions is yet to come as this repository will be update in future.

Function schema.search

Search and retrieve for the schema objects in database.

Signature:

function schema.search(
+PostrgeSQL Schema Tools

pg_schema_tools

Edit this page on GitHub

License GitHub Stars GitHub Forks

pg_schema_tools is a collection of tools and utilities for working with PostgreSQL database schemas implemented as set of Open-Source PostrgeSQL Functions.

Features

Currently, there two public functions implemeneted:

  1. schema.search
  2. schema.dump

More functions is yet to come as this repository will be update in future.

Function schema.search

Search and retrieve for the schema objects in database.

Signature:

function schema.search(
     _schema text = null,
     _type text = null,
     _search text = null
diff --git a/pgmigrations/index.html b/pgmigrations/index.html
index d8f69006..bb19cf7d 100644
--- a/pgmigrations/index.html
+++ b/pgmigrations/index.html
@@ -1,4 +1,4 @@
-pgmigrations

PgMigrations

Edit this page on GitHub

npm version License GitHub Stars GitHub Forks

Lightweight, Zero-Dependency, PostgreSQL Tool for Node.js and NPM. You can:

  • Run Migrations Up or Down (Repeatable, Version, Before or After).
  • Run Arbitrary psql Commands by using your Project Configuration.
  • Create Database Schema Dumps by using your Project Configuration.
  • Run PostgreSQL Database Unit Tests in Functions or Procedures.

Use the pgmigrations command to manage migrations and run database commands:

> npx pgmigrations --help
+pgmigrations

PgMigrations

Edit this page on GitHub

npm version License GitHub Stars GitHub Forks

Lightweight, Zero-Dependency, PostgreSQL Tool for Node.js and NPM. You can:

  • Run Migrations Up or Down (Repeatable, Version, Before or After).
  • Run Arbitrary psql Commands by using your Project Configuration.
  • Create Database Schema Dumps by using your Project Configuration.
  • Run PostgreSQL Database Unit Tests in Functions or Procedures.

Use the pgmigrations command to manage migrations and run database commands:

> npx pgmigrations --help
 Usage:
  pgmigrations [command] [switches]
 
diff --git a/pgroutiner-default-config/index.html b/pgroutiner-default-config/index.html
index 35756d82..f287cda0 100644
--- a/pgroutiner-default-config/index.html
+++ b/pgroutiner-default-config/index.html
@@ -1,4 +1,4 @@
-PgRoutiner Default Configuration

PgRoutiner Default Configuration

/* PgRoutiner (5.4.0.0) settings */
+PgRoutiner Default Configuration

PgRoutiner Default Configuration

/* PgRoutiner (5.4.0.0) settings */
 {
   "ConnectionStrings": {
     "PostgresConnection": "postgresql://postgres:postgres@127.0.0.1:5432/postgres"
diff --git a/pgroutiner/index.html b/pgroutiner/index.html
index e64f9c73..7b398140 100644
--- a/pgroutiner/index.html
+++ b/pgroutiner/index.html
@@ -1,4 +1,4 @@
-PgRoutiner

PgRoutiner - Database-First For .NET and PostgreSQL

Edit this page on GitHub

PgRoutiner is a set of command-line tools for PostgreSQL databases and PostgreSQL .NET projects.

Using your .NET configuration project connection string (or custom-defined connection) - you can:

  1. Download native executable files (not dependent on any framework) for the latest version from the releases page.
  2. Set the appropriate path to the downloaded executable file.
  3. Type pgroutiner --info
  4. Note: working with native executables is many times faster, they very short startup time and they offer many times better user experience.

Table of Contents:

Installation

Download Binaries

This is the fastest and easiest way to get started with the PgRoutiner tool. The releases page contains downloadable executables that are not dependent on anything. No framework or docker is required, just plain old native executable.

This is actually, the preferable way of using the PgRoutiner tool. Native executables are very much optimized and have very short startup time and they offer many times better user experience.

Here are the steps:

  1. Download native executable files (not dependent on any framework) for the latest version from the releases page.
  2. Set the appropriate path to the downloaded executable file.
  3. Type pgroutiner --info to see f it works.

That is it.

.NET Tool

Requirements

Global .NET tool

To install a global tool (recommended):

$ dotnet tool install --global dotnet-pgroutiner
+PgRoutiner

PgRoutiner - Database-First For .NET and PostgreSQL

Edit this page on GitHub

PgRoutiner is a set of command-line tools for PostgreSQL databases and PostgreSQL .NET projects.

Using your .NET configuration project connection string (or custom-defined connection) - you can:

  1. Download native executable files (not dependent on any framework) for the latest version from the releases page.
  2. Set the appropriate path to the downloaded executable file.
  3. Type pgroutiner --info
  4. Note: working with native executables is many times faster, they very short startup time and they offer many times better user experience.

Table of Contents:

Installation

Download Binaries

This is the fastest and easiest way to get started with the PgRoutiner tool. The releases page contains downloadable executables that are not dependent on anything. No framework or docker is required, just plain old native executable.

This is actually, the preferable way of using the PgRoutiner tool. Native executables are very much optimized and have very short startup time and they offer many times better user experience.

Here are the steps:

  1. Download native executable files (not dependent on any framework) for the latest version from the releases page.
  2. Set the appropriate path to the downloaded executable file.
  3. Type pgroutiner --info to see f it works.

That is it.

.NET Tool

Requirements

Global .NET tool

To install a global tool (recommended):

$ dotnet tool install --global dotnet-pgroutiner
 Tool 'dotnet-pgroutiner' (version '5.4.0') was successfully installed.
$ dotnet tool install --global dotnet-pgroutiner
 Tool 'dotnet-pgroutiner' (version '5.4.0') was successfully installed.

To update a global tool:

$ dotnet tool update --global dotnet-pgroutiner
 Tool 'dotnet-pgroutiner' was successfully updated from version '5.0.7' to version '5.0.8'.
$ dotnet tool update --global dotnet-pgroutiner
diff --git a/razorsvelte/index.html b/razorsvelte/index.html
index 6f1da820..225cb9c2 100644
--- a/razorsvelte/index.html
+++ b/razorsvelte/index.html
@@ -1,4 +1,4 @@
-RazorSvelte

License GitHub Stars GitHub Forks

RazorSvelte

Edit this page on GitHub

Note:

There are several other UI Component frameworks evaluated, and finally this template is settled with Bootstrap.

To use other templates, for example, Carbon or Material UI, see installation instructions below in this file.

This is a project template and as such is being constantly updated with improvements and new components needed more modern and versatile web application.

Project template repository containing a template project with the following setup:

  • ASP.NET Razor Pages (C# and .NET8).
  • Svelte JavaScript Framework configured for use with TypeScript and SCSS preprocessor.
  • Rollup JavaScript bundler build system.
  • Bootstrap 5+ CSS framework configured for SCSS preprocessor, see https://getbootstrap.com/docs/.
  • For Bootstrap icons, see https://icons.getbootstrap.com/.
  • Sample authentication mechanism using (JWT using cookies with optional refresh tokens) and with three external login providers (Google, Linkedin, and Github).
  • Sample pages like index, privacy, login, logout, authorized sample page, unauthorized (401), not found (404), and error page.
  • Sample Single Page Application example using hashtag router component.
  • Built-in dark theme support with a theme built-in switching mechanism.
  • Sample Bootstrap components with the demo. New components are being added constantly.
  • UI components include:
    • chart - wrapper for Chart.js.
    • chart-box - chart with title and full-screen zoom buttons.
    • data-grid - data grid with the remote data source that uses bootstrap tables.
    • modal - wrapper for the bootstrap modal.
    • multiselect - multiple dropdown select with search and virtual scroll.
    • offcanvas - wrapper for the bootstrap offcanvas.
    • pager - bootstrap pager that works with data-grid.
    • placeholder - loading placeholder based on the bootstrap placeholder, mostly used by other components to manage an un-initialized state.
    • search-input - simple search input with a search icon that handles search timeouts and prevents multiple search requests.
    • etc, many more are being added regularly

To see usage examples for these components see this project.

Screenshot

Demo docker

Follow these steps to build and run the RazorSvelte demo application:

  1. Download the Dockerfile from https://raw.githubusercontent.com/vb-consulting/RazorSvelte/master/Dockerfile (or just run wgethttps://raw.githubusercontent.com/vb-consulting/RazorSvelte/master/Dockerfile` from the command prompt)

  2. Open a command prompt and navigate to the folder where you saved the Dockerfile

  3. Run the following commands:

docker build -t razorsvelte . docker run --rm -it -p 5000:80 --name razorsvelte razorsvelte:latest

Note:

If you try to login with an external provider you will be redirected to error page. Please edit appsettings.json with your own client provider id and client secrets and make sure that OAuth application redirects to `localhost:5000`` - to enable this feature.

Sample pages

  • /: index page - show value from external props hello world from svelte and display useful links
  • /privacy - privacy sample page, shows h1 title in a Svelte page passed from Razor Page ViewData.
  • /login - show external login buttons
  • /authorized - Sample authorized page protected with the Authorize attribute. Displays simple authorized user data passed from the Razor Page.
  • /401 - Sample unauthorized page that redirects when an unauthorized user tries to access the page with the Authorize attribute.
  • /404 - Not found page for unknown server routes.
  • /spa Example of the Single Page Application (SPA) with the hashtag client router component that displays various routes in a SPA fashion.

Important Notes:

  • There is no other NodeJS Web Server. Svelte is integrated with the Razor Pages.
  • Rollup JavaScript bundler is configured to output files into wwwroot and you can normally import them into Razor Pages (or any other pages).
  • There is no need to configure CORS since everything is served by .NET Web Server (Kestrel).

Why

  • Svelte is a radical new approach to building user interfaces.

  • Whereas traditional frameworks like React and Vue do the bulk of their work in the browser - Svelte shifts that work into a compile step that happens when you build your app. Instead of using techniques like virtual DOM diffing, Svelte writes code that surgically updates the DOM when the state of your app changes.

  • Svelte is a compiler that produces small and very optimized JavaScript output.

  • Svelte bundles your markup into compiler output as well, which is even smaller than what the normal markup would be.

  • Svelte compiler output is then cached in the browser which makes every subsequent request even faster since the browser doesn't even have to download that markup again.

  • Since Svelte produces pure vanilla JavaScript, there is no runtime overhead. This also means that you can import and bundle (with rollup) and runtime framework that you might need, perhaps to reuse the old UI components you might have. For example, legacy code with jQuery.

  • Svelte has become the most loved web framework for developers in a 2021 year, according to the StackOverflow survey.

  • Rollup is already pre-configured to run with the ASP.NET project, compile, bundle and remove unused modules, and then output into your wwwroot of your ASP.NET project.

  • You can also continue using the normal ASP.NET Razor Pages (or MVC) as you normally would.

The result is a very** optimized web**** application*** with:

  • The Backend is served by ASP.NET.
  • The front end is rendered and optimized by Svelte and Rollup.

And, you can combine server-side rendering with optimized Svelte front-end rendering.

Best of all - you can avoid tedious configuration by using this template.

Installation

From the command line:

Main template

$ npx degit vb-consulting/RazorSvelte
+RazorSvelte

License GitHub Stars GitHub Forks

RazorSvelte

Edit this page on GitHub

Note:

There are several other UI Component frameworks evaluated, and finally this template is settled with Bootstrap.

To use other templates, for example, Carbon or Material UI, see installation instructions below in this file.

This is a project template and as such is being constantly updated with improvements and new components needed more modern and versatile web application.

Project template repository containing a template project with the following setup:

  • ASP.NET Razor Pages (C# and .NET8).
  • Svelte JavaScript Framework configured for use with TypeScript and SCSS preprocessor.
  • Rollup JavaScript bundler build system.
  • Bootstrap 5+ CSS framework configured for SCSS preprocessor, see https://getbootstrap.com/docs/.
  • For Bootstrap icons, see https://icons.getbootstrap.com/.
  • Sample authentication mechanism using (JWT using cookies with optional refresh tokens) and with three external login providers (Google, Linkedin, and Github).
  • Sample pages like index, privacy, login, logout, authorized sample page, unauthorized (401), not found (404), and error page.
  • Sample Single Page Application example using hashtag router component.
  • Built-in dark theme support with a theme built-in switching mechanism.
  • Sample Bootstrap components with the demo. New components are being added constantly.
  • UI components include:
    • chart - wrapper for Chart.js.
    • chart-box - chart with title and full-screen zoom buttons.
    • data-grid - data grid with the remote data source that uses bootstrap tables.
    • modal - wrapper for the bootstrap modal.
    • multiselect - multiple dropdown select with search and virtual scroll.
    • offcanvas - wrapper for the bootstrap offcanvas.
    • pager - bootstrap pager that works with data-grid.
    • placeholder - loading placeholder based on the bootstrap placeholder, mostly used by other components to manage an un-initialized state.
    • search-input - simple search input with a search icon that handles search timeouts and prevents multiple search requests.
    • etc, many more are being added regularly

To see usage examples for these components see this project.

Screenshot

Demo docker

Follow these steps to build and run the RazorSvelte demo application:

  1. Download the Dockerfile from https://raw.githubusercontent.com/vb-consulting/RazorSvelte/master/Dockerfile (or just run wgethttps://raw.githubusercontent.com/vb-consulting/RazorSvelte/master/Dockerfile` from the command prompt)

  2. Open a command prompt and navigate to the folder where you saved the Dockerfile

  3. Run the following commands:

docker build -t razorsvelte . docker run --rm -it -p 5000:80 --name razorsvelte razorsvelte:latest

Note:

If you try to login with an external provider you will be redirected to error page. Please edit appsettings.json with your own client provider id and client secrets and make sure that OAuth application redirects to `localhost:5000`` - to enable this feature.

Sample pages

  • /: index page - show value from external props hello world from svelte and display useful links
  • /privacy - privacy sample page, shows h1 title in a Svelte page passed from Razor Page ViewData.
  • /login - show external login buttons
  • /authorized - Sample authorized page protected with the Authorize attribute. Displays simple authorized user data passed from the Razor Page.
  • /401 - Sample unauthorized page that redirects when an unauthorized user tries to access the page with the Authorize attribute.
  • /404 - Not found page for unknown server routes.
  • /spa Example of the Single Page Application (SPA) with the hashtag client router component that displays various routes in a SPA fashion.

Important Notes:

  • There is no other NodeJS Web Server. Svelte is integrated with the Razor Pages.
  • Rollup JavaScript bundler is configured to output files into wwwroot and you can normally import them into Razor Pages (or any other pages).
  • There is no need to configure CORS since everything is served by .NET Web Server (Kestrel).

Why

  • Svelte is a radical new approach to building user interfaces.

  • Whereas traditional frameworks like React and Vue do the bulk of their work in the browser - Svelte shifts that work into a compile step that happens when you build your app. Instead of using techniques like virtual DOM diffing, Svelte writes code that surgically updates the DOM when the state of your app changes.

  • Svelte is a compiler that produces small and very optimized JavaScript output.

  • Svelte bundles your markup into compiler output as well, which is even smaller than what the normal markup would be.

  • Svelte compiler output is then cached in the browser which makes every subsequent request even faster since the browser doesn't even have to download that markup again.

  • Since Svelte produces pure vanilla JavaScript, there is no runtime overhead. This also means that you can import and bundle (with rollup) and runtime framework that you might need, perhaps to reuse the old UI components you might have. For example, legacy code with jQuery.

  • Svelte has become the most loved web framework for developers in a 2021 year, according to the StackOverflow survey.

  • Rollup is already pre-configured to run with the ASP.NET project, compile, bundle and remove unused modules, and then output into your wwwroot of your ASP.NET project.

  • You can also continue using the normal ASP.NET Razor Pages (or MVC) as you normally would.

The result is a very** optimized web**** application*** with:

  • The Backend is served by ASP.NET.
  • The front end is rendered and optimized by Svelte and Rollup.

And, you can combine server-side rendering with optimized Svelte front-end rendering.

Best of all - you can avoid tedious configuration by using this template.

Installation

From the command line:

Main template

$ npx degit vb-consulting/RazorSvelte
 > cloned vb-consulting/RazorSvelte#HEAD
 $ cd RazorSvelte
 $ npm install
diff --git a/xunit.npgsql-sample-config/index.html b/xunit.npgsql-sample-config/index.html
index 71d0c12d..300ae321 100644
--- a/xunit.npgsql-sample-config/index.html
+++ b/xunit.npgsql-sample-config/index.html
@@ -1,4 +1,4 @@
-PgRoutiner Default Configuration

XUnit.Npgsql Sample Configuration

{
+PgRoutiner Default Configuration

XUnit.Npgsql Sample Configuration

{
   "TestSettings": {
 
     //
diff --git a/xunit.npgsql/index.html b/xunit.npgsql/index.html
index 8f33a420..f3d4a04b 100644
--- a/xunit.npgsql/index.html
+++ b/xunit.npgsql/index.html
@@ -1,4 +1,4 @@
-XUnit.Npgsql

XUnit.Npgsql

Edit this page on GitHub

XUnit Unit Testing for PostgreSQL Databases and .NET Standard 2.1

build-publish

Basic Usage

  1. Create a new XUnit Test Project.

  2. Add a reference to the XUnit.Npgsql package. e.g. dotnet add package XUnit.Npgsql

  3. Add new collection fixture to your project:

using XUnit.Npgsql;
+XUnit.Npgsql

XUnit.Npgsql

Edit this page on GitHub

XUnit Unit Testing for PostgreSQL Databases and .NET Standard 2.1

build-publish

Basic Usage

  1. Create a new XUnit Test Project.

  2. Add a reference to the XUnit.Npgsql package. e.g. dotnet add package XUnit.Npgsql

  3. Add new collection fixture to your project:

using XUnit.Npgsql;
 
 [CollectionDefinition("PostgreSqlDatabase")]
 public class DatabaseCollection : ICollectionFixture<PostgreSqlUnitTestFixture> { }
using XUnit.Npgsql;